<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://willhwig.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://willhwig.github.io/" rel="alternate" type="text/html" /><updated>2026-10-13T19:41:35+00:00</updated><id>https://willhwig.github.io/feed.xml</id><title type="html">Will Herwig</title><subtitle>Notes on Linux, hardware, and software I run into.</subtitle><entry><title type="html">Framework 16 + Anker Prime dock: the USB-PD loop behind the ‘USB 3 never comes up’ problem</title><link href="https://willhwig.github.io/2026/10/framework-16-anker-dock-usb-pd-loop/" rel="alternate" type="text/html" title="Framework 16 + Anker Prime dock: the USB-PD loop behind the ‘USB 3 never comes up’ problem" /><published>2026-10-13T00:00:00+00:00</published><updated>2026-10-13T00:00:00+00:00</updated><id>https://willhwig.github.io/2026/10/framework-16-anker-dock-usb-pd-loop</id><content type="html" xml:base="https://willhwig.github.io/2026/10/framework-16-anker-dock-usb-pd-loop/"><![CDATA[<p><strong>Symptom:</strong> 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 <code class="language-plaintext highlighter-rouge">device not accepting address, error -71</code> repeating in the kernel log. Three 1080p
DisplayLink monitors at 480 Mbps lag badly.</p>

<p><strong>Cause:</strong> 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.</p>

<p><strong>Workaround:</strong> 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.</p>

<p><strong>Fix:</strong> a small EC firmware change; patch and bug report at
<a href="https://github.com/willhwig/framework-ec-epr-fix">willhwig/framework-ec-epr-fix</a>.</p>

<h2 id="what-linux-showed">What Linux showed</h2>

<p>Two different slot types, two different failure shapes:</p>

<p>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:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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
</code></pre></div></div>

<p>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:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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
</code></pre></div></div>

<p>Fifteen successful link trainings and 116 <code class="language-plaintext highlighter-rouge">-71</code> failures in about 15 minutes. <code class="language-plaintext highlighter-rouge">-71</code> is <code class="language-plaintext highlighter-rouge">EPROTO</code>, 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.</p>

<p>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.</p>

<p>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.</p>

<h2 id="what-the-ec-showed">What the EC showed</h2>

<p>Framework publishes <code class="language-plaintext highlighter-rouge">framework_tool</code>, which can read the embedded controller’s console:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo framework_tool --console follow
</code></pre></div></div>

<p>With the dock in a middle slot, this repeats every 1.4 seconds:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[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]
</code></pre></div></div>

<p>Eleven hard resets in 15 seconds. Unplugging the Framework charger changed nothing;
unplugging the dock stopped it. Note the <code class="language-plaintext highlighter-rouge">AP throttling</code> lines: each cycle asserts PROCHOT, so
the CPU was being throttled on and off continuously while the dock was attached.</p>

<h2 id="the-mechanism-in-the-ec-source">The mechanism in the EC source</h2>

<p>Framework’s EC firmware is open source
(<a href="https://github.com/FrameworkComputer/EmbeddedController">FrameworkComputer/EmbeddedController</a>,
branch <code class="language-plaintext highlighter-rouge">fwk-tulip-29169</code> for this board). The relevant code is in
<code class="language-plaintext highlighter-rouge">zephyr/program/framework/src/</code>:</p>

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

<p><code class="language-plaintext highlighter-rouge">epr_flow_pending_deferred()</code> does have a guard: after <code class="language-plaintext highlighter-rouge">epr_retry_count &gt; 4</code> 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.</p>

<p>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 <code class="language-plaintext highlighter-rouge">EPR_Mode Fail</code>. But the EC should
not loop forever on a misbehaving partner either, and it is the side that can be fixed in
software.</p>

<h2 id="what-i-tried-from-the-os-before-giving-up-on-a-software-only-fix">What I tried from the OS before giving up on a software-only fix</h2>

