Symptom: an Anker Prime Docking Station (A83B3, DisplayLink DL7400) on a Framework Laptop 16 (AMD Ryzen AI 300) either flaps constantly or comes up USB 2.0 only (480 Mbps), with device not accepting address, error -71 repeating in the kernel log. Three 1080p DisplayLink monitors at 480 Mbps lag badly.

Cause: the dock advertises USB-PD Extended Power Range (EPR) capability. The Framework EC tries to enter EPR, the dock never completes the handshake, the PD controller hard-resets the port, and the EC’s “give up after 4 tries” counter is cleared by that same hard reset. The port is reset every 1.4 seconds, forever. USB 3 never survives long enough to enumerate.

Workaround: put the dock in a front expansion slot (3 or 6). Those slots have no PD controller, so no contract, no EPR attempt, no loop. 10 Gbps, all three monitors, no lag. The dock won’t charge the laptop from there.

Fix: a small EC firmware change; patch and bug report at willhwig/framework-ec-epr-fix.

What Linux showed

Two different slot types, two different failure shapes:

USB4 slot (1 or 4): the dock’s USB 2 hub enumerated and vanished every second or two, with a UCSI connector-change event each time:

usb 7-1: new high-speed USB device number 23 using xhci_hcd
usb 7-1: New USB device found, idVendor=2109, idProduct=2822
hub 7-1:1.0: 5 ports detected
ucsi_acpi USBC000:00: unknown error 256
usb 7-1: USB disconnect, device number 23
ucsi_acpi USBC000:00: UCSI_GET_PDOS failed (-95)
usb 8-1: device not accepting address 8, error -71
usb 7-1-port2: attempt power cycle

Middle slot (USB 3.2 Gen 2 with DisplayPort): the USB 2 side stayed up at 480M, but the USB 3 side trained to 10 Gbps and then failed its first command, over and over:

usb 4-1: new SuperSpeed Plus Gen 2x1 USB device number 17 using xhci_hcd
usb 4-1: Device not responding to setup address.
usb 4-1: device not accepting address 20, error -71

Fifteen successful link trainings and 116 -71 failures in about 15 minutes. -71 is EPROTO, a USB transaction error, which usually gets blamed on cables. That was a red herring here: the link trained fine; the dock just got reset before it could answer.

Things that were not the cause, each tested: USB autosuspend and xHCI runtime PM (disabled, no change), USB 3 link power management (disabled, no change), the expansion card (two different ones), the host controller (both xHCI controllers failed the same way), the DisplayLink driver, system memory pressure, and a full power-cycle of the dock. The only components common to every failure were the dock, its cable, and the laptop’s PD stack.

One more clue from sysfs: the laptop saw the dock as a plain 5 V / 3 A source with no PD contract, even though the dock is rated to charge the laptop at 100 W.

What the EC showed

Framework publishes framework_tool, which can read the embedded controller’s console:

sudo framework_tool --console follow

With the dock in a middle slot, this repeats every 1.4 seconds:

[417651.7597 CYPD_RESPONSE_PD_CONTRACT_NEGOTIATION_COMPLETE 2]
[417651.8718 set AP throttling type 1 to on (0x00000010)]
[417652.0286 CCG_RESPONSE_HARD_RESET_SENT]
[417652.1008 C2 enter EPR stuck, retry!]
[417652.3691 set AP throttling type 1 to off (0x00000000)]
[417653.0701 P2 EPR mode capable]
[417653.1739 CYPD_RESPONSE_PD_CONTRACT_NEGOTIATION_COMPLETE 2]

Eleven hard resets in 15 seconds. Unplugging the Framework charger changed nothing; unplugging the dock stopped it. Note the AP throttling lines: each cycle asserts PROCHOT, so the CPU was being throttled on and off continuously while the dock was attached.

The mechanism in the EC source