<p>The EC only attempts EPR when the laptop is the power <em>sink</em>. Framework’s EC passes UCSI
<code class="language-plaintext highlighter-rouge">SET_PDR</code> 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:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo source | sudo tee /sys/class/typec/port2/power_role
</code></pre></div></div>

<p>The EC refused all three attempts (<code class="language-plaintext highlighter-rouge">-70 ECOMM</code>, <code class="language-plaintext highlighter-rouge">-95 EOPNOTSUPP</code>). No OS-level fix.</p>

<h2 id="the-workaround">The workaround</h2>

<p>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:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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
</code></pre></div></div>

<p>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.</p>

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

<h2 id="the-fix">The fix</h2>

<p>The patch adds a per-port counter of hard resets caused by the EC’s own EPR entry attempts.
<code class="language-plaintext highlighter-rouge">clear_port_state()</code> leaves it alone; only a physical disconnect clears it. <code class="language-plaintext highlighter-rouge">enter_epr_mode()</code>
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:
<a href="https://github.com/willhwig/framework-ec-epr-fix">willhwig/framework-ec-epr-fix</a>.</p>

<p>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.</p>

<h2 id="if-you-have-this-problem">If you have this problem</h2>

<ol>
  <li><code class="language-plaintext highlighter-rouge">lsusb -t | grep -i usbfs</code> — if the DisplayLink device shows <code class="language-plaintext highlighter-rouge">480M</code>, you’re in the fallback.</li>
  <li><code class="language-plaintext highlighter-rouge">sudo framework_tool --console follow</code> for 15 s and count <code class="language-plaintext highlighter-rouge">HARD_RESET_SENT</code>. If it’s more
than zero and you see <code class="language-plaintext highlighter-rouge">enter EPR stuck, retry!</code>, it’s this loop.</li>
  <li>Move the dock to a front slot.</li>
</ol>

<p>A Framework 13 Pro owner hit what looks like the same thing with an Anker DL7400 dock
(<a href="https://community.frame.work/t/framework-13-pro-seems-incompatible-with-anker-prime-dl7400-dock-due-to-some-kind-of-usb-pd-issue/84472">community thread</a>)
and ended up replacing the dock. If your laptop has a slot without PD, you may not have to.</p>]]></content><author><name></name></author><category term="framework-16" /><category term="linux" /><category term="usb-c" /><category term="usb-pd" /><category term="displaylink" /><summary type="html"><![CDATA[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.]]></summary></entry><entry><title type="html">Framework 16: keyboard and numpad drop out every minute (and how to stop it)</title><link href="https://willhwig.github.io/2026/10/framework-16-keyboard-numpad-dropouts/" rel="alternate" type="text/html" title="Framework 16: keyboard and numpad drop out every minute (and how to stop it)" /><published>2026-10-13T00:00:00+00:00</published><updated>2026-10-13T00:00:00+00:00</updated><id>https://willhwig.github.io/2026/10/framework-16-keyboard-numpad-dropouts</id><content type="html" xml:base="https://willhwig.github.io/2026/10/framework-16-keyboard-numpad-dropouts/"><![CDATA[<p><strong>Symptom:</strong> on a Framework Laptop 16 (AMD Ryzen AI 300, Ubuntu 26.04), the keyboard and
numpad disconnect together every 20–60 seconds, then come back a second later. If a key is
down at the moment of the drop, the key-up is lost and the character repeats (<code class="language-plaintext highlighter-rouge">aaaaaaa</code>).</p>

<p><strong>Cause:</strong> the embedded controller (EC) cuts power to the whole input deck when its
“deck populated / chassis closed” detection flickers. It is not a kernel, USB, or driver
problem.</p>

<p><strong>Workaround:</strong> <code class="language-plaintext highlighter-rouge">sudo framework_tool --inputdeck-mode on</code>. Permanent fix in BIOS:
Advanced → “Force Power for Input Modules”.</p>

<h2 id="what-it-looks-like-from-linux">What it looks like from Linux</h2>

<p><code class="language-plaintext highlighter-rouge">journalctl -k -f</code> shows both USB devices leaving and returning at the same instant:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usb 3-3.2: USB disconnect, device number 48
usb 3-4.2: USB disconnect, device number 49
usb 3-3.2: new full-speed USB device number 50 using xhci_hcd
usb 3-4.2: new full-speed USB device number 51 using xhci_hcd
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">3-3.2</code> is the keyboard module (<code class="language-plaintext highlighter-rouge">32ac:0012</code>), <code class="language-plaintext highlighter-rouge">3-4.2</code> the numpad module (<code class="language-plaintext highlighter-rouge">32ac:0014</code>).
They sit on different internal hub ports, so a single flaky connector can’t explain both
dropping in the same millisecond. Something upstream is removing power from both.</p>

<p>Things that looked plausible and were not the cause:</p>

<ul>
  <li>USB autosuspend (<code class="language-plaintext highlighter-rouge">/sys/module/usbcore/parameters/autosuspend</code>): disabling it changed nothing.</li>
  <li>Keyboard firmware (0.3.1) and BIOS (04.01) were current.</li>
  <li>Kernel version: it happened on the Ubuntu 7.0 OEM kernel and is not a regression.</li>
</ul>

<h2 id="what-it-looks-like-from-the-ec">What it looks like from the EC</h2>

<p>Framework’s EC is open source and ships a host tool,
<a href="https://github.com/FrameworkComputer/framework-system"><code class="language-plaintext highlighter-rouge">framework_tool</code></a>. Its <code class="language-plaintext highlighter-rouge">--console</code>
option reads the EC’s own log:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo framework_tool --console recent
</code></pre></div></div>

<p>Around every drop it prints an <em>Input modules off</em> followed by <em>Input modules on</em>. The EC has
a detect switch for the input deck and powers the modules down when it reads “not populated”.
On this unit the switch flickers, so the deck gets power-cycled.</p>

<p><code class="language-plaintext highlighter-rouge">framework_tool --versions</code> shows the module positions the EC thinks are present:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Laptop 16 Keyboard Module - ANSI
  Firmware Version: 0.3.1
  Location: [X] [ ] [ ]       [ ] [ ]
Laptop 16 Numpad Module
  Firmware Version: 0.3.1
  Location: [ ] [ ] [ ]       [X] [ ]
</code></pre></div></div>

<h2 id="stopping-it">Stopping it</h2>

<p>The EC can be told to ignore the detect switch:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo framework_tool --inputdeck-mode on
</code></pre></div></div>

<p>The drops stop immediately. The setting resets to <code class="language-plaintext highlighter-rouge">auto</code> on every reboot, so either run it
each boot (I keep it as a shell alias) or set it in the BIOS: <strong>Advanced → Force Power for
Input Modules</strong>, which survives reboots.</p>

<p>Both treat the symptom. The underlying detect switch or module seating problem is still open;
re-seating the modules (slide the input deck latch, lift, re-insert) is the first thing to
try, and a Framework support ticket is the next.</p>

<h2 id="if-you-want-to-check-yours">If you want to check yours</h2>

<ol>
  <li><code class="language-plaintext highlighter-rouge">journalctl -k -f</code> and wait for a paired disconnect of <code class="language-plaintext highlighter-rouge">32ac:0012</code> and <code class="language-plaintext highlighter-rouge">32ac:0014</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">sudo framework_tool --console recent</code> and look for <em>Input modules off/on</em>.</li>
  <li><code class="language-plaintext highlighter-rouge">sudo framework_tool --inputdeck-mode on</code> and confirm the drops stop.</li>
</ol>]]></content><author><name></name></author><category term="framework-16" /><category term="linux" /><category term="hardware" /><summary type="html"><![CDATA[Symptom: on a Framework Laptop 16 (AMD Ryzen AI 300, Ubuntu 26.04), the keyboard and numpad disconnect together every 20–60 seconds, then come back a second later. If a key is down at the moment of the drop, the key-up is lost and the character repeats (aaaaaaa).]]></summary></entry></feed>