Framework’s EC firmware is open source (FrameworkComputer/EmbeddedController, branch fwk-tulip-29169 for this board). The relevant code is in zephyr/program/framework/src/:

  1. cypress_pd_common.c, on CCG_RESPONSE_SOURCE_CAP_MSG_RX: if the first PDO has the EPR-capable bit, set epr_support = 1 and log P2 EPR mode capable.
  2. On CCG_RESPONSE_PD_CONTRACT_NEGOTIATION_COMPLETE: schedule enter_epr_mode() in 100 ms.
  3. cypd_ccg8.c, enter_epr_mode(): for every sink port with epr_support, send the PD chip CCG_PD_CMD_INITIATE_EPR_ENTRY, drop the input current limit to 0, assert PMF/PROCHOT, and arm a 200 ms timer.
  4. The dock never answers. The timer fires epr_flow_pending_deferred(), which logs enter EPR stuck, retry! and tries again. The CCG8 PD chip ends the failed entry with a hard reset.
  5. The hard-reset handler calls clear_port_state(), which zeroes epr_support and epr_retry_count.
  6. The contract renegotiates, the source capabilities arrive again, back to step 1.

epr_flow_pending_deferred() does have a guard: after epr_retry_count > 4 it gives up on EPR for that port. It can never fire, because step 5 resets the counter on every cycle. Nothing in the EC remembers that EPR entry on this connection has already failed.

The dock is also at fault: it claims EPR capability on a 100 W port and then doesn’t complete the handshake. A spec-following source would answer with EPR_Mode Fail. But the EC should not loop forever on a misbehaving partner either, and it is the side that can be fixed in software.

What I tried from the OS before giving up on a software-only fix

The EC only attempts EPR when the laptop is the power sink. Framework’s EC passes UCSI SET_PDR through to the PD chip, and Linux exposes that as a sysfs write, so in principle the laptop could become the source on the dock port and sidestep EPR entirely:

echo source | sudo tee /sys/class/typec/port2/power_role

The EC refused all three attempts (-70 ECOMM, -95 EOPNOTSUPP). No OS-level fix.

The workaround

The Framework 16 EC has five PD ports for six expansion slots. The front slots sit behind an internal USB hub and have no PD controller. With a USB-C expansion card in a front slot:

usb 4-2.3.3: new SuperSpeed Plus Gen 2x1 USB device number 42 using xhci_hcd
usb 4-2.3.3: Product: A83B3_A1

No Type-C partner, no contract, no EPR, no hard resets. Everything on the dock came up in four seconds. 10 Gbps is the dock’s maximum anyway, so nothing is lost versus the USB4 slots except laptop charging through the dock.

One GNOME wrinkle after a re-plug: only one of the three DisplayLink monitors came on. The evdi connector names (DVI-I-N) shift on each enumeration and ~/.config/monitors.xml is keyed by name plus serial, so the saved layout didn’t match. sudo systemctl restart displaylink-driver, then Settings → Displays, fixed it.

The fix

The patch adds a per-port counter of hard resets caused by the EC’s own EPR entry attempts. clear_port_state() leaves it alone; only a physical disconnect clears it. enter_epr_mode() skips the port after two such resets, logs once, and stays on the SPR contract (100 W here). EPR is tried again on the next plug-in. 42 lines, three files: willhwig/framework-ec-epr-fix.

I have not built or flashed it; flashing a self-built EC on a production laptop is a brick risk, and the right path is review by Framework and a BIOS release.

If you have this problem

  1. lsusb -t | grep -i usbfs — if the DisplayLink device shows 480M, you’re in the fallback.
  2. sudo framework_tool --console follow for 15 s and count HARD_RESET_SENT. If it’s more than zero and you see enter EPR stuck, retry!, it’s this loop.
  3. Move the dock to a front slot.

A Framework 13 Pro owner hit what looks like the same thing with an Anker DL7400 dock (community thread) and ended up replacing the dock. If your laptop has a slot without PD, you may not have to.