* [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3
@ 2026-10-24 17:47 Dennis Wissel
2026-10-24 20:34 ` Yiyu Zhou
` (2 more replies)
0 siblings, 3 replies; 41+ messages in thread
From: Dennis Wissel @ 2026-10-24 17:47 UTC (permalink / raw)
To: linux-usb; +Cc: mathias.nyman, regressions
Hi,
since moving from 7.2 to 7.3, a wired Keychron M5 mouse (3434:d068,
firmware 1.0.0, latest) that is plugged in at boot makes the boot hang
for about 3 minutes. usbhid probe times out on every interface with
-110, the device is disconnected and re-enumerated in a loop, udev
stalls, and when the desktop finally comes up neither the mouse nor
the keyboard on the same controller (NuPhy, 19f5:103b, port 1-5) works.
Hot-plugging the mouse after boot works fine on 7.3: all four
interfaces bind and there are no errors.
On 7.2.11 the same device at boot fails only on interfaces 2 and 3,
and it fails right away with -71. Interfaces 0 and 1 (mouse,
keyboard) bind and the mouse works. So the device firmware already
seems to misbehave at boot-time enumeration, but before 7.3 this was
harmless.
Hardware: Gigabyte Z790 EAGLE AX, i7-13700KF,
00:14.0 Intel 700 Series Chipset xHCI [8086:7a60] (rev 11)
Kernels: 7.2.11-1-cachyos (good), 7.3.0-4-cachyos (bad). These are
distribution kernels (CachyOS). CachyOS's USB/HID config is the same
for 7.2 and 7.3, so I think the change is upstream. I can test a
vanilla build if that helps.
7.3.0-4, mouse plugged in at boot:
[ 3.491895] usb 1-1: new full-speed USB device number 2 using xhci_hcd
[ 3.492774] usb 1-1: New USB device found, idVendor=3434, idProduct=d068, bcdDevice= 1.00
[ 3.492894] input: Keychron Keychron M5 as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:3434:D068.0001/input/input3
[ 3.492951] input: Keychron Keychron M5 Keyboard as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.1/0003:3434:D068.0002/input/input4
[ 29.274413] usbhid 1-1:1.2: can't add hid device: -110
[ 29.276093] usbhid 1-1:1.2: probe with driver usbhid failed with error -110
[ 54.874362] usbhid 1-1:1.3: can't add hid device: -110
[ 54.875509] usbhid 1-1:1.3: probe with driver usbhid failed with error -110
[ 56.380225] usb 1-1: USB disconnect, device number 2
[ 56.786013] usb 1-1: new full-speed USB device number 11 using xhci_hcd
[ 82.522447] usbhid 1-1:1.2: can't add hid device: -110
[ 108.122321] usbhid 1-1:1.3: can't add hid device: -110
[ 108.123378] usb 1-1: USB disconnect, device number 11
[ 108.389087] usb 1-1: new full-speed USB device number 13 using xhci_hcd
... (repeats)
7.2.11, mouse plugged in at boot:
[ 3.488582] usb 1-1: new full-speed USB device number 2 using xhci_hcd
[ 3.489628] hid-generic 0003:3434:D068.0001: input,hidraw0: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0
[ 3.516753] hid-generic 0003:3434:D068.0002: input,hidraw1: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1
[ 3.516859] usbhid 1-1:1.2: can't add hid device: -71
[ 3.517422] usbhid 1-1:1.3: can't add hid device: -71
[ 4.989074] usb 1-1: reset full-speed USB device number 2 using xhci_hcd
(no further errors, mouse works)
Full 7.3 boot log: https://paste.cachyos.org/p/ead6b4c.log
(the bad boot is the "previous boot" section)
Things I tried on 7.3, none of which helped:
- UEFI "Legacy USB Support" and "XHCI Hand-off" both enabled (they
were both disabled). There is no "BIOS handoff failed" message in
any boot.
- usbcore.quirks=3434:d068:gn. This made it worse: boot still hangs,
and hot-plug now fails with -110 as well.
My guess, untested: the xhci changes merged for 7.3 that touch
cancelled transfers on control endpoints, e.g. 7c0c31c66a7f ("move
dequeue to next valid td instead of past cancelled one"). The fast -71
on 7.2 turning into -110 timeouts plus resets on 7.3 seems to fit
that. I haven't bisected or tested a revert yet, but I can if you
point me at what to try.
#regzbot introduced: v7.2..v7.3
Thanks, Dennis
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-24 17:47 [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Dennis Wissel @ 2026-10-24 20:34 ` Yiyu Zhou 2026-10-24 20:35 ` Yiyu Zhou 2026-10-25 6:28 ` Greg KH 2 siblings, 0 replies; 41+ messages in thread From: Yiyu Zhou @ 2026-10-24 20:34 UTC (permalink / raw) To: Dennis Wissel; +Cc: Yiyu Zhou, linux-usb, mathias.nyman, regressions On Sat, 24 Oct 2026 19:47:10 +0200, Dennis Wissel wrote: > My guess, untested: the xhci changes merged for 7.3 that touch > cancelled transfers on control endpoints, e.g. 7c0c31c66a7f ("move > dequeue to next valid td instead of past cancelled one"). The fast -71 > on 7.2 turning into -110 timeouts plus resets on 7.3 seems to fit > that. I haven't bisected or tested a revert yet, but I can if you > point me at what to try. This matches a regression I reported with an HHKB keyboard on a root port. There too, 7.2 failed at once with -71, while 7.3 made the usbhid probe wait out repeated 5 s control timeouts and then re-enumerated the device, which hung again. In my case the device disconnects itself while a control transfer is in flight. Since 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") and 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error."), xhci does not give back a halted transfer on a disconnected root port and stops ringing the doorbell for that endpoint, so every later request waits for its timeout until hub_wq handles the disconnect. The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 ("xhci: give back all TDs when skipping endpoint reset after disconnect") and applies cleanly to v7.3: https://git.kernel.org/pub/scm/linux/kernel/git/mnyman/xhci.git/commit/?h=for-usb-linus&id=1f36cc9fa9496189e95fe5762cde8a74e0cd9d68 Could you test it? If it fixes your case, please reply here so that Mathias can add your Tested-by. If it does not, reverting 042aad8d0db6 and 7e0ef4332ed9 on v7.3 would show whether these commits are involved. Regards, Yiyu ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-24 17:47 [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Dennis Wissel 2026-10-24 20:34 ` Yiyu Zhou @ 2026-10-24 20:35 ` Yiyu Zhou 2026-10-24 23:10 ` Dennis Wissel 2026-10-25 6:28 ` Greg KH 2 siblings, 1 reply; 41+ messages in thread From: Yiyu Zhou @ 2026-10-24 20:35 UTC (permalink / raw) To: Dennis Wissel; +Cc: Yiyu Zhou, linux-usb, mathias.nyman, regressions On Sat, 24 Oct 2026 19:47:10 +0200, Dennis Wissel wrote: > My guess, untested: the xhci changes merged for 7.3 that touch > cancelled transfers on control endpoints, e.g. 7c0c31c66a7f ("move > dequeue to next valid td instead of past cancelled one"). The fast -71 > on 7.2 turning into -110 timeouts plus resets on 7.3 seems to fit > that. I haven't bisected or tested a revert yet, but I can if you > point me at what to try. This matches a regression I reported with an HHKB keyboard on a root port. There too, 7.2 failed at once with -71, while 7.3 made the usbhid probe wait out repeated 5 s control timeouts and then re-enumerated the device, which hung again. In my case the device disconnects itself while a control transfer is in flight. Since 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") and 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error."), xhci does not give back a halted transfer on a disconnected root port and stops ringing the doorbell for that endpoint, so every later request waits for its timeout until hub_wq handles the disconnect. The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 ("xhci: give back all TDs when skipping endpoint reset after disconnect") and applies cleanly to v7.3: https://git.kernel.org/pub/scm/linux/kernel/git/mnyman/xhci.git/commit/?h=for-usb-linus&id=1f36cc9fa9496189e95fe5762cde8a74e0cd9d68 Could you test it? If it fixes your case, please reply here so that Mathias can add your Tested-by. If it does not, reverting 042aad8d0db6 and 7e0ef4332ed9 on v7.3 would show whether these commits are involved. Regards, Yiyu ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-24 20:35 ` Yiyu Zhou @ 2026-10-24 23:10 ` Dennis Wissel 2026-10-25 8:59 ` Thorsten Leemhuis 2026-10-25 10:14 ` Michal Pecio 0 siblings, 2 replies; 41+ messages in thread From: Dennis Wissel @ 2026-10-24 23:10 UTC (permalink / raw) To: Yiyu Zhou; +Cc: Yiyu Zhou, linux-usb, mathias.nyman, regressions On Sat, 24 Oct 2026 13:34:07 -0700, Yiyu Zhou wrote: > The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 > ("xhci: give back all TDs when skipping endpoint reset after > disconnect") and applies cleanly to v7.3: [...] > Could you test it? If it fixes your case, please reply here so that > Mathias can add your Tested-by. If it does not, reverting 042aad8d0db6 > and 7e0ef4332ed9 on v7.3 would show whether these commits are involved. Thanks, I tested both on top of 7.3.0-4-cachyos, booting with the mouse plugged in each time. 1) With 1f36cc9fa949: much better, but not completely fixed. No reset loop anymore. After one disconnect and re-enumeration all four interfaces bind, and both the mouse and the NuPhy keyboard work. Before, the boot took about 3 minutes and both were dead. But hub_wq still stalls for about 11 s after the first reset of the mouse. Other devices on the same controller (1-9.2, 1-14) are only enumerated after that. Just before the disconnect is handled, xhci prints three "not part of TD" messages for ep 0: [ 3.509460] usb 1-1: new full-speed USB device number 2 using xhci_hcd [ 3.510626] hid-generic 0003:3434:D068.0001: input,hidraw0: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 [ 3.510772] hid-generic 0003:3434:D068.0002: input,hidraw1: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 [ 4.973074] usb 1-1: reset full-speed USB device number 2 using xhci_hcd (nothing on the bus for 11 s) [ 15.970122] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205260 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 [ 15.970767] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205280 for ep 0 status 13 not part of TD at 00000001042052d0 - 00000001042052f0 [ 15.971131] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205290 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 [ 16.157121] usb 1-9.2: new high-speed USB device number 7 using xhci_hcd [ 16.354120] usb 1-14: new full-speed USB device number 8 using xhci_hcd [ 16.481086] usb 1-1: USB disconnect, device number 2 [ 16.894150] usb 1-1: new full-speed USB device number 11 using xhci_hcd [ 17.026214] hid-generic 0003:3434:D068.000B: input,hidraw1: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 [ 17.099110] hid-generic 0003:3434:D068.000C: input,hidraw9: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 [ 17.101019] hid-generic 0003:3434:D068.000D: hiddev100,hidraw10: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input2 [ 17.103029] hid-generic 0003:3434:D068.000E: hiddev101,hidraw11: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input3 2) With 042aad8d0db6 and 7e0ef4332ed9 reverted (and without 1f36cc9fa949): exactly like 7.2.11. Interfaces 2 and 3 fail right away with -71, the device is reset once, no stall, no reset loop, and the mouse and keyboard work: [ 3.498259] usb 1-1: new full-speed USB device number 2 using xhci_hcd [ 3.525104] usbhid 1-1:1.2: can't add hid device: -71 [ 3.525732] usbhid 1-1:1.3: can't add hid device: -71 [ 4.981085] usb 1-1: reset full-speed USB device number 2 using xhci_hcd [ 5.167055] usb 1-9.2: new high-speed USB device number 7 using xhci_hcd [ 5.352064] usb 1-14: new full-speed USB device number 8 using xhci_hcd So these two commits are the whole cause here, and with 1f36cc9fa949 about 11 s of the regression remain. I'm happy to boot again with xhci dynamic debug or tracing enabled, or to test further patches. For 1f36cc9fa949, since it fixes the hang and the dead input devices for me, if that's useful: Tested-by: Dennis Wissel <dennis@dsine.de> Regards, Dennis ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-24 23:10 ` Dennis Wissel @ 2026-10-25 8:59 ` Thorsten Leemhuis 2026-10-26 9:28 ` Mathias Nyman 2026-10-25 10:14 ` Michal Pecio 1 sibling, 1 reply; 41+ messages in thread From: Thorsten Leemhuis @ 2026-10-25 8:59 UTC (permalink / raw) To: Dennis Wissel, Yiyu Zhou; +Cc: linux-usb, mathias.nyman, regressions, Greg KH On 10/25/26 01:10, Dennis Wissel wrote: > On Sat, 24 Oct 2026 13:34:07 -0700, Yiyu Zhou wrote: >> The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 >> ("xhci: give back all TDs when skipping endpoint reset after >> disconnect") and applies cleanly to v7.3: > [...] >> Could you test it? If it fixes your case, please reply here so that >> Mathias can add your Tested-by. If it does not, reverting 042aad8d0db6 >> and 7e0ef4332ed9 on v7.3 would show whether these commits are involved. > > Thanks, I tested both on top of 7.3.0-4-cachyos, booting with the mouse > plugged in each time. > > 1) With 1f36cc9fa949: much better, but not completely fixed. This btw is the third report about problems that that "xhci: give back all TDs when skipping endpoint reset after disconnect" fixes; the first was what lead to the fix, the second was: https://lore.kernel.org/linux-usb/20261023190104.113331-1-diogochaves@me.com/ So it sounds like this is something we should mainline rather sooner than later (ideally with a stable tag to ensure it's backported). Mathias could you make that happen? If you are busy and need help, just say so. Ciao, Thorsten > No reset loop anymore. After one disconnect and re-enumeration all four > interfaces bind, and both the mouse and the NuPhy keyboard work. > Before, the boot took about 3 minutes and both were dead. > > But hub_wq still stalls for about 11 s after the first reset of the > mouse. Other devices on the same controller (1-9.2, 1-14) are only > enumerated after that. Just before the disconnect is handled, xhci > prints three "not part of TD" messages for ep 0: > > [ 3.509460] usb 1-1: new full-speed USB device number 2 using xhci_hcd > [ 3.510626] hid-generic 0003:3434:D068.0001: input,hidraw0: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 > [ 3.510772] hid-generic 0003:3434:D068.0002: input,hidraw1: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 > [ 4.973074] usb 1-1: reset full-speed USB device number 2 using xhci_hcd > (nothing on the bus for 11 s) > [ 15.970122] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205260 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 > [ 15.970767] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205280 for ep 0 status 13 not part of TD at 00000001042052d0 - 00000001042052f0 > [ 15.971131] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205290 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 > [ 16.157121] usb 1-9.2: new high-speed USB device number 7 using xhci_hcd > [ 16.354120] usb 1-14: new full-speed USB device number 8 using xhci_hcd > [ 16.481086] usb 1-1: USB disconnect, device number 2 > [ 16.894150] usb 1-1: new full-speed USB device number 11 using xhci_hcd > [ 17.026214] hid-generic 0003:3434:D068.000B: input,hidraw1: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 > [ 17.099110] hid-generic 0003:3434:D068.000C: input,hidraw9: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 > [ 17.101019] hid-generic 0003:3434:D068.000D: hiddev100,hidraw10: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input2 > [ 17.103029] hid-generic 0003:3434:D068.000E: hiddev101,hidraw11: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input3 > > 2) With 042aad8d0db6 and 7e0ef4332ed9 reverted (and without > 1f36cc9fa949): exactly like 7.2.11. Interfaces 2 and 3 fail right away > with -71, the device is reset once, no stall, no reset loop, and the > mouse and keyboard work: > > [ 3.498259] usb 1-1: new full-speed USB device number 2 using xhci_hcd > [ 3.525104] usbhid 1-1:1.2: can't add hid device: -71 > [ 3.525732] usbhid 1-1:1.3: can't add hid device: -71 > [ 4.981085] usb 1-1: reset full-speed USB device number 2 using xhci_hcd > [ 5.167055] usb 1-9.2: new high-speed USB device number 7 using xhci_hcd > [ 5.352064] usb 1-14: new full-speed USB device number 8 using xhci_hcd > > So these two commits are the whole cause here, and with 1f36cc9fa949 > about 11 s of the regression remain. I'm happy to boot again with xhci > dynamic debug or tracing enabled, or to test further patches. > > For 1f36cc9fa949, since it fixes the hang and the dead input devices > for me, if that's useful: > Tested-by: Dennis Wissel <dennis@dsine.de> > > Regards, > Dennis ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-25 8:59 ` Thorsten Leemhuis @ 2026-10-26 9:28 ` Mathias Nyman 2026-10-26 9:49 ` Thorsten Leemhuis 2026-10-26 10:47 ` Greg KH 0 siblings, 2 replies; 41+ messages in thread From: Mathias Nyman @ 2026-10-26 9:28 UTC (permalink / raw) To: Thorsten Leemhuis, Dennis Wissel, Yiyu Zhou Cc: linux-usb, regressions, Greg KH On 10/25/26 10:59, Thorsten Leemhuis wrote: > On 10/25/26 01:10, Dennis Wissel wrote: >> On Sat, 24 Oct 2026 13:34:07 -0700, Yiyu Zhou wrote: >>> The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 >>> ("xhci: give back all TDs when skipping endpoint reset after >>> disconnect") and applies cleanly to v7.3: >> [...] >>> Could you test it? If it fixes your case, please reply here so that >>> Mathias can add your Tested-by. If it does not, reverting 042aad8d0db6 >>> and 7e0ef4332ed9 on v7.3 would show whether these commits are involved. >> >> Thanks, I tested both on top of 7.3.0-4-cachyos, booting with the mouse >> plugged in each time. >> >> 1) With 1f36cc9fa949: much better, but not completely fixed. > > This btw is the third report about problems that that "xhci: give back > all TDs when skipping endpoint reset after disconnect" fixes; the first > was what lead to the fix, the second was: > https://lore.kernel.org/linux-usb/20261023190104.113331-1-diogochaves@me.com/ > > So it sounds like this is something we should mainline rather sooner > than later (ideally with a stable tag to ensure it's backported). > Mathias could you make that happen? If you are busy and need help, just > say so. That fix isn't enough, we need to fix it properly. 7.3 where the issue exists is already out, so that is too late. What is the policy here? Should we try to shoehorn regression fixes into rc1 during merge window, or wait until rc1 is out? Thanks Mathias ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 9:28 ` Mathias Nyman @ 2026-10-26 9:49 ` Thorsten Leemhuis 2026-10-26 10:47 ` Greg KH 1 sibling, 0 replies; 41+ messages in thread From: Thorsten Leemhuis @ 2026-10-26 9:49 UTC (permalink / raw) To: Mathias Nyman, Dennis Wissel, Yiyu Zhou; +Cc: linux-usb, regressions, Greg KH On 10/26/26 10:28, Mathias Nyman wrote: > On 10/25/26 10:59, Thorsten Leemhuis wrote: >> On 10/25/26 01:10, Dennis Wissel wrote: >>> On Sat, 24 Oct 2026 13:34:07 -0700, Yiyu Zhou wrote: >>>> The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 >>>> ("xhci: give back all TDs when skipping endpoint reset after >>>> disconnect") and applies cleanly to v7.3: >>> [...] >>>> Could you test it? If it fixes your case, please reply here so that >>>> Mathias can add your Tested-by. If it does not, reverting 042aad8d0db6 >>>> and 7e0ef4332ed9 on v7.3 would show whether these commits are involved. >>> >>> Thanks, I tested both on top of 7.3.0-4-cachyos, booting with the mouse >>> plugged in each time. >>> >>> 1) With 1f36cc9fa949: much better, but not completely fixed. >> >> This btw is the third report about problems that that "xhci: give back >> all TDs when skipping endpoint reset after disconnect" fixes; the first >> was what lead to the fix, the second was: >> https://lore.kernel.org/linux-usb/20261023190104.113331-1- >> diogochaves@me.com/ >> >> So it sounds like this is something we should mainline rather sooner >> than later (ideally with a stable tag to ensure it's backported). >> Mathias could you make that happen? If you are busy and need help, just >> say so. > > That fix isn't enough, we need to fix it properly. Yeah, if there really is a remaining problem usually is the best. But that proper fix can be "revert and rethink" (see below) -- is that an option here to resolve the problem quickly? > 7.3 where the issue exists is already out, so that is too late. > > What is the policy here? > Should we try to shoehorn regression fixes into rc1 during merge window, > or wait until rc1 is out? To quote Linus from Documentation/process/handling-regressions.rst / https://www.kernel.org/doc/html/latest/process/handling-regressions.html#on-how-quickly-regressions-should-be-fixed ""But a user complaining should basically result in an immediate fix - possibly a "revert and rethink". [...]"" and ""It's also worth noting that "immediate" obviously doesn't mean "right this *second* when the problem has been reported". But if it's a regression with a known commit that caused it, I think the rule of thumb should generally be "within a week", preferably before the next rc."" You'd have to ask Linus to be sure, but I doubt that an ongoing merge window make a difference from his POV; but at the same time I suspect some subsystem maintainers will disagree. Ciao, Thorsten ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 9:28 ` Mathias Nyman 2026-10-26 9:49 ` Thorsten Leemhuis @ 2026-10-26 10:47 ` Greg KH 1 sibling, 0 replies; 41+ messages in thread From: Greg KH @ 2026-10-26 10:47 UTC (permalink / raw) To: Mathias Nyman Cc: Thorsten Leemhuis, Dennis Wissel, Yiyu Zhou, linux-usb, regressions On Mon, Oct 26, 2026 at 11:28:37AM +0200, Mathias Nyman wrote: > On 10/25/26 10:59, Thorsten Leemhuis wrote: > > On 10/25/26 01:10, Dennis Wissel wrote: > > > On Sat, 24 Oct 2026 13:34:07 -0700, Yiyu Zhou wrote: > > > > The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 > > > > ("xhci: give back all TDs when skipping endpoint reset after > > > > disconnect") and applies cleanly to v7.3: > > > [...] > > > > Could you test it? If it fixes your case, please reply here so that > > > > Mathias can add your Tested-by. If it does not, reverting 042aad8d0db6 > > > > and 7e0ef4332ed9 on v7.3 would show whether these commits are involved. > > > > > > Thanks, I tested both on top of 7.3.0-4-cachyos, booting with the mouse > > > plugged in each time. > > > > > > 1) With 1f36cc9fa949: much better, but not completely fixed. > > > > This btw is the third report about problems that that "xhci: give back > > all TDs when skipping endpoint reset after disconnect" fixes; the first > > was what lead to the fix, the second was: > > https://lore.kernel.org/linux-usb/20261023190104.113331-1-diogochaves@me.com/ > > > > So it sounds like this is something we should mainline rather sooner > > than later (ideally with a stable tag to ensure it's backported). > > Mathias could you make that happen? If you are busy and need help, just > > say so. > > That fix isn't enough, we need to fix it properly. > > 7.3 where the issue exists is already out, so that is too late. > > What is the policy here? > Should we try to shoehorn regression fixes into rc1 during merge window, > or wait until rc1 is out? I can take patches now as the -rc1 window looks like it is going to be a "bit" bigger than normal. thanks, greg k-h ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-24 23:10 ` Dennis Wissel 2026-10-25 8:59 ` Thorsten Leemhuis @ 2026-10-25 10:14 ` Michal Pecio 2026-10-25 11:11 ` Dennis Wissel 2026-10-26 9:18 ` Mathias Nyman 1 sibling, 2 replies; 41+ messages in thread From: Michal Pecio @ 2026-10-25 10:14 UTC (permalink / raw) To: Dennis Wissel; +Cc: Yiyu Zhou, linux-usb, mathias.nyman, regressions Hi, On Sun, 25 Oct 2026 01:10:27 +0200, Dennis Wissel wrote: > On Sat, 24 Oct 2026 13:34:07 -0700, Yiyu Zhou wrote: > > The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 > > ("xhci: give back all TDs when skipping endpoint reset after > > disconnect") and applies cleanly to v7.3: > [...] > > Could you test it? If it fixes your case, please reply here so that > > Mathias can add your Tested-by. If it does not, reverting > > 042aad8d0db6 and 7e0ef4332ed9 on v7.3 would show whether these > > commits are involved. > > Thanks, I tested both on top of 7.3.0-4-cachyos, booting with the > mouse plugged in each time. > > 1) With 1f36cc9fa949: much better, but not completely fixed. > > No reset loop anymore. After one disconnect and re-enumeration all four > interfaces bind, and both the mouse and the NuPhy keyboard work. > Before, the boot took about 3 minutes and both were dead. > > But hub_wq still stalls for about 11 s after the first reset of the > mouse. Other devices on the same controller (1-9.2, 1-14) are only > enumerated after that. Just before the disconnect is handled, xhci > prints three "not part of TD" messages for ep 0: > > [ 3.509460] usb 1-1: new full-speed USB device number 2 using xhci_hcd > [ 3.510626] hid-generic 0003:3434:D068.0001: input,hidraw0: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 > [ 3.510772] hid-generic 0003:3434:D068.0002: input,hidraw1: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 > [ 4.973074] usb 1-1: reset full-speed USB device number 2 using xhci_hcd > (nothing on the bus for 11 s) > [ 15.970122] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205260 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 > [ 15.970767] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205280 for ep 0 status 13 not part of TD at 00000001042052d0 - 00000001042052f0 > [ 15.971131] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205290 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 That's not good, your HC seems to be executing stale URBs, probably from before the device was reset. I suspect we reuse the default pipe without recovering it from the broken state left by EP_DROP_PENDING. (Such bug may have existed since forever, but only in USB3 and cases which seldom or never happen. 7.3 generalized it to more cases.) But is USB core really resetting a device for which the hub has reported disconnection? Something isn't as I would expect. This could result in DMAR faults, but it didn't. Was IOMMU enabled? > [ 16.157121] usb 1-9.2: new high-speed USB device number 7 using xhci_hcd > [ 16.354120] usb 1-14: new full-speed USB device number 8 using xhci_hcd > [ 16.481086] usb 1-1: USB disconnect, device number 2 > [ 16.894150] usb 1-1: new full-speed USB device number 11 using xhci_hcd > [ 17.026214] hid-generic 0003:3434:D068.000B: input,hidraw1: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 > [ 17.099110] hid-generic 0003:3434:D068.000C: input,hidraw9: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 > [ 17.101019] hid-generic 0003:3434:D068.000D: hiddev100,hidraw10: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input2 > [ 17.103029] hid-generic 0003:3434:D068.000E: hiddev101,hidraw11: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input3 > > 2) With 042aad8d0db6 and 7e0ef4332ed9 reverted (and without > 1f36cc9fa949): exactly like 7.2.11. Interfaces 2 and 3 fail right away > with -71, the device is reset once, no stall, no reset loop, and the > mouse and keyboard work: > > [ 3.498259] usb 1-1: new full-speed USB device number 2 using xhci_hcd > [ 3.525104] usbhid 1-1:1.2: can't add hid device: -71 > [ 3.525732] usbhid 1-1:1.3: can't add hid device: -71 > [ 4.981085] usb 1-1: reset full-speed USB device number 2 using xhci_hcd > [ 5.167055] usb 1-9.2: new high-speed USB device number 7 using xhci_hcd > [ 5.352064] usb 1-14: new full-speed USB device number 8 using xhci_hcd Not sure if I want to ask you to repro the failure on 7.3+1f36cc9fa949 unless you are sure that IOMMU is in good order or don't mind this system potentially getting random junk DMA'd to a random place in RAM. But can you post what happens on 7.2 with xhci_hcd and usbcore dynamic debug enabled? And BTW, the previous commit in the series (e3d757dc9257) also creates problems which are fixed by the later ones, but those would be more of a nuisance than corruption risk. Regards, Michal ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-25 10:14 ` Michal Pecio @ 2026-10-25 11:11 ` Dennis Wissel 2026-10-26 11:15 ` Michal Pecio 2026-10-26 9:18 ` Mathias Nyman 1 sibling, 1 reply; 41+ messages in thread From: Dennis Wissel @ 2026-10-25 11:11 UTC (permalink / raw) To: Michal Pecio; +Cc: Yiyu Zhou, linux-usb, mathias.nyman, regressions On Sun, 25 Oct 2026 11:14:10 +0100, Michal Pecio wrote: > This could result in DMAR faults, but it didn't. Was IOMMU enabled? No. The kernel command line has no intel_iommu=on, CONFIG_INTEL_IOMMU_DEFAULT_ON is not set, and /sys/class/iommu is empty. DMAR is only used for interrupt remapping. I won't boot 7.3+1f36cc9fa949 again. The box now runs 7.3 with 042aad8d0db6 and 7e0ef4332ed9 reverted. > But can you post what happens on 7.2 with xhci_hcd and usbcore > dynamic debug enabled? 7.2.11-1-cachyos booted with "xhci_hcd.dyndbg=+p usbcore.dyndbg=+p log_buf_len=16M", mouse plugged in at boot. Below are the lines for port 1-1 / slot 1. The full log is 270 KB, so I can send it off-list or post it somewhere if needed. This time all four interfaces failed with -71, not only 2 and 3 as in my earlier 7.2.11 boots, and there was no "usb 1-1: reset", only the disconnect/re-enumeration. The device seems to drop off the bus right after Set Configuration, at the first control transfer of the usbhid probe: [ 3.537963] xhci_hcd 0000:00:14.0: set port reset, actual port 1-1 status = 0x791 [ 3.538304] usb 1-1: new full-speed USB device number 2 using xhci_hcd [ 3.538344] xhci_hcd 0000:00:14.0: Slot ID 1: HW portnum 0, hcd portnum 0 [ 3.540254] usb 1-1: ep0 maxpacket = 8 [ 3.540543] usb 1-1: New USB device found, idVendor=3434, idProduct=d068, bcdDevice= 1.00 [ 3.541469] usb 1-1: configuration #1 chosen from 1 choice [ 3.541509] xhci_hcd 0000:00:14.0: add ep 0x82, slot id 1, new drop flags = 0x0, new add flags = 0x21 [ 3.541673] xhci_hcd 0000:00:14.0: add ep 0x83, slot id 1, new drop flags = 0x0, new add flags = 0x6a9 [ 3.542427] usb 1-1: adding 1-1:1.0 (config #1, interface 0) [ 3.542477] usbhid 1-1:1.0: usb_probe_interface [ 3.542526] usbhid 1-1:1.0: usb_probe_interface - got id [ 3.542566] xhci_hcd 0000:00:14.0: Transfer error for slot 1 ep 0 on endpoint [ 3.542606] xhci_hcd 0000:00:14.0: TRB error 4, halted endpoint index = 0 [ 3.542646] xhci_hcd 0000:00:14.0: Hard-reset ep 0, slot 1 [ 3.542725] xhci_hcd 0000:00:14.0: Ignoring reset ep completion code of 1 [ 3.542923] xhci_hcd 0000:00:14.0: Port change event, 1-1, id 1, portsc: 0x202a0 [ 3.543163] xhci_hcd 0000:00:14.0: Transfer error for slot 1 ep 0 on endpoint [ 3.543203] xhci_hcd 0000:00:14.0: TRB error 4, halted endpoint index = 0 [ 3.543244] xhci_hcd 0000:00:14.0: Hard-reset ep 0, slot 1 [ 3.543326] xhci_hcd 0000:00:14.0: Ignoring reset ep completion code of 1 [... the same 4 lines for each further control transfer, about every 0.5 ms ...] [ 3.544720] usbhid 1-1:1.0: can't add hid device: -71 [ 3.544804] usb 1-1: adding 1-1:1.1 (config #1, interface 1) [ 3.547532] usbhid 1-1:1.1: can't add hid device: -71 [ 3.547617] usb 1-1: adding 1-1:1.2 (config #1, interface 2) [ 3.550329] usbhid 1-1:1.2: can't add hid device: -71 [ 3.550413] usb 1-1: adding 1-1:1.3 (config #1, interface 3) [ 3.553190] usbhid 1-1:1.3: can't add hid device: -71 [... hub_wq enumerates the other ports, nothing for 1-1 ...] [ 5.065514] hub 1-0:1.0: state 7 ports 16 chg 0000 evt 0002 [ 5.065577] xhci_hcd 0000:00:14.0: Get port status 1-1 read: 0x206e1, return 0x10101 [ 5.065637] xhci_hcd 0000:00:14.0: clear port1 connect change, portsc: 0x6e1 [ 5.065692] usb usb1-port1: status 0101, change 0001, 12 Mb/s [ 5.065697] usb 1-1: USB disconnect, device number 2 [ 5.065750] usb 1-1: usb_disable_device nuking all URBs [ 5.065810] xhci_hcd 0000:00:14.0: drop ep 0x81, slot id 1, new drop flags = 0x8, new add flags = 0x0 [ 5.066201] xhci_hcd 0000:00:14.0: drop ep 0x5, slot id 1, new drop flags = 0x6a8, new add flags = 0x0 [ 5.170113] usb usb1-port1: debounce total 100ms stable 100ms status 0x101 [ 5.354755] xhci_hcd 0000:00:14.0: set port reset, actual port 1-1 status = 0x791 [ 5.466345] usb 1-1: new full-speed USB device number 11 using xhci_hcd [ 5.597007] hid-generic 0003:3434:D068.0009: input,hidraw8: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 [ 5.684004] hid-generic 0003:3434:D068.000A: input,hidraw9: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 [ 5.685139] hid-generic 0003:3434:D068.000B: hiddev100,hidraw10: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input2 [ 5.686139] hid-generic 0003:3434:D068.000C: hiddev101,hidraw11: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input3 So on 7.2 the disconnect (portsc 0x202a0, CCS=0) is reported at 3.542923, and the device is connected again (0x206e1) by the time hub_wq looks at port 1 at 5.065. There is no other port change event for 1-1 in between. All ep0 transfers to the gone device fail within about 0.5 ms with a transaction error, so the probes are done after 11 ms. Regards, Dennis ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-25 11:11 ` Dennis Wissel @ 2026-10-26 11:15 ` Michal Pecio 2026-10-26 20:39 ` Yiyu Zhou 0 siblings, 1 reply; 41+ messages in thread From: Michal Pecio @ 2026-10-26 11:15 UTC (permalink / raw) To: Dennis Wissel; +Cc: Yiyu Zhou, linux-usb, mathias.nyman, regressions There was some problem and I haven't got this message until I found it in the mailing list archive today. On Sun, 25 Oct 2026 12:11:21 +0100, Dennis Wissel wrote: > 7.2.11-1-cachyos booted with "xhci_hcd.dyndbg=+p usbcore.dyndbg=+p > log_buf_len=16M", mouse plugged in at boot. Below are the lines for > port 1-1 / slot 1. The full log is 270 KB, so I can send it off-list or > post it somewhere if needed. > > This time all four interfaces failed with -71, not only 2 and 3 as > in my earlier 7.2.11 boots, and there was no "usb 1-1: reset", only > the disconnect/re-enumeration. The device seems to drop off the bus > right after Set Configuration, at the first control transfer of the > usbhid probe: OK, but you showed a different log where the device gets reset. That's the interesting case which causes problems with 1f36cc9fa949 and would be useful to see with debugging enabled. I wonder if it's possible that usbhid driver requests a reset to recover from errors and usbcore performs it blindly without paying attention to connect status? Maybe enable usbhid debug as well. BTW, it's likely that the same will happen if the mouse is plugged during operation, so there may be no need to reboot each time. And log would be free of unrelated boot time noise. Regards, Michal ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 11:15 ` Michal Pecio @ 2026-10-26 20:39 ` Yiyu Zhou 2026-10-27 7:29 ` Dennis Wissel 2026-10-27 10:58 ` [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Michal Pecio 0 siblings, 2 replies; 41+ messages in thread From: Yiyu Zhou @ 2026-10-26 20:39 UTC (permalink / raw) To: Michal Pecio Cc: Yiyu Zhou, Dennis Wissel, Mathias Nyman, Alan Stern, linux-usb, regressions On Mon, 26 Oct 2026 12:15:44 +0100, Michal Pecio wrote: > I wonder if it's possible that usbhid driver requests a reset to > recover from errors and usbcore performs it blindly without paying > attention to connect status? I think that is what happens, and that 1f36cc9fa949 is what makes it reachable here. Interfaces 0 and 1 bind before the device drops off, and the VT keyboard handler opens the keyboard interface right away, so its interrupt-in URB is running. With 1f36cc9fa949 that URB is given back with -EPROTO and the resubmits fail with -ENODEV, so hid_io_error() keeps retrying and after 1 s schedules hid_reset(), which calls usb_queue_reset_device(). usb_reset_device() only checks for USB_STATE_NOTATTACHED, and the udev stays configured until hub_wq handles the connect change. At boot hub_wq only gets back to port 1 after the other ports (about 1.5 s after the disconnect in Dennis's dyndbg log), so the reset gets there first. The device is back by then, so the port reset succeeds and the reset reuses the udev and the slot, ep0 ring included. On plain 7.3 the halted interrupt TD isn't given back until hub_wq handles the disconnect, so usbhid sees no error and never asks for a reset. The device only comes back through the full disconnect at 56 s in Dennis's first log, which frees the slot and its ring. This would also explain Dennis's two 7.2 logs: the boot with "usb 1-1: reset" at 4.98 s had interfaces 0 and 1 bound, while in the dyndbg boot all four probes failed, so nothing was polling. > Maybe enable usbhid debug as well. Booting the reverted kernel with usbhid.dyndbg=+p should show "resetting device" from hid_reset() just before "usb 1-1: reset". Instead of repairing ep0 in place, could it stay blocked until Address Device has reloaded its context? Reset Device keeps the ep0 ring and dequeue pointer, but Address Device points the xHC at our enqueue pointer, past the stale TRBs. If EP_DROP_PENDING stays set on ep0 until then, the new-scheme GET_DESCRIPTOR fails at once with -ENODEV, and usb_reset_and_verify_device() re-enumerates the device on a new slot, as after a real disconnect. The patch below does that, on top of 1f36cc9fa949. It is only build-tested. On my HHKB, hub_wq handles the disconnect within about 0.3 s, before usbhid's 1 s window ends, so the reset never happens here, and I see no "not part of TD" messages with 1f36cc9fa949. Dennis, if you are willing to try it on top of 1f36cc9fa949, the reset should now fail within a fraction of a second, and the mouse should come back as a new device without the 11 s stall. The stale ring is never restarted, so the DMA problem Michal pointed out should not happen either. I used an LLM to trace the code and draft the patch. Regards, Yiyu -- >8 -- Subject: [RFC PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it After a root port disconnect or link error, xhci_handle_halted_endpoint() sets EP_DROP_PENDING instead of resetting the endpoint, and gives back its TDs. Their TRBs stay on the ring, and the endpoint's dequeue pointer still points at the halted TD. If the device comes back before hub_wq handles the disconnect, a driver may reset it on the same slot. usbhid does this after 1 s of interrupt-in errors. xhci_discover_or_reset_device() then clears EP_DROP_PENDING on every endpoint. The other endpoints are disabled by Reset Device and get new rings, but ep0 keeps its ring and dequeue pointer. For USB 2 devices, usbcore by default sends a 64 byte GET_DESCRIPTOR before SET_ADDRESS, and so before Address Device reloads the ep0 context. That request is queued behind the stale TRBs. With a Keychron M5 the reset stalled for 11 s, and the xHC then ran the old TDs ("Event dma ... for ep 0 ... not part of TD"), writing into buffers of URBs that had already been given back. Keep EP_DROP_PENDING set on ep0 through Reset Device, and clear it when an Address Device command succeeds. That command loads the ep0 context from the input context, whose dequeue pointer is our enqueue pointer, so the xHC skips the stale TRBs. Until then, ep0 requests fail with -ENODEV. If Address Device comes first, as for SuperSpeed devices, the device recovers in place. Otherwise the reset fails quickly, and usbcore re-enumerates the device on a new slot, as after a real disconnect. The same applies when Reset Device fails because the slot was never addressed: the next enumeration attempt uses a new slot instead of the stale ring. Fixes: 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Reported-by: Dennis Wissel <dennis@dsine.de> Closes: https://lore.kernel.org/linux-usb/4MjB9K-2SoiA85WbI9iEig@dsine.de/ Signed-off-by: Yiyu Zhou <yiyu@yiyuzhou.io> --- drivers/usb/host/xhci.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index fa3012bf4c0f..15f4ee4aa2c3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4091,7 +4091,13 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, ret = 0; command_cleanup: - for (i = 0; i < EP_CTX_PER_DEV; i++) + /* + * Reset Device leaves the ep0 ring and dequeue pointer as they were. + * After a disconnect or link error, ep0 may still point at TRBs of TDs + * that were given back, so keep it blocked until Address Device + * reloads its context. + */ + for (i = 1; i < EP_CTX_PER_DEV; i++) virt_dev->eps[i].ep_state &= ~EP_DROP_PENDING; xhci_free_command(xhci, reset_device_cmd); @@ -4463,6 +4469,16 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, } if (ret) goto out; + + /* + * Address Device loaded the ep0 context from the input context, so + * the xHC now starts at our enqueue pointer, past any TRBs of TDs + * given back after a disconnect or link error. Unblock ep0. + */ + spin_lock_irqsave(&xhci->lock, flags); + virt_dev->eps[0].ep_state &= ~EP_DROP_PENDING; + spin_unlock_irqrestore(&xhci->lock, flags); + temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); xhci_dbg_trace(xhci, trace_xhci_dbg_address, "Op regs DCBAA ptr = %#016llx", temp_64); ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 20:39 ` Yiyu Zhou @ 2026-10-27 7:29 ` Dennis Wissel 2026-10-27 8:48 ` [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it Yiyu Zhou 2026-10-27 10:58 ` [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Michal Pecio 1 sibling, 1 reply; 41+ messages in thread From: Dennis Wissel @ 2026-10-27 7:29 UTC (permalink / raw) To: Michal Pecio, Yiyu Zhou; +Cc: Mathias Nyman, Alan Stern, linux-usb, regressions On Mon, 26 Oct 2026 13:39:42 -0700, Yiyu Zhou wrote: > Booting the reverted kernel with usbhid.dyndbg=+p should show > "resetting device" from hid_reset() just before "usb 1-1: reset". Confirmed. With 042aad8d0db6 and 7e0ef4332ed9 reverted and usbhid.dyndbg=+p usbcore.dyndbg=+p: [ 3.488406] usbhid 1-1:1.1: retrying intr urb (repeated every ~110 ms) [ 4.577507] usbhid 1-1:1.1: resetting device [ 4.780458] usb usb1-port1: not enabled, trying reset again... [ 5.035696] usb 1-1: reset full-speed USB device number 2 using xhci_hcd > Dennis, if you are willing to try it on top of 1f36cc9fa949, the reset > should now fail within a fraction of a second, and the mouse should > come back as a new device without the 11 s stall. (A)I tested v7.3 (CachyOS 7.3.0-4) + 1f36cc9fa949 + your RFC patch with the same command line and the M5 plugged in at boot, two boots. In the first boot the device dropped off before interface 1 was bound, so nothing was polling and there was no reset. hub_wq handled the disconnect at 5.07 s and the M5 came back as a new device at 5.47 s. In the second boot interfaces 0 and 1 were bound and the reset path was taken: [ 4.531003] usbhid 1-1:1.1: resetting device [ 4.753507] usb usb1-port1: not enabled, trying reset again... [ 5.012720] usb 1-1: reset full-speed USB device number 2 using xhci_hcd [ 5.441496] usb usb1-port1: logical disconnect [ 5.441503] drivers/hid/usbhid/hid-core.c: reading report descriptor failed (post_reset) [ 5.441504] drivers/hid/usbhid/hid-core.c: reading report descriptor failed (post_reset) [ 5.837110] usb 1-1: USB disconnect, device number 2 [ 6.261660] usb 1-1: new full-speed USB device number 11 using xhci_hcd [ 6.477540] hid-generic 0003:3434:D068.000E: hiddev101,hidraw11: USB HID v1.11 Device [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input3 The reset fails after 0.43 s and the M5 is re-enumerated on a new slot, with all four interfaces bound about 2 s after usbhid requested the reset. There are no "not part of TD" messages and no stall (with 1f36cc9fa949 alone, hub_wq stalled from 4.97 s to 16 s). Mouse and keyboard work after boot. Tested-by: Dennis Wissel <dennis@dsine.de> Full logs are available if needed. Regards, Dennis ^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it 2026-10-27 7:29 ` Dennis Wissel @ 2026-10-27 8:48 ` Yiyu Zhou 2026-10-27 9:10 ` sashiko-bot 2026-10-27 10:36 ` Mathias Nyman 0 siblings, 2 replies; 41+ messages in thread From: Yiyu Zhou @ 2026-10-27 8:48 UTC (permalink / raw) To: mathias.nyman, gregkh Cc: Yiyu Zhou, linux-usb, linux-kernel, michal.pecio, regressions, Dennis Wissel After a root port disconnect or link error, xhci_handle_halted_endpoint() sets EP_DROP_PENDING instead of resetting the endpoint, and gives back its TDs. Their TRBs stay on the ring, and the endpoint's dequeue pointer still points at the halted TD. If the device comes back before hub_wq handles the disconnect, a driver may reset it on the same slot. usbhid does this after 1 s of interrupt-in errors. xhci_discover_or_reset_device() then clears EP_DROP_PENDING on every endpoint. The other endpoints are disabled by Reset Device and get new rings, but ep0 keeps its ring and dequeue pointer. For USB 2 devices, usbcore by default sends a 64 byte GET_DESCRIPTOR before SET_ADDRESS, and so before Address Device reloads the ep0 context. That request is queued behind the stale TRBs. With a Keychron M5 the reset stalled for 11 s, and the xHC then ran the old TDs ("Event dma ... for ep 0 ... not part of TD"), writing into buffers of URBs that had already been given back. Keep EP_DROP_PENDING set on ep0 through Reset Device, and clear it when an Address Device command succeeds. That command loads the ep0 context from the input context, whose dequeue pointer is our enqueue pointer, so the xHC skips the stale TRBs. Until then, ep0 requests fail with -ENODEV. If Address Device comes first, as for SuperSpeed devices, the device recovers in place. Otherwise the reset fails quickly, and usbcore re-enumerates the device on a new slot, as after a real disconnect. The same applies when Reset Device fails because the slot was never addressed: the next enumeration attempt uses a new slot instead of the stale ring. Fixes: 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Reported-by: Dennis Wissel <dennis@dsine.de> Closes: https://lore.kernel.org/linux-usb/4MjB9K-2SoiA85WbI9iEig@dsine.de/ Tested-by: Dennis Wissel <dennis@dsine.de> Signed-off-by: Yiyu Zhou <yiyu@yiyuzhou.io> --- This is the RFC from the regression thread [1], unchanged apart from Dennis's Tested-by. It applies on top of 1f36cc9fa949 ("xhci: give back all TDs when skipping endpoint reset after disconnect") in for-usb-linus and depends on it: without that patch, ep0 requests are not rejected while EP_DROP_PENDING is set, so they would wait for their timeouts. 7.3 needs both, so they should probably go to stable together. I used an LLM to trace the code and draft the patch. [1] https://lore.kernel.org/linux-usb/20261026203944.2235991-1-yiyu@yiyuzhou.io/ drivers/usb/host/xhci.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index fa3012bf4c0f..15f4ee4aa2c3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4091,7 +4091,13 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, ret = 0; command_cleanup: - for (i = 0; i < EP_CTX_PER_DEV; i++) + /* + * Reset Device leaves the ep0 ring and dequeue pointer as they were. + * After a disconnect or link error, ep0 may still point at TRBs of TDs + * that were given back, so keep it blocked until Address Device + * reloads its context. + */ + for (i = 1; i < EP_CTX_PER_DEV; i++) virt_dev->eps[i].ep_state &= ~EP_DROP_PENDING; xhci_free_command(xhci, reset_device_cmd); @@ -4463,6 +4469,16 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, } if (ret) goto out; + + /* + * Address Device loaded the ep0 context from the input context, so + * the xHC now starts at our enqueue pointer, past any TRBs of TDs + * given back after a disconnect or link error. Unblock ep0. + */ + spin_lock_irqsave(&xhci->lock, flags); + virt_dev->eps[0].ep_state &= ~EP_DROP_PENDING; + spin_unlock_irqrestore(&xhci->lock, flags); + temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); xhci_dbg_trace(xhci, trace_xhci_dbg_address, "Op regs DCBAA ptr = %#016llx", temp_64); base-commit: 1f36cc9fa9496189e95fe5762cde8a74e0cd9d68 -- 2.55.0 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it 2026-10-27 8:48 ` [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it Yiyu Zhou @ 2026-10-27 9:10 ` sashiko-bot 2026-10-27 10:36 ` Mathias Nyman 1 sibling, 0 replies; 41+ messages in thread From: sashiko-bot @ 2026-10-27 9:10 UTC (permalink / raw) To: Yiyu Zhou; +Cc: linux-usb > After a root port disconnect or link error, xhci_handle_halted_endpoint() > sets EP_DROP_PENDING instead of resetting the endpoint, and gives back > its TDs. Their TRBs stay on the ring, and the endpoint's dequeue > pointer still points at the halted TD. > > If the device comes back before hub_wq handles the disconnect, a driver > may reset it on the same slot. usbhid does this after 1 s of > interrupt-in errors. xhci_discover_or_reset_device() then clears > EP_DROP_PENDING on every endpoint. The other endpoints are disabled by > Reset Device and get new rings, but ep0 keeps its ring and dequeue > pointer. For USB 2 devices, usbcore by default sends a 64 byte > GET_DESCRIPTOR before SET_ADDRESS, and so before Address Device reloads > the ep0 context. That request is queued behind the stale TRBs. With a > Keychron M5 the reset stalled for 11 s, and the xHC then ran the old > TDs ("Event dma ... for ep 0 ... not part of TD"), writing into buffers > [ ... ] > Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") > Reported-by: Dennis Wissel <dennis@dsine.de> > Closes: https://lore.kernel.org/linux-usb/4MjB9K-2SoiA85WbI9iEig@dsine.de/ > Tested-by: Dennis Wissel <dennis@dsine.de> > Signed-off-by: Yiyu Zhou <yiyu@yiyuzhou.io> Sashiko has reviewed this patch and found no issues. -- Sashiko AI review · https://sashiko.dev/#/patchset/20261027084845.1588204-1-yiyu@yiyuzhou.io?part=1 ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it 2026-10-27 8:48 ` [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it Yiyu Zhou 2026-10-27 9:10 ` sashiko-bot @ 2026-10-27 10:36 ` Mathias Nyman 2026-10-27 11:27 ` Michal Pecio 2026-10-27 18:40 ` Yiyu Zhou 1 sibling, 2 replies; 41+ messages in thread From: Mathias Nyman @ 2026-10-27 10:36 UTC (permalink / raw) To: Yiyu Zhou, mathias.nyman, gregkh Cc: linux-usb, linux-kernel, michal.pecio, regressions, Dennis Wissel On 10/27/26 10:48, Yiyu Zhou wrote: > After a root port disconnect or link error, xhci_handle_halted_endpoint() > sets EP_DROP_PENDING instead of resetting the endpoint, and gives back > its TDs. Their TRBs stay on the ring, and the endpoint's dequeue > pointer still points at the halted TD. > > If the device comes back before hub_wq handles the disconnect, a driver > may reset it on the same slot. usbhid does this after 1 s of > interrupt-in errors. xhci_discover_or_reset_device() then clears > EP_DROP_PENDING on every endpoint. The other endpoints are disabled by > Reset Device and get new rings, but ep0 keeps its ring and dequeue > pointer. For USB 2 devices, usbcore by default sends a 64 byte > GET_DESCRIPTOR before SET_ADDRESS, and so before Address Device reloads > the ep0 context. That request is queued behind the stale TRBs. With a > Keychron M5 the reset stalled for 11 s, and the xHC then ran the old > TDs ("Event dma ... for ep 0 ... not part of TD"), writing into buffers > of URBs that had already been given back. > > Keep EP_DROP_PENDING set on ep0 through Reset Device, and clear it when > an Address Device command succeeds. That command loads the ep0 context > from the input context, whose dequeue pointer is our enqueue pointer, so > the xHC skips the stale TRBs. Until then, ep0 requests fail with > -ENODEV. If Address Device comes first, as for SuperSpeed devices, the > device recovers in place. Otherwise the reset fails quickly, and > usbcore re-enumerates the device on a new slot, as after a real > disconnect. The same applies when Reset Device fails because the slot > was never addressed: the next enumeration attempt uses a new slot > instead of the stale ring. Thanks for the detailed description, this looks like a very targeted fix for this specific hid case. It still leaves the stale TRBs on ep0 ring, and relies on a successful address device command to clear the EP_DROP_PENDING flag, blocking ep0 in all other scenarios. It also leaves xHC internal ep0 in the 'halted' state. Not sure if xHC internal halted ep0 state is cleared during 'reset device' or 'address device' command. There are cases where EP_DROP_PENDING won't be cleared at all in this patch. For example if slot is already in the default state when hci_setup_device() is called. (slot is in default state after reset device command) I'm thinking we should take a step backwards first when fixing this regression, and then look if we can tune fine tune ep0 after that. 1. Make sure All TDs are turned to no-op before returning the URBs in the disconnect case. Add all TDs in ring to cancelled list, turn them no-op, and then give them back. 2. Treat ep0 differently, cancel all TDs on ring as above, but still reset it when halted. Allow a Set TR deq pointer command as well, and only give back ep0 URBs after this. This partially reverts the two patches that caused this issue, and clears the ep0 halted state 3. Possibly keep EP_DROP_PENDING flag for ep0 until xhci_setup_device() as this patch does, but always clear it in xhci_setup_device() before it returns Let me know if you find any flaws with this approach. Thanks Mathias ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it 2026-10-27 10:36 ` Mathias Nyman @ 2026-10-27 11:27 ` Michal Pecio 2026-10-27 18:40 ` Yiyu Zhou 1 sibling, 0 replies; 41+ messages in thread From: Michal Pecio @ 2026-10-27 11:27 UTC (permalink / raw) To: Mathias Nyman Cc: Yiyu Zhou, mathias.nyman, gregkh, linux-usb, linux-kernel, regressions, Dennis Wissel On Tue, 27 Oct 2026 12:36:26 +0200, Mathias Nyman wrote: > Thanks for the detailed description, this looks like a very targeted fix > for this specific hid case. > > It still leaves the stale TRBs on ep0 ring, and relies on a successful > address device command to clear the EP_DROP_PENDING flag, blocking ep0 > in all other scenarios. It also leaves xHC internal ep0 in the > 'halted' state. Not sure if xHC internal halted ep0 state is cleared during > 'reset device' or 'address device' command. Addres Device is not suitable, unless preceded by Drop/Enable slot. Reset Device: For the Default Control Endpoint the xHC shall terminate any USB activity, abort any pending events not already posted to an Event Ring, and transition the endpoint to the Running state. I see no mention of "halted" in all of 4.6.11. Logically, the spec seems to assume that SW can use this command when EP0 is running and busy, so it can transition to halted while the command is pending, so the xHC "should" be able to deal with that. We know how dependable xHCI hardware is in practice, but actually this might work because IIRC Windows also doesn't bother resetting endpoints of disconnected devices. I haven't studied this very thoroughly, but I recall noticing that it queries PORTSC before resetting endpoints and it violates the spec by dropping halted endpoints, just like we do. > I'm thinking we should take a step backwards first when fixing this > regression, and then look if we can tune fine tune ep0 after that. > > 1. Make sure All TDs are turned to no-op before returning the URBs in > the disconnect case. > > Add all TDs in ring to cancelled list, turn them no-op, and then > give them back. Seems helpful and harmless, doesn't account for potential TRB caching. > 2. Treat ep0 differently, cancel all TDs on ring as above, but still > reset it when halted. Allow a Set TR deq pointer command as well, > and only give back ep0 URBs after this. This partially reverts the > two patches that caused this issue, and clears the ep0 halted state Sensible, if Reset EP/Set TR Deq on EP0 of a disconnected USB3 device don't trigger HW bugs. These commands only change some EP Ctx fields and don't submit or abort USB transfers, so they may be safe. It's even possible that they are safe on all endpoints, but who knows. I don't think this will cause any issuess on Renesas, even generalized to all endpoints, and I still have the HW and ability to test. We could use some input from the author of b8c3b718087b ("usb: xhci: Don't try to recover an endpoint if port is in error state.") about those issues, whether they affected EP0 or not :) > 3. Possibly keep EP_DROP_PENDING flag for ep0 until > xhci_setup_device() as this patch does, but always clear it in > xhci_setup_device() before it returns Does this result in URBs failing to submit before the device is addressed, causing USB core to drop and enumerate again? That part does seem a little dodgy. We may agree or disagree with core's policies, but they are what they are, and not an accidental bug. Doesn't seem suitable for 7.3. Regards, Michal ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it 2026-10-27 10:36 ` Mathias Nyman 2026-10-27 11:27 ` Michal Pecio @ 2026-10-27 18:40 ` Yiyu Zhou 2026-10-27 19:21 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman 1 sibling, 1 reply; 41+ messages in thread From: Yiyu Zhou @ 2026-10-27 18:40 UTC (permalink / raw) To: Mathias Nyman Cc: Yiyu Zhou, Michal Pecio, Greg Kroah-Hartman, Dennis Wissel, linux-usb, linux-kernel, regressions On Tue, 27 Oct 2026 12:36:26 +0200, Mathias Nyman wrote: > There are cases where EP_DROP_PENDING won't be cleared at all in this patch. You are right. xhci_setup_device() returns early with "Slot already in default state" for the SETUP_CONTEXT_ONLY call from hub_enable_device(), before my new clear, and Reset Device leaves the slot in that state. I missed that early return. ep0 then stays blocked, and usbcore only gets out of it by re-enumerating the device. On Tue, 27 Oct 2026 11:58:05 +0100, Michal Pecio wrote: > You seem to suggest that xhci-hcd should trick usbcore into abandoning > "resuscitation", right? Yes, that was the effect, and I agree it is the wrong place for it. It would also re-enumerate devices that recover from an in-place reset on 7.2, which is a bigger change than I weighed. Please drop this patch. I can't judge the controller side of the plan in your mail, but I am happy to test it. My HHKB covers the original disconnect hang, and Dennis's Keychron covers the reset case. If it helps, I can also turn steps 1 and 2 into an RFC to test with, unless you have already started on them. -YZ ^ permalink raw reply [flat|nested] 41+ messages in thread
* [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect 2026-10-27 18:40 ` Yiyu Zhou @ 2026-10-27 19:21 ` Mathias Nyman 2026-10-27 19:21 ` [RFT PATCH 1/2] xhci: give back all TDs when skipping endpoint reset after disconnect Mathias Nyman ` (4 more replies) 0 siblings, 5 replies; 41+ messages in thread From: Mathias Nyman @ 2026-10-27 19:21 UTC (permalink / raw) To: yiyu Cc: linux-usb, regressions, diogochaves, michal.pecio, raoxu, dennis, gregkh, Mathias Nyman Yiyu Zhou wrote PATCH 1/2, fixing a regression in USB HID device enumeration caused by the endpoint recovery prevention code added in v7.3-rc1. Some HID devices that used to enumerate after a brief disconnect during enumeration now got stuck until URBs timed out. PATCH 1/2 gives back the pending URBs right away, which solves most of the problem, but it leaves the TRBs of the given back URBs on the ep0 ring. ep0 survives a brief disconnect during a port reset, so the xHC may later process those TRBs during an enumeration retry, writing into buffers that were already given back, or ep0 stays halted and the next control transfer times out. PATCH 2/2 cleans up the ep0 ring by resetting ep0 and moving its dequeue pointer past the cancelled TDs, even if a disconnect or link error is detected. Only Reset Endpoint and Set TR Dequeue Pointer commands are issued; ep0 is not restarted while the disconnect is pending. The rapid endpoint reset, restart and stop sequence that made some xHC hosts fail Stop Endpoint commands is still avoided. Other endpoints are still given back without resetting them, but their TRBs are turned into no-ops first. If you have seen the HID enumeration issue, or the xHC Stop Endpoint failures with rapid endpoint state changes, testing these two patches would be greatly appreciated. If these patches work, they might be squashed into one before going upstream. [This message, and PATCH 2/2 commit message were cleaed up by LLM, Code is still 'organic'.] Thanks Mathias Mathias Nyman (1): xhci: clean up ep0 ring after disconnect instead of leaving stale TRBs Yiyu Zhou (1): xhci: give back all TDs when skipping endpoint reset after disconnect drivers/usb/host/xhci-ring.c | 71 ++++++++++++++++++++++++++++++------ drivers/usb/host/xhci.c | 13 ++++--- 2 files changed, 67 insertions(+), 17 deletions(-) -- 2.43.0 ^ permalink raw reply [flat|nested] 41+ messages in thread
* [RFT PATCH 1/2] xhci: give back all TDs when skipping endpoint reset after disconnect 2026-10-27 19:21 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman @ 2026-10-27 19:21 ` Mathias Nyman 2026-10-27 19:21 ` [RFT PATCH 2/2] xhci: clean up ep0 ring after disconnect instead of leaving stale TRBs Mathias Nyman ` (3 subsequent siblings) 4 siblings, 0 replies; 41+ messages in thread From: Mathias Nyman @ 2026-10-27 19:21 UTC (permalink / raw) To: yiyu Cc: linux-usb, regressions, diogochaves, michal.pecio, raoxu, dennis, gregkh, Mathias Nyman From: Yiyu Zhou <yiyu@yiyuzhou.io> Commit 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") makes xhci_handle_halted_endpoint() return early when the root port is disconnected, and commit 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") also sets EP_DROP_PENDING there, which keeps the doorbell from being rung until the device is reset. The callers rely on xhci_handle_halted_endpoint() to take over the halted TD. For example, finish_td() returns right after calling it, expecting the TD to be given back once the Reset Endpoint command completes. With the early return, nobody gives the TD back. Its URB stays pending until the submitter times out and unlinks it. URBs queued behind it are stuck the same way, and every URB queued on the endpoint afterwards never starts, because the doorbell is blocked, and also has to time out. Devices that disconnect and reconnect themselves during enumeration hit this. A PFU HHKB Professional HYBRID Type-S keyboard (04fe:0021) drops off the bus about 300 ms after its first enumeration, while usbhid is still probing its third interface. The probe runs in hub_wq, so the disconnect is not handled until the probe returns. On a root port the HID descriptor request and its four retries in hid_get_class_descriptor() each wait for the full 5 second USB_CTRL_GET_TIMEOUT: [57685.006036] usb 3-2: new full-speed USB device number 24 using xhci_hcd ... [57685.291304] hid-generic 0003:04FE:0021.0017: input,hidraw1: USB HID v1.11 Keyboard [PFU Limited HHKB-Hybrid] on usb-0000:00:14.0-2/input1 [57711.221083] usbhid 3-2:1.2: can't add hid device: -110 [57711.221613] usbhid 3-2:1.2: probe with driver usbhid failed with error -110 [57711.221842] usb 3-2: USB disconnect, device number 24 The re-enumeration that follows can stall the same way, leaving the keyboard dead until reboot. Behind an external hub, where the root port stays connected, the same keyboard recovers in about 300 ms, as it did on the root port before these commits. Keep skipping Reset Endpoint on a disconnected or inactive port, but give back the halted TD right away, with -EPROTO if no error status was set yet, and all other TDs on the endpoint with -ESHUTDOWN. The endpoint is not restarted until the device is reset or dropped, so the ring dequeue pointer can stay where it is, as xhci_invalidate_cancelled_tds() already assumes for cancelled TDs on such endpoints. Also refuse new URBs on an endpoint with EP_DROP_PENDING set, like xhci_urb_enqueue() already does for an inactive link, so they fail right away instead of timing out. [mn: merge EP_DROP_PENDING and link_inactive checks in xhci_urb_enqueue()] Fixes: 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Closes: https://lore.kernel.org/all/20261010071811.20483-1-yiyu@yiyuzhou.io/ Assisted-by: LLM Signed-off-by: Yiyu Zhou <yiyu@yiyuzhou.io> Tested-by: Diogo Chaves <diogochaves@me.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> --- drivers/usb/host/xhci-ring.c | 12 ++++++++++-- drivers/usb/host/xhci.c | 13 +++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ec278a9f9540..8262ed516d37 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -65,6 +65,7 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, u32 field1, u32 field2, u32 field3, u32 field4, bool command_must_succeed); +static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, int slot_id, int ep_index); /* * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA @@ -989,12 +990,19 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, int err; /* - * Avoid resetting endpoint if link is inactive or device disonnected. + * Avoid resetting endpoint if link is inactive or device disconnected. * Can cause host hang. - * Device will be reset to recover an inactive link, so don't do anything + * The endpoint won't restart before the device is reset or the endpoint + * dropped, so give back all its TDs now instead of letting them time out. */ if (rhub_port->link_inactive || !rhub_port->connected) { + xhci_dbg(xhci, "Not resetting ep %u slot %u after disconnect or link error\n", + ep->ep_index, slot_id); ep->ep_state |= EP_DROP_PENDING; + if (td) + xhci_td_cleanup(xhci, td, xhci_urb_to_transfer_ring(xhci, td->urb), + td->status ?: -EPROTO); + xhci_kill_endpoint_urbs(xhci, slot_id, ep->ep_index); return -ENODEV; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7f7babe9d681..fa3012bf4c0f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1665,12 +1665,6 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag goto free_priv; } - if (xhci->devs[slot_id]->rhub_port->link_inactive) { - xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); - ret = -ENODEV; - goto free_priv; - } - if (xhci->xhc_state & XHCI_STATE_DYING) { xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n", urb->ep->desc.bEndpointAddress, urb); @@ -1680,6 +1674,13 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state; + if (xhci->devs[slot_id]->rhub_port->link_inactive || + *ep_state & EP_DROP_PENDING) { + xhci_dbg(xhci, "Can't queue urb, port disconnect or link inactive\n"); + ret = -ENODEV; + goto free_priv; + } + if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", *ep_state); -- 2.43.0 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFT PATCH 2/2] xhci: clean up ep0 ring after disconnect instead of leaving stale TRBs 2026-10-27 19:21 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman 2026-10-27 19:21 ` [RFT PATCH 1/2] xhci: give back all TDs when skipping endpoint reset after disconnect Mathias Nyman @ 2026-10-27 19:21 ` Mathias Nyman 2026-10-27 23:05 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Dennis Wissel ` (2 subsequent siblings) 4 siblings, 0 replies; 41+ messages in thread From: Mathias Nyman @ 2026-10-27 19:21 UTC (permalink / raw) To: yiyu Cc: linux-usb, regressions, diogochaves, michal.pecio, raoxu, dennis, gregkh, Mathias Nyman Commit 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") and commit 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") skip endpoint recovery if the root port is disconnected or the link is inactive, and set EP_DROP_PENDING to keep the endpoint stopped. TDs are given back without moving the endpoint dequeue pointer, or turning the TRBs into no-ops, assuming the endpoint will soon be dropped and its ring freed. This assumption doesn't hold for the default control endpoint. If a USB 2 device briefly disconnects during a port reset in enumeration, the hub driver retries the reset and keeps the same usb_device, and the xhci ep0 ring stays in use. The given back TRBs remain on the ring between the xHC dequeue pointer and the enqueue pointer. Reset Device fails with a context state error if the slot is in default state, and Address Device with BSR=1 is skipped for a slot already in default state. In this case nothing moves the ep0 dequeue pointer before the next enumeration attempt. xHC may then process TRBs of already given back URBs, writing data into buffers that may already be freed, or ep0 remains halted and the next control transfer times out. Handle a halted ep0 on a disconnected port by cancelling all its TDs and resetting it normally. The Reset Endpoint handler turns the cancelled TDs into no-ops and issues a Set TR Dequeue Pointer command to move past them, flushing any cached TRBs, before the TDs are given back. ep0 is left stopped. It is not restarted while EP_DROP_PENDING is set, so the reset, restart and stop sequence that caused the xHC to fail Stop Endpoint commands is still avoided. Other endpoints are still given back directly without resetting them, but their TRBs are now turned into no-ops first. The halted TD is given back with -EPROTO if no error status was set yet, and other TDs with -ESHUTDOWN. Commit message written with LLM help, code is still organic Fixes: 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect") Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Assisted-by: LLM Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> --- drivers/usb/host/xhci-ring.c | 77 +++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 8262ed516d37..fdc02e7d937a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -956,6 +956,24 @@ static void xhci_giveback_invalidated_tds(struct xhci_hcd *xhci, struct xhci_vir } } +static void xhci_cancel_ring_tds(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + struct xhci_ring *ring, int td_status) +{ + struct xhci_td *tmp_td = NULL; + struct xhci_td *td = NULL; + + /* Add all TDs on ring to cancelled td list */ + list_for_each_entry_safe(td, tmp_td, &ring->td_list, td_list) { + if (list_empty(&td->cancelled_td_list)) { + list_add_tail(&td->cancelled_td_list, + &ep->cancelled_td_list); + td->cancel_status = TD_DIRTY; + if (!td->status) + td->status = td_status; + } + } +} + static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, enum xhci_ep_reset_type reset_type) { @@ -987,40 +1005,62 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, { struct xhci_port *rhub_port = ep->vdev->rhub_port; unsigned int slot_id = ep->vdev->slot_id; + bool disconnected = false; + struct xhci_ring *ring; int err; - /* - * Avoid resetting endpoint if link is inactive or device disconnected. - * Can cause host hang. - * The endpoint won't restart before the device is reset or the endpoint - * dropped, so give back all its TDs now instead of letting them time out. - */ + /* link is inactive or device disconnected */ if (rhub_port->link_inactive || !rhub_port->connected) { - xhci_dbg(xhci, "Not resetting ep %u slot %u after disconnect or link error\n", - ep->ep_index, slot_id); ep->ep_state |= EP_DROP_PENDING; - if (td) - xhci_td_cleanup(xhci, td, xhci_urb_to_transfer_ring(xhci, td->urb), - td->status ?: -EPROTO); - xhci_kill_endpoint_urbs(xhci, slot_id, ep->ep_index); - return -ENODEV; + disconnected = true; + if (!td) { + xhci_kill_endpoint_urbs(xhci, slot_id, ep->ep_index); + return -ENODEV; + } } - /* add td to cancelled list and let reset ep handler take care of it */ - if (reset_type == EP_HARD_RESET) { - ep->ep_state |= EP_HARD_CLEAR_TOGGLE; + /* Add halted td to cancelled list and let reset ep handler take care of it */ + if (reset_type == EP_HARD_RESET || disconnected) { if (td && list_empty(&td->cancelled_td_list)) { list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); td->cancel_status = TD_HALTED; + if (disconnected && !td->status) + td->status = -EPROTO; } } + /* + * Avoid resetting non-ep0 endpoints if link is inactive or device + * disconnected. Can cause host hang. + * Endpoints other than ep0 won't restart before the device is reset or + * the endpoint is dropped, so cancel all TDs, and give back non-ep0 TDs + * now instead of letting them time out. Ep0 can survive a short device + * disconnect during enumeration so reset ep0 normally and clean it up. + */ + if (disconnected) { + ring = xhci_urb_to_transfer_ring(xhci, td->urb); + xhci_cancel_ring_tds(xhci, ep, ring, -ESHUTDOWN); + if (ep->ep_index != 0) { + xhci_dbg(xhci, "Not resetting ep %u slot %u after disconnect\n", + ep->ep_index, slot_id); + + xhci_process_cancelled_tds(xhci, ep); + xhci_kill_endpoint_urbs(xhci, slot_id, ep->ep_index); + return -ENODEV; + } + /* hard-reset a halted disconnected ep0 */ + reset_type = EP_HARD_RESET; + } + if (ep->ep_state & EP_HALTED) { xhci_dbg(xhci, "Reset ep command for ep_index %d already pending\n", ep->ep_index); return 0; } + if (reset_type == EP_HARD_RESET) + ep->ep_state |= EP_HARD_CLEAR_TOGGLE; + err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type); if (err) return err; @@ -1071,8 +1111,9 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt continue; } - /* device disconnected or link error, ep will be dropped */ - if (ep->ep_state & EP_DROP_PENDING) { + /* device disconnected or link error, non-ep0 endpoints will be dropped */ + if (ep->ep_state & EP_DROP_PENDING && ep->ep_index != 0) { + td_to_noop(xhci, ep, td, false); td->cancel_status = TD_CLEARED; continue; } -- 2.43.0 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect 2026-10-27 19:21 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman 2026-10-27 19:21 ` [RFT PATCH 1/2] xhci: give back all TDs when skipping endpoint reset after disconnect Mathias Nyman 2026-10-27 19:21 ` [RFT PATCH 2/2] xhci: clean up ep0 ring after disconnect instead of leaving stale TRBs Mathias Nyman @ 2026-10-27 23:05 ` Dennis Wissel 2026-10-28 7:07 ` Michal Pecio 2026-10-29 4:18 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Yiyu Zhou 4 siblings, 0 replies; 41+ messages in thread From: Dennis Wissel @ 2026-10-27 23:05 UTC (permalink / raw) To: yiyu, Mathias Nyman Cc: linux-usb, regressions, diogochaves, michal.pecio, raoxu, gregkh, Mathias Nyman I tested v7.3 (CachyOS 7.3.0-4) + both patches with the Keychron M5 (3434:d068) plugged in at boot, two boots, with xhci_hcd.dyndbg=+p usbhid.dyndbg=+p usbcore.dyndbg=+p. In both boots the M5 drops off at the first control transfers after Set Configuration, and ep0 on the disconnected port now goes through the new path: [ 3.536042] xhci_hcd 0000:00:14.0: Not resetting ep 2 slot 1 after disconnect [ 3.536404] xhci_hcd 0000:00:14.0: Transfer error for slot 1 ep 0 on endpoint [ 3.536447] xhci_hcd 0000:00:14.0: TRB error 4, halted endpoint index = 0 [ 3.536487] xhci_hcd 0000:00:14.0: Hard-reset ep 0, slot 1 followed by Set TR Deq, the URB given back with -71 and further URBs refused with "Can't queue urb, port disconnect or link inactive". Boot 1: no interface was bound before the drop, so all four fail within 2 ms, as on v7.2. hub_wq handles the disconnect at 5.31 s and the M5 comes back as a new device at 5.72 s, all four interfaces bound at 5.94 s. Boot 2: interfaces 0 and 1 were bound, so usbhid requested a reset: [ 4.539124] usbhid 1-1:1.1: resetting device [ 4.771324] usb usb1-port1: not enabled, trying reset again... [ 5.023262] usb 1-1: reset full-speed USB device number 2 using xhci_hcd [ 5.135351] xhci_hcd 0000:00:14.0: Can't reset device (slot ID 1) in default state [ 5.135498] xhci_hcd 0000:00:14.0: Successful setup address command [ 5.148062] xhci_hcd 0000:00:14.0: Successful Endpoint Configure command The device is resuscitated in place on the same slot and ep0 works again after the reset. Mouse and keyboard work after boot. In neither boot are there "not part of TD" messages or any stall (with 1f36cc9fa949 alone, hub_wq stalled from 4.97 s to 16 s). initrd takes 2.9-3.0 s, the same as v7.2.11. One observation, probably not xhci related: in boot 2, interfaces 2 and 3 failed their probe before the reset ("reading report descriptor failed") and stay unbound after the in-place reset, until the mouse is replugged. On v7.2 the device was re-enumerated instead, so all four interfaces ended up bound. Tested-by: Dennis Wissel <dennis@dsine.de> Full logs are available if needed. Regards, Dennis ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect 2026-10-27 19:21 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman ` (2 preceding siblings ...) 2026-10-27 23:05 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Dennis Wissel @ 2026-10-28 7:07 ` Michal Pecio 2026-10-29 6:54 ` [PATCH 0/4] Fix problems on disconnected devices in 7.3 Michal Pecio 2026-10-29 4:18 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Yiyu Zhou 4 siblings, 1 reply; 41+ messages in thread From: Michal Pecio @ 2026-10-28 7:07 UTC (permalink / raw) To: Mathias Nyman Cc: yiyu, linux-usb, regressions, diogochaves, raoxu, dennis, gregkh On Tue, 27 Oct 2026 21:21:25 +0200, Mathias Nyman wrote: > Yiyu Zhou wrote PATCH 1/2, fixing a regression in USB HID device > enumeration caused by the endpoint recovery prevention code added in > v7.3-rc1. Some HID devices that used to enumerate after a brief > disconnect during enumeration now got stuck until URBs timed out. > > PATCH 1/2 gives back the pending URBs right away, which solves most of > the problem, but it leaves the TRBs of the given back URBs on the ep0 > ring. ep0 survives a brief disconnect during a port reset, so the xHC > may later process those TRBs during an enumeration retry, writing into > buffers that were already given back, or ep0 stays halted and the next > control transfer times out. > > PATCH 2/2 cleans up the ep0 ring by resetting ep0 and moving its > dequeue pointer past the cancelled TDs, even if a disconnect or link > error is detected. Only Reset Endpoint and Set TR Dequeue Pointer > commands are issued; ep0 is not restarted while the disconnect is > pending. The rapid endpoint reset, restart and stop sequence that made > some xHC hosts fail Stop Endpoint commands is still avoided. Other > endpoints are still given back without resetting them, but their TRBs > are turned into no-ops first. > > If you have seen the HID enumeration issue, or the xHC Stop Endpoint > failures with rapid endpoint state changes, testing these two patches > would be greatly appreciated. > > If these patches work, they might be squashed into one before going > upstream. Might? :) 1/2 is a possibly dangereous regression and shouldn't be used alone. Anyway, I think it all can be done with a bit less code, while also handling disconnection during unlink. Particularly on EP0, multiple URBs may be submitted by different drivers and/or userspace. Just because one of them unlinks its URB doesn't mean that the others are aware of anything being wrong and won't stall for <N> seconds. This below is a rudimentarily tested RFC but it seems to work. It's simple enough that hopefully it might even be correct. I will test it more and write a changelog later today if there are no objections. I tweaked the logic to return everything with -ESHUTDOWN and not bother to assign proper status to the URB which halted. Intuition: we want them to give up, not call clear_halt() or reset_device(). --- diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index fa6684746305..b37056cb8576 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -987,14 +987,11 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, int err; /* - * Avoid resetting endpoint if link is inactive or device disonnected. - * Can cause host hang. - * Device will be reset to recover an inactive link, so don't do anything + * Mark endpoints behind disconnected or SS.Inactive root hub ports. + * Restarting them is futile and known to triggers HC bugs on USB3. */ - if (rhub_port->link_inactive || !rhub_port->connected) { + if (rhub_port->link_inactive || !rhub_port->connected) ep->ep_state |= EP_DROP_PENDING; - return -ENODEV; - } /* add td to cancelled list and let reset ep handler take care of it */ if (reset_type == EP_HARD_RESET) { @@ -1011,6 +1008,12 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, return 0; } + /* Don't reset lost endpoints, only EP0 can survive device reset */ + if (ep->ep_state & EP_DROP_PENDING && ep->ep_index) { + xhci_process_cancelled_tds(xhci, ep); + return 0; + } + err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type); if (err) return err; @@ -1022,6 +1025,9 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, return 0; } +static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, int slot_id, int ep_index); + + /* * Fix up the ep ring first, so HW stops executing cancelled TDs. * We have the xHCI lock, so nothing can modify this list until we drop it. @@ -1047,6 +1053,22 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt if (ep->ep_state & SET_DEQ_PENDING) return 0; + if (ep->ep_state & EP_DROP_PENDING) { + xhci_dbg(xhci, "Nuking dead slot %d ep %d\n", ep->vdev->slot_id, ep->ep_index); + if (ep->ep_index) { + xhci_kill_endpoint_urbs(xhci, ep->vdev->slot_id, ep->ep_index); + return 0; + } + /* EP0 may be reused after device reset, clean up the ring properly */ + list_for_each_entry(td, &ep->ring->td_list, td_list) { + td->status = -ESHUTDOWN; + if (list_empty(&td->cancelled_td_list)) { + list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); + td->cancel_status = TD_DIRTY; // for clarity, it's redundant + } + } + } + list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, cancelled_td_list) { xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Removing canceled TD starting at 0x%llx (dma) in stream %u URB %p", @@ -1061,12 +1083,6 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt continue; } - /* device disconnected or link error, ep will be dropped */ - if (ep->ep_state & EP_DROP_PENDING) { - td->cancel_status = TD_CLEARED; - continue; - } - /* * If a ring stopped on the TD we need to cancel then we have to * move the xHC endpoint ring dequeue pointer past this TD. ^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH 0/4] Fix problems on disconnected devices in 7.3 2026-10-28 7:07 ` Michal Pecio @ 2026-10-29 6:54 ` Michal Pecio 2026-10-29 6:54 ` [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints Michal Pecio ` (3 more replies) 0 siblings, 4 replies; 41+ messages in thread From: Michal Pecio @ 2026-10-29 6:54 UTC (permalink / raw) To: Mathias Nyman Cc: yiyu, linux-usb, regressions, diogochaves, raoxu, dennis, gregkh On Wed, 28 Oct 2026 08:07:34 +0100, Michal Pecio wrote: > Anyway, I think it all can be done with a bit less code, while also > handling disconnection during unlink. Particularly on EP0, multiple > URBs may be submitted by different drivers and/or userspace. Just > because one of them unlinks its URB doesn't mean that the others are > aware of anything being wrong and won't stall for <N> seconds. > > This below is a rudimentarily tested RFC but it seems to work. It's > simple enough that hopefully it might even be correct. I will test it > more and write a changelog later today if there are no objections. > > I tweaked the logic to return everything with -ESHUTDOWN and not > bother to assign proper status to the URB which halted. Intuition: > we want them to give up, not call clear_halt() or reset_device(). Actually, wouldn't this break the "resuscitation" feature? Does anyone depend on it? Hell knows... I changed to give back the halted URB with normal status and ended up with similar code as everyone else, but in different places, so that URBs should also be flushed on unlink now. Took a little longer than I hoped. Is the last patch 4/4 necessary in practice? I guess it probably is. As for disconnection of USB3 NICs from Renesas, that still works without hanging the HC. In fact, we could even Reset EP and Set Deq on the interrupt endpoint and nothing happens if it's not restarted, but these patches here only clean up EP0. Regards, Michal ^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints 2026-10-29 6:54 ` [PATCH 0/4] Fix problems on disconnected devices in 7.3 Michal Pecio @ 2026-10-29 6:54 ` Michal Pecio 2026-10-29 7:12 ` sashiko-bot 2026-10-29 6:55 ` [PATCH 2/4] usb: xhci: Give back stranded URBs " Michal Pecio ` (2 subsequent siblings) 3 siblings, 1 reply; 41+ messages in thread From: Michal Pecio @ 2026-10-29 6:54 UTC (permalink / raw) To: Mathias Nyman Cc: yiyu, linux-usb, regressions, diogochaves, raoxu, dennis, gregkh This code prevents queuing Set TR Dequeue commands to endpoints of disconnected devices. Turns out, USB core may "resuscitate" these devices if a reset is requested before disconnection and completed after reconnection, leading to reuse of the default endpoint. Make sure that the default endpoint is cleaned up properly - TRBs are erased (just in case, as usual) and Dequeue is set to Enqueue. And don't overwrite TD_HALTED status, we may need it when resetting of halted disconnected control endpoints is implemented later to further prepare them for resuscitation. Reported-by: Dennis Wissel <dennis@dsine.de> Link: https://lore.kernel.org/linux-usb/SrQQcLIwRWyg9PdEIpc0eg@dsine.de/ Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Cc: stable@vger.kernel.org Signed-off-by: Michal Pecio <michal.pecio@gmail.com> --- drivers/usb/host/xhci-ring.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index fa6684746305..7049787725fb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1061,12 +1061,6 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt continue; } - /* device disconnected or link error, ep will be dropped */ - if (ep->ep_state & EP_DROP_PENDING) { - td->cancel_status = TD_CLEARED; - continue; - } - /* * If a ring stopped on the TD we need to cancel then we have to * move the xHC endpoint ring dequeue pointer past this TD. @@ -1118,6 +1112,12 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt if (!cached_td) return 0; + /* Don't bother fixing disconnected endpoints except EP0 */ + if (ep->ep_state & EP_DROP_PENDING && ep->ep_index != 0) { + cached_td->cancel_status = TD_CLEARED; + return 0; + } + err = xhci_move_deq_to_next_td(xhci, ep, cached_td->urb->stream_id); if (err) { -- 2.48.1 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints 2026-10-29 6:54 ` [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints Michal Pecio @ 2026-10-29 7:12 ` sashiko-bot 0 siblings, 0 replies; 41+ messages in thread From: sashiko-bot @ 2026-10-29 7:12 UTC (permalink / raw) To: Michal Pecio; +Cc: linux-usb Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] usb: xhci: uncleared deferred stream TDs in xhci_invalidate_cancelled_tds() -- commit 6bfb98376f7395944affad9a4c188ba84e981149 Author: Michal Pecio <michal.pecio@gmail.com> usb: xhci: Fix TD invalidation on disconnected endpoints This commit moves the EP_DROP_PENDING check in xhci_invalidate_cancelled_tds() after the loop over ep->cancelled_td_list and restricts the early return to non-EP0 endpoints so that EP0 TRBs are turned into no-ops and the dequeue pointer is moved to enqueue when a disconnected device is resuscitated by reset. Link: https://lore.kernel.org/linux-usb/SrQQcLIwRWyg9PdEIpc0eg@dsine.de/ > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c > index ec278a9f95404..698f994e43a55 100644 > --- a/drivers/usb/host/xhci-ring.c > +++ b/drivers/usb/host/xhci-ring.c > @@ -1063,12 +1063,6 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt > continue; > } > > - /* device disconnected or link error, ep will be dropped */ > - if (ep->ep_state & EP_DROP_PENDING) { > - td->cancel_status = TD_CLEARED; > - continue; > - } > - > /* > * If a ring stopped on the TD we need to cancel then we have to > * move the xHC endpoint ring dequeue pointer past this TD. > @@ -1120,6 +1114,12 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt > if (!cached_td) > return 0; > > + /* Don't bother fixing disconnected endpoints except EP0 */ > + if (ep->ep_state & EP_DROP_PENDING && ep->ep_index != 0) { > + cached_td->cancel_status = TD_CLEARED; > + return 0; > + } [Severity: High] Can this leave deferred TDs uncleared on multi-stream endpoints? When a non-EP0 multi-stream endpoint has EP_DROP_PENDING set and multiple streams have cancelled TDs at their hardware dequeue pointers (trb_in_td(td, hw_deq)), the loop in drivers/usb/host/xhci-ring.c:xhci_invalidate_cancelled_tds() unlinks every cancelled TD from ring->td_list via list_del_init(&td->td_list), assigns the first stopped stream's TD to cached_td with TD_CLEARING_CACHE, and marks subsequent stopped TDs on other streams as TD_CLEARING_CACHE_DEFERRED: if (cached_td) { if (cached_td->urb->stream_id != td->urb->stream_id) { /* Multiple streams case, defer move dq */ xhci_dbg(xhci, "Move dq deferred: stream %u URB %p\n", td->urb->stream_id, td->urb); td->cancel_status = TD_CLEARING_CACHE_DEFERRED; break; } When the new EP_DROP_PENDING check after the loop returns early without calling xhci_move_deq_to_next_td(), only cached_td->cancel_status is set to TD_CLEARED, leaving any TD_CLEARING_CACHE_DEFERRED TDs on ep->cancelled_td_list uncleared. In xhci_giveback_invalidated_tds(), only TDs with cancel_status == TD_CLEARED are cleaned up and given back: if (td->cancel_status == TD_CLEARED) { xhci_dbg(xhci, "%s: Giveback cancelled URB %p TD\n", __func__, td->urb); xhci_td_cleanup(xhci, td, ring, td->status); } else { xhci_dbg(xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n", __func__, td->urb, td->cancel_status); } Since SET_DEQ_PENDING is never set, nothing re-triggers invalidation, stranding those deferred TDs in usb_kill_urb() or usb_hcd_flush_endpoint(). Even with the later patches in this series ("usb: xhci: Give back stranded URBs on disconnected endpoints" and "usb: xhci: Give back URBs on halted disconnected endpoints") that add a fallback call to xhci_kill_endpoint_urbs(), could this still cause problems in two ways? First, if xhci_giveback_invalidated_tds() runs while EP_STOP_CMD_PENDING or EP_HALTED is still set (for example via xhci_handle_cmd_stop_ep() -> xhci_handle_halted_endpoint() -> xhci_process_cancelled_tds(), before EP_STOP_CMD_PENDING is cleared at reset_done), xhci_kill_endpoint_urbs() is skipped and the deferred TDs remain stranded. Second, when xhci_kill_endpoint_urbs() does run, those deferred TDs were already unlinked from ring->td_list by xhci_invalidate_cancelled_tds(), so they bypass both xhci_td_cleanup() and xhci_kill_ring_urbs() and fall into the ep->cancelled_td_list loop in xhci_kill_endpoint_urbs(), which does not call xhci_unmap_td_bounce_buffer() and overwrites td->status with -ESHUTDOWN. Should this path also clear any TD_CLEARING_CACHE_DEFERRED TDs on ep->cancelled_td_list, similar to the error handling path when xhci_move_deq_to_next_td() fails? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261029075409.4b203658.michal.pecio@gmail.com?part=1 ^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 2/4] usb: xhci: Give back stranded URBs on disconnected endpoints 2026-10-29 6:54 ` [PATCH 0/4] Fix problems on disconnected devices in 7.3 Michal Pecio 2026-10-29 6:54 ` [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints Michal Pecio @ 2026-10-29 6:55 ` Michal Pecio 2026-10-29 7:23 ` sashiko-bot 2026-10-29 6:56 ` [PATCH 3/4] usb: xhci: Give back URBs on halted " Michal Pecio 2026-10-29 6:57 ` [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices Michal Pecio 3 siblings, 1 reply; 41+ messages in thread From: Michal Pecio @ 2026-10-29 6:55 UTC (permalink / raw) To: Mathias Nyman Cc: yiyu, linux-usb, regressions, diogochaves, raoxu, dennis, gregkh When a URB is unlinked and Stop Endpoint handler sets EP_DROP_PENDING, the endpoint won't be restarted and URBs will be hanging until drivers unlink them, possibly only after a long timeout. For control endpoints, cancel all remaining URBs before invalidation and then process them normally to ensure proper ring cleanup. On other endpoints just nuke remaining URBs after cancelled TD processing; URBs which are already cancelled are still returned normally. Based on ideas from patches by Yiyu Zhou and Mathias Nyman, reworked to integrate deeper with existing infrastructure and cover more cases. Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Cc: stable@vger.kernel.org Signed-off-by: Michal Pecio <michal.pecio@gmail.com> --- drivers/usb/host/xhci-ring.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 7049787725fb..14cfb025c365 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -62,6 +62,7 @@ #include "xhci.h" #include "xhci-trace.h" +static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, int slot_id, int ep_index); static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, u32 field1, u32 field2, u32 field3, u32 field4, bool command_must_succeed); @@ -951,6 +952,11 @@ static void xhci_giveback_invalidated_tds(struct xhci_hcd *xhci, struct xhci_vir if (xhci->xhc_state & XHCI_STATE_DYING) return; } + + /* Nuke stranded URBs if there is no one to give them back */ + if ((ep->ep_state & EP_DROP_PENDING) && + !(ep->ep_state & (EP_HALTED | SET_DEQ_PENDING | EP_STOP_CMD_PENDING))) + xhci_kill_endpoint_urbs(xhci, ep->vdev->slot_id, ep->ep_index); } static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id, @@ -1047,6 +1053,20 @@ static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt if (ep->ep_state & SET_DEQ_PENDING) return 0; + /* + * Disconnected EP0 may be reused when core "resuscitates" the device, + * so we must clean up its ring properly. Cancel all remaining URBs. + */ + if (ep->ep_state & EP_DROP_PENDING && ep->ep_index == 0) { + list_for_each_entry(td, &ep->ring->td_list, td_list) { + if (list_empty(&td->cancelled_td_list)) { + list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); + td->cancel_status = TD_DIRTY; + td->status = -ESHUTDOWN; + } + } + } + list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, cancelled_td_list) { xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Removing canceled TD starting at 0x%llx (dma) in stream %u URB %p", -- 2.48.1 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH 2/4] usb: xhci: Give back stranded URBs on disconnected endpoints 2026-10-29 6:55 ` [PATCH 2/4] usb: xhci: Give back stranded URBs " Michal Pecio @ 2026-10-29 7:23 ` sashiko-bot 0 siblings, 0 replies; 41+ messages in thread From: sashiko-bot @ 2026-10-29 7:23 UTC (permalink / raw) To: Michal Pecio; +Cc: linux-usb Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] usb: xhci: uncleared deferred TDs in xhci_invalidate_cancelled_tds() -- commit b1010543af7d4802d6d3abbb86ff8ccfdb2101da Author: Michal Pecio <michal.pecio@gmail.com> usb: xhci: Give back stranded URBs on disconnected endpoints This commit gives back remaining URBs on endpoints marked with EP_DROP_PENDING by cancelling remaining TDs before invalidation on EP0 and calling xhci_kill_endpoint_urbs() after cancelled TD processing on other endpoints. > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c > index 698f994e43a55..49483eb55dc83 100644 > --- a/drivers/usb/host/xhci-ring.c > +++ b/drivers/usb/host/xhci-ring.c [ ... ] > @@ -953,6 +954,11 @@ static void xhci_giveback_invalidated_tds(struct xhci_hcd *xhci, struct xhci_vir > if (xhci->xhc_state & XHCI_STATE_DYING) > return; > } > + > + /* Nuke stranded URBs if there is no one to give them back */ > + if ((ep->ep_state & EP_DROP_PENDING) && > + !(ep->ep_state & (EP_HALTED | SET_DEQ_PENDING | EP_STOP_CMD_PENDING))) > + xhci_kill_endpoint_urbs(xhci, ep->vdev->slot_id, ep->ep_index); [Severity: High] Can this skip xhci_td_cleanup() and leak DMA bounce buffer mappings on disconnected stream-enabled endpoints when multiple streams have cancelled TDs stopped at their hardware dequeue pointers? In drivers/usb/host/xhci-ring.c, xhci_invalidate_cancelled_tds() first unlinks every TD on ep->cancelled_td_list from its transfer ring via list_del_init(&td->td_list). When cancelled TDs are stopped at hw_deq across multiple streams, the first TD becomes cached_td with TD_CLEARING_CACHE, while TDs in other streams are marked TD_CLEARING_CACHE_DEFERRED: drivers/usb/host/xhci-ring.c:xhci_invalidate_cancelled_tds() { ... if (cached_td->urb->stream_id != td->urb->stream_id) { /* Multiple streams case, defer move dq */ xhci_dbg(xhci, "Move dq deferred: stream %u URB %p\n", td->urb->stream_id, td->urb); td->cancel_status = TD_CLEARING_CACHE_DEFERRED; break; } ... } Later in xhci_invalidate_cancelled_tds(), the early return for disconnected non-control endpoints only clears cached_td: /* Don't bother fixing disconnected endpoints except EP0 */ if (ep->ep_state & EP_DROP_PENDING && ep->ep_index != 0) { cached_td->cancel_status = TD_CLEARED; return 0; } Any TDs in other streams remain in TD_CLEARING_CACHE_DEFERRED without a Set TR Dequeue command queued. When xhci_giveback_invalidated_tds() runs, those deferred TDs are skipped by the first loop because td->cancel_status != TD_CLEARED, and are then handed to xhci_kill_endpoint_urbs(). Because they were already removed from ring->td_list, xhci_kill_ring_urbs() does not see them, and they fall through to the ep->cancelled_td_list loop at the end of xhci_kill_endpoint_urbs(): drivers/usb/host/xhci-ring.c:xhci_kill_endpoint_urbs() { ... list_for_each_entry_safe(cur_td, tmp, &ep->cancelled_td_list, cancelled_td_list) { list_del_init(&cur_td->cancelled_td_list); inc_td_cnt(cur_td->urb); if (last_td_in_urb(cur_td)) xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); } } Unlike xhci_kill_ring_urbs() and xhci_td_cleanup(), this loop does not call xhci_unmap_td_bounce_buffer() (leaving seg->bounce_dma mapped and seg->bounce_len non-zero) and overwrites the cancelled URB's td->status with -ESHUTDOWN. Additionally, if EP_HALTED is set on the endpoint, those already-cancelled URBs will not be given back here either. Should the EP_DROP_PENDING && ep->ep_index != 0 path in xhci_invalidate_cancelled_tds() also mark any TD_CLEARING_CACHE_DEFERRED TDs as TD_CLEARED (similar to the xhci_move_deq_to_next_td() error path right below it) so that xhci_giveback_invalidated_tds() cleans them up normally? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261029075409.4b203658.michal.pecio@gmail.com?part=2 ^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 3/4] usb: xhci: Give back URBs on halted disconnected endpoints 2026-10-29 6:54 ` [PATCH 0/4] Fix problems on disconnected devices in 7.3 Michal Pecio 2026-10-29 6:54 ` [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints Michal Pecio 2026-10-29 6:55 ` [PATCH 2/4] usb: xhci: Give back stranded URBs " Michal Pecio @ 2026-10-29 6:56 ` Michal Pecio 2026-10-29 7:19 ` sashiko-bot 2026-10-29 6:57 ` [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices Michal Pecio 3 siblings, 1 reply; 41+ messages in thread From: Michal Pecio @ 2026-10-29 6:56 UTC (permalink / raw) To: Mathias Nyman Cc: yiyu, linux-usb, regressions, diogochaves, raoxu, dennis, gregkh Bailing out of xhci_handle_halted_endpoint() on disconnected devices had a side effect of leaving the failed URB and other URBs stranded until the driver times out or its disconnect() routine runs and the URBs are unlinked. And since disconnect() can't run during probe(), only timeouts remained, slowing down error handling and making some devices which disconnect during probe fail to probe altogether. Ensure giveback of all URBs when we don't queue Reset Endpoint. Set return status to 0, because the only caller that looks at it is xhci_handle_cmd_stop_ep(), which would only repeat an equivalent of xhci_process_cancelled_tds() if we return -ENODEV. Reported-by: Yiyu Zhou <yiyu@yiyuzhou.io> Link: https://lore.kernel.org/linux-usb/20261010064407.11030-1-yiyu@yiyuzhou.io/ Reported-by: Dennis Wissel <dennis@dsine.de> Link: https://lore.kernel.org/linux-usb/SrQQcLIwRWyg9PdEIpc0eg@dsine.de/ Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Cc: stable@vger.kernel.org Signed-off-by: Michal Pecio <michal.pecio@gmail.com> --- drivers/usb/host/xhci-ring.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 14cfb025c365..1097600699d4 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -993,13 +993,14 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, int err; /* - * Avoid resetting endpoint if link is inactive or device disonnected. - * Can cause host hang. - * Device will be reset to recover an inactive link, so don't do anything + * Flag endpoints behind disconnected RH ports and override soft retries. + * Restarting them is futile and known to trigger HC bugs on USB3 buses. */ if (rhub_port->link_inactive || !rhub_port->connected) { + xhci_dbg(xhci, "Halted slot %d ep %d is lost\n", + slot_id, ep->ep_index); ep->ep_state |= EP_DROP_PENDING; - return -ENODEV; + reset_type = EP_HARD_RESET; } /* add td to cancelled list and let reset ep handler take care of it */ @@ -1017,6 +1018,12 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, return 0; } + /* Don't reset lost endpoints, only EP0 can survive device reset */ + if (ep->ep_state & EP_DROP_PENDING && ep->ep_index != 0) { + xhci_process_cancelled_tds(xhci, ep); + return 0; + } + err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type); if (err) return err; -- 2.48.1 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH 3/4] usb: xhci: Give back URBs on halted disconnected endpoints 2026-10-29 6:56 ` [PATCH 3/4] usb: xhci: Give back URBs on halted " Michal Pecio @ 2026-10-29 7:19 ` sashiko-bot 0 siblings, 0 replies; 41+ messages in thread From: sashiko-bot @ 2026-10-29 7:19 UTC (permalink / raw) To: Michal Pecio; +Cc: linux-usb Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] usb: xhci: xhci_handle_halted_endpoint() completes failed URBs with status 0 - [High] usb: xhci: xhci_handle_halted_endpoint() skips killing URBs during Stop EP -- commit 87abeac00a1623e4912a3090721b206e6d47ac3a Author: Michal Pecio <michal.pecio@gmail.com> usb: xhci: Give back URBs on halted disconnected endpoints This commit updates xhci_handle_halted_endpoint() to override soft retries with EP_HARD_RESET and call xhci_process_cancelled_tds() for non-zero endpoints on disconnected or link-inactive roothub ports, ensuring URBs are given back without queuing a Reset Endpoint command. Link: https://lore.kernel.org/linux-usb/20261010064407.11030-1-yiyu@yiyuzhou.io/ Link: https://lore.kernel.org/linux-usb/SrQQcLIwRWyg9PdEIpc0eg@dsine.de/ > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c > index 49483eb55dc83..b731e59852f58 100644 > --- a/drivers/usb/host/xhci-ring.c > +++ b/drivers/usb/host/xhci-ring.c > @@ -995,13 +995,14 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, > int err; > > /* > - * Avoid resetting endpoint if link is inactive or device disonnected. > - * Can cause host hang. > - * Device will be reset to recover an inactive link, so don't do anything > + * Flag endpoints behind disconnected RH ports and override soft retries. > + * Restarting them is futile and known to trigger HC bugs on USB3 buses. > */ > if (rhub_port->link_inactive || !rhub_port->connected) { > + xhci_dbg(xhci, "Halted slot %d ep %d is lost\n", > + slot_id, ep->ep_index); > ep->ep_state |= EP_DROP_PENDING; > - return -ENODEV; > + reset_type = EP_HARD_RESET; > } [Severity: High] Can overriding reset_type from EP_SOFT_RESET to EP_HARD_RESET here cause failed bulk and interrupt URBs to be completed with status 0 (success)? When a bulk or interrupt transfer fails with COMP_USB_TRANSACTION_ERROR on a non-TT endpoint without XHCI_NO_SOFT_RETRY, handle_tx_event() calls process_bulk_intr_td(), which clears td->status to 0 before requesting a soft reset and returns before updating td->urb->actual_length: drivers/usb/host/xhci-ring.c:process_bulk_intr_td() case COMP_USB_TRANSACTION_ERROR: if (xhci->quirks & XHCI_NO_SOFT_RETRY || (ep->err_count++ > MAX_SOFT_RETRY) || le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) break; td->status = 0; xhci_handle_halted_endpoint(xhci, ep, td, EP_SOFT_RESET); return; When xhci_handle_halted_endpoint() upgrades reset_type to EP_HARD_RESET, it places td onto ep->cancelled_td_list with td->status still set to 0: if (reset_type == EP_HARD_RESET) { ep->ep_state |= EP_HARD_CLEAR_TOGGLE; if (td && list_empty(&td->cancelled_td_list)) { list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); td->cancel_status = TD_HALTED; } } Then xhci_process_cancelled_tds() -> xhci_invalidate_cancelled_tds() marks the TD as TD_CLEARED, and xhci_giveback_invalidated_tds() gives it back using td->status before xhci_kill_endpoint_urbs() runs: drivers/usb/host/xhci-ring.c:xhci_giveback_invalidated_tds() if (td->cancel_status == TD_CLEARED) { xhci_dbg(xhci, "%s: Giveback cancelled URB %p TD\n", __func__, td->urb); xhci_td_cleanup(xhci, td, ring, td->status); } Wouldn't this complete the failed URB to the USB driver with urb->status == 0 and urb->actual_length == 0 instead of an error code? > > /* add td to cancelled list and let reset ep handler take care of it */ > @@ -1019,6 +1020,12 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, > return 0; > } > > + /* Don't reset lost endpoints, only EP0 can survive device reset */ > + if (ep->ep_state & EP_DROP_PENDING && ep->ep_index != 0) { > + xhci_process_cancelled_tds(xhci, ep); > + return 0; > + } [Severity: High] What happens here if an endpoint halts on a disconnected or link-inactive port while a Stop Endpoint command is pending (EP_STOP_CMD_PENDING is set)? In xhci_giveback_invalidated_tds(), xhci_kill_endpoint_urbs() is skipped whenever EP_STOP_CMD_PENDING is set: drivers/usb/host/xhci-ring.c:xhci_giveback_invalidated_tds() /* Nuke stranded URBs if there is no one to give them back */ if ((ep->ep_state & EP_DROP_PENDING) && !(ep->ep_state & (EP_HALTED | SET_DEQ_PENDING | EP_STOP_CMD_PENDING))) xhci_kill_endpoint_urbs(xhci, ep->vdev->slot_id, ep->ep_index); When the Stop Endpoint command completes with COMP_CONTEXT_STATE_ERROR in EP_STATE_HALTED, xhci_handle_cmd_stop_ep() calls xhci_handle_halted_endpoint() before clearing EP_STOP_CMD_PENDING: drivers/usb/host/xhci-ring.c:xhci_handle_cmd_stop_ep() /* reset ep, reset handler cleans up cancelled tds */ err = xhci_handle_halted_endpoint(xhci, ep, td, reset_type); xhci_dbg(xhci, "Stop ep completion resetting ep, status %d\n", err); if (err) break; reset_done: /* Reset EP handler will clean up cancelled TDs */ ep->ep_state &= ~EP_STOP_CMD_PENDING; return; Because EP_STOP_CMD_PENDING is still set during the call to xhci_handle_halted_endpoint(), xhci_process_cancelled_tds() -> xhci_giveback_invalidated_tds() skips xhci_kill_endpoint_urbs(). Then, because xhci_handle_halted_endpoint() returns 0 instead of an error, xhci_handle_cmd_stop_ep() jumps to reset_done, clears EP_STOP_CMD_PENDING, and returns early without reaching the xhci_giveback_invalidated_tds() call at the end of xhci_handle_cmd_stop_ep(). Doesn't this leave all remaining non-cancelled URBs on the endpoint ring stranded? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261029075409.4b203658.michal.pecio@gmail.com?part=3 ^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices 2026-10-29 6:54 ` [PATCH 0/4] Fix problems on disconnected devices in 7.3 Michal Pecio ` (2 preceding siblings ...) 2026-10-29 6:56 ` [PATCH 3/4] usb: xhci: Give back URBs on halted " Michal Pecio @ 2026-10-29 6:57 ` Michal Pecio 2026-10-29 7:24 ` sashiko-bot 3 siblings, 1 reply; 41+ messages in thread From: Michal Pecio @ 2026-10-29 6:57 UTC (permalink / raw) To: Mathias Nyman Cc: yiyu, linux-usb, regressions, diogochaves, raoxu, dennis, gregkh Restarting halted endpoints of disconnected USB3 devices triggers some HW bugs and we actually prevent this on all devices now. Keep drivers from pointlessly submitting URBs and needing to unlink them later, which may involve excessive timeouts. This generalizes existing check for USB3 ports in the Error state. Suggested-by: Yiyu Zhou <yiyu@yiyuzhou.io> Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.") Cc: stable@vger.kernel.org Signed-off-by: Michal Pecio <michal.pecio@gmail.com> --- drivers/usb/host/xhci.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e5c8b3a945a6..66b9fed65ac7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1662,12 +1662,6 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag goto free_priv; } - if (xhci->devs[slot_id]->rhub_port->link_inactive) { - xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); - ret = -ENODEV; - goto free_priv; - } - if (xhci->xhc_state & XHCI_STATE_DYING) { xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n", urb->ep->desc.bEndpointAddress, urb); @@ -1677,6 +1671,13 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state; + if (xhci->devs[slot_id]->rhub_port->link_inactive || + !xhci->devs[slot_id]->rhub_port->connected || *ep_state & EP_DROP_PENDING) { + xhci_dbg(xhci, "Can't queue urb, link error or disconnected\n"); + ret = -ENODEV; + goto free_priv; + } + if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", *ep_state); -- 2.48.1 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices 2026-10-29 6:57 ` [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices Michal Pecio @ 2026-10-29 7:24 ` sashiko-bot 0 siblings, 0 replies; 41+ messages in thread From: sashiko-bot @ 2026-10-29 7:24 UTC (permalink / raw) To: Michal Pecio; +Cc: linux-usb Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] usb: xhci: stale rhub_port state in xhci_urb_enqueue() rejects valid URBs -- commit 3e6930cee6e8275b8d271ab4827ba5004d45037f Author: Michal Pecio <michal.pecio@gmail.com> usb: xhci: Reject URBs to disconnected devices This commit extends the port link error check in xhci_urb_enqueue() to also reject URBs with -ENODEV when the root hub port is marked disconnected or the endpoint has EP_DROP_PENDING set. > diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c > index a9e47e178c280..4a893a8438c3a 100644 > --- a/drivers/usb/host/xhci.c > +++ b/drivers/usb/host/xhci.c > @@ -1665,12 +1665,6 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag > goto free_priv; > } > > - if (xhci->devs[slot_id]->rhub_port->link_inactive) { > - xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); > - ret = -ENODEV; > - goto free_priv; > - } > - > if (xhci->xhc_state & XHCI_STATE_DYING) { > xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n", > urb->ep->desc.bEndpointAddress, urb); > @@ -1680,6 +1674,13 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag > > ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state; > > + if (xhci->devs[slot_id]->rhub_port->link_inactive || > + !xhci->devs[slot_id]->rhub_port->connected || *ep_state & EP_DROP_PENDING) { > + xhci_dbg(xhci, "Can't queue urb, link error or disconnected\n"); > + ret = -ENODEV; > + goto free_priv; > + } [Severity: High] Can rhub_port->connected, rhub_port->link_inactive, or EP_DROP_PENDING remain stale here and cause xhci_urb_enqueue() to reject valid URBs (including EP0 control transfers) during device reset, resuscitation, resume, or enumeration? Across the xHCI driver, port->connected and port->link_inactive are only updated in drivers/usb/host/xhci-ring.c:handle_port_status() when a hardware TRB_PORT_STATUS event is received while PORT_RESET is not set: drivers/usb/host/xhci-ring.c:handle_port_status() { ... if (!(portsc & PORT_RESET)) { port->link_inactive = (pls == XDEV_INACTIVE); port->connected = !!(portsc & PORT_CONNECT); } ... /* * xHCI port-status-change events occur when the "or" of all the * status-change bits in the portsc register changes from 0 to 1. * New status changes won't cause an event if any other change * bits are still set. When an event occurs, switch over to * polling to avoid losing status changes. */ } Neither xhci_get_port_status(), xhci_clear_port_change_bit(), nor xhci_discover_or_reset_device() updates port->connected or port->link_inactive: drivers/usb/host/xhci-hub.c:xhci_get_port_status() { ... /* common wPortStatus bits */ if (portsc & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; status |= xhci_port_speed(portsc); } } drivers/usb/host/xhci.c:xhci_discover_or_reset_device() { ... command_cleanup: for (i = 0; i < EP_CTX_PER_DEV; i++) virt_dev->eps[i].ep_state &= ~EP_DROP_PENDING; } When a disconnect (PORT_CSC = 1, PORT_CONNECT = 0) or link error (PORT_PLC = 1, pls = XDEV_INACTIVE) occurs, handle_port_status() sets port->connected = 0 or port->link_inactive = 1, leaves the status-change bits set in PORTSC, and switches the roothub to polling. Because the xHC only generates a TRB_PORT_STATUS event when the logical OR of all PORTSC status-change bits transitions from 0 to 1, subsequent transitions back to PORT_CONNECT = 1 or XDEV_U0 will not generate a new TRB_PORT_STATUS event while any change bit remains set in PORTSC. This appears to leave rhub_port state (or EP_DROP_PENDING) stale in several paths: 1. Device reset or resuscitation across a disconnect or link error via usb_reset_device() -> usb_reset_and_verify_device() -> hub_port_init() -> hub_port_reset(), where port_dev->status_lock is held so port_event() cannot clear PORT_CSC or PORT_PLC. On USB3 root ports, PORT_CSC or PORT_PLC stays set throughout the reset, suppressing TRB_PORT_STATUS when the device reconnects and reset completes. On USB2 root ports, if the first reset completes while PORT_CSC is set, hub_port_wait_reset() clears only C_CONNECTION and returns -EAGAIN without clearing C_RESET (PORT_RC), so PORT_RC stays set throughout the retry reset and suppresses TRB_PORT_STATUS when the retry completes. Although xhci_discover_or_reset_device() clears EP_DROP_PENDING, rhub_port->connected remains 0 (or link_inactive remains 1), causing get_bMaxPacketSize0() or usb_get_device_descriptor() in hub_port_init() to fail with -ENODEV. 2. Delayed connection after reset completion in drivers/usb/core/hub.c:hub_port_wait_reset(): drivers/usb/core/hub.c:hub_port_wait_reset() { ... if (!(portstatus & USB_PORT_STAT_RESET) && (portstatus & USB_PORT_STAT_CONNECTION)) break; } If PORT_RESET clears (setting PORT_RC = 1) before PORT_CONNECT is asserted, handle_port_status() runs on the PORT_RC event while PORT_CONNECT is 0 and sets port->connected = 0. When PORT_CONNECT subsequently becomes 1 while PORT_RC is still set, no new TRB_PORT_STATUS event fires. 3. Connect bounce during hub_port_debounce(): a bounce disconnect sets PORT_CSC = 1 (and/or PORT_PLC = 1) and port->connected = 0. If the port reconnects during the debounce sleep while PORT_CSC is still 1, no TRB_PORT_STATUS event fires on reconnect, and hub_port_debounce() clears C_CONNECTION while leaving port->connected == 0. 4. Status change during active reset: if PORT_CSC or PORT_PLC becomes 1 while PORT_RESET is active, TRB_PORT_STATUS fires while (portsc & PORT_RESET) is true, so handle_port_status() skips updating port->connected and port->link_inactive, and the uncleared change bit suppresses the event when PORT_RESET clears. 5. USB3 resuscitation without a port reset in drivers/usb/core/hub.c:hub_port_connect_change(), or transient disconnect during wait_for_connected() in usb_port_resume(): drivers/usb/core/hub.c:hub_port_connect_change() { ... if (portstatus & USB_PORT_STAT_ENABLE) { /* * USB-3 connections are initialized automatically by * the hostcontroller hardware. Therefore check for * changed device descriptors before resuscitating the * device. */ descr = usb_get_device_descriptor(udev); } If a USB3 device briefly disconnects (setting PORT_CSC = 1, port->connected = 0, and EP_DROP_PENDING on halted/stopped endpoints) and reconnects to U0 while PORT_CSC is still 1, no second TRB_PORT_STATUS event fires. When hub_port_connect_change() or finish_port_resume() then submits EP0 control URBs without calling xhci_discover_or_reset_device(), won't xhci_urb_enqueue() reject them with -ENODEV due to stale rhub_port->connected == 0 or stale EP_DROP_PENDING on EP0? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261029075409.4b203658.michal.pecio@gmail.com?part=4 ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect 2026-10-27 19:21 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman ` (3 preceding siblings ...) 2026-10-28 7:07 ` Michal Pecio @ 2026-10-29 4:18 ` Yiyu Zhou 4 siblings, 0 replies; 41+ messages in thread From: Yiyu Zhou @ 2026-10-29 4:18 UTC (permalink / raw) To: Mathias Nyman Cc: Yiyu Zhou, Michal Pecio, Greg Kroah-Hartman, Dennis Wissel, diogochaves, raoxu, linux-usb, regressions On Tue, 27 Oct 2026 21:21:25 +0200, Mathias Nyman wrote: > If you have seen the HID enumeration issue, or the xHC Stop Endpoint > failures with rapid endpoint state changes, testing these two patches > would be greatly appreciated. I have seen the HID enumeration issue, and I tested both patches on the laptop that shows it: a System76 Galago Pro (galp7) with an Intel Alder Lake PCH xHCI (8086:51ed), running v7.3 plus these two patches, with the xhci_hcd dynamic debug messages enabled. The keyboard is a PFU HHKB Professional HYBRID Type-S (04fe:0021) on root port 3-2. It drops off the bus about 0.28 s after its first enumeration, which is what used to hang. I unplugged and replugged it three times, once right after an S3 resume. Each time the keyboard was back with all three interfaces bound about 0.9 s after the first "new full-speed USB device" line. There was no -110 from usbhid, no hung task, no "not part of TD" error and no command timeout. The dynamic debug output was on for the last two replugs. This is the second one (trimmed): [ 526.532129] usb 3-2: new full-speed USB device number 7 using xhci_hcd [ 526.764553] xhci_hcd 0000:00:14.0: Port change event, 3-2, id 2, portsc: 0x202a0 [ 526.765548] xhci_hcd 0000:00:14.0: Not resetting ep 2 slot 6 after disconnect [ 526.766517] xhci_hcd 0000:00:14.0: Giveback URB 00000000123956d9, len = 0, expected = 8, status = -71 [ 526.767395] xhci_hcd 0000:00:14.0: Not resetting ep 4 slot 6 after disconnect [ 526.768195] xhci_hcd 0000:00:14.0: Giveback URB 00000000fa65d958, len = 0, expected = 31, status = -71 [ 526.780018] xhci_hcd 0000:00:14.0: Can't queue urb, port disconnect or link inactive [ 526.812029] xhci_hcd 0000:00:14.0: TRB error 4, halted endpoint index = 0 [ 526.812280] xhci_hcd 0000:00:14.0: Hard-reset ep 0, slot 6 [ 526.812752] xhci_hcd 0000:00:14.0: Ignoring reset ep completion code of 1 [ 526.813210] xhci_hcd 0000:00:14.0: Set TR Deq ptr 0x112dd12f0, cycle 1 [ 526.813846] xhci_hcd 0000:00:14.0: Successful Set TR Deq Ptr cmd, deq = @112dd12f0 [ 526.814254] xhci_hcd 0000:00:14.0: Giveback URB 00000000aa106b15, len = 0, expected = 0, status = -71 [ 526.814648] xhci_hcd 0000:00:14.0: Can't queue urb, port disconnect or link inactive [ 526.815742] usb 3-2: USB disconnect, device number 7 [ 527.167687] usb 3-2: new full-speed USB device number 8 using xhci_hcd [ 527.426094] hid-generic 0003:04FE:0021.000E: hiddev96,hidraw2: ... on usb-0000:00:14.0-2/input2 > Only Reset Endpoint and Set TR Dequeue Pointer commands are issued; > ep0 is not restarted while the disconnect is pending. That is what the log shows here. Reset Endpoint on the disconnected ep0 completed with success, Set TR Dequeue Pointer succeeded, the control URB was given back with -71, and later URBs were refused until hub_wq re-enumerated the device. The other endpoints were given back without a reset. I saw no controller hang or command timeout, so this Intel xHC is fine with Reset Endpoint on a disconnected ep0 (it ran twice). > If these patches work, they might be squashed into one before going > upstream. Squashing is fine with me. 1/2 alone leaves the stale TRBs on the ep0 ring, as the cover letter says, so I would not apply it separately. Tested-by: Yiyu Zhou <yiyu@yiyuzhou.io> I have not tried the RFC diff Michal posted in this thread. I am happy to run it on the HHKB once it has a changelog. -YZ ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 20:39 ` Yiyu Zhou 2026-10-27 7:29 ` Dennis Wissel @ 2026-10-27 10:58 ` Michal Pecio 1 sibling, 0 replies; 41+ messages in thread From: Michal Pecio @ 2026-10-27 10:58 UTC (permalink / raw) To: Yiyu Zhou Cc: Dennis Wissel, Mathias Nyman, Alan Stern, linux-usb, regressions On Mon, 26 Oct 2026 13:39:42 -0700, Yiyu Zhou wrote: > On Mon, 26 Oct 2026 12:15:44 +0100, Michal Pecio wrote: > > I wonder if it's possible that usbhid driver requests a reset to > > recover from errors and usbcore performs it blindly without paying > > attention to connect status? > > I think that is what happens, and that 1f36cc9fa949 is what makes it > reachable here. > > Interfaces 0 and 1 bind before the device drops off, and the VT > keyboard handler opens the keyboard interface right away, so its > interrupt-in URB is running. With 1f36cc9fa949 that URB is given back > with -EPROTO and the resubmits fail with -ENODEV, so hid_io_error() > keeps retrying and after 1 s schedules hid_reset(), which calls > usb_queue_reset_device(). usb_reset_device() only checks for > USB_STATE_NOTATTACHED, and the udev stays configured until hub_wq > handles the connect change. At boot hub_wq only gets back to port 1 > after the other ports (about 1.5 s after the disconnect in Dennis's > dyndbg log), so the reset gets there first. The device is back by > then, so the port reset succeeds and the reset reuses the udev and the > slot, ep0 ring included. Yes, this seems plausible based on the input from Alan Stern. If reset is requested before a USB2 reconnection but executed after it, then hub_port_connect_change() sees (connect-change && enabled) port state and it attempts to reuse ("resuscitate") the existing udev. > On plain 7.3 the halted interrupt TD isn't given back until hub_wq > handles the disconnect, so usbhid sees no error and never asks for a > reset. The device only comes back through the full disconnect at 56 s > in Dennis's first log, which frees the slot and its ring. Plausible too. But while the bug isn't triggered, it's still there. Even on 7.3 without 1f36cc9fa949, when the failed URB is unlinked, it seems that xhci_invalidate_cancelled_tds() marks its TDs as ready for giveback without doing anything to prevent their execution. The EP is expected never to run again and we are just lucky that nobody resets the device before it's freed. > Instead of repairing ep0 in place, could it stay blocked until Address > Device has reloaded its context? Not really, because EP0 must be ready for URBs before the device is addressed, and the "BSR" flag is only legal on freshly enabled slots. > If EP_DROP_PENDING stays set on ep0 until then, the new-scheme > GET_DESCRIPTOR fails at once with -ENODEV, and > usb_reset_and_verify_device() re-enumerates the device on a new slot, > as after a real disconnect. You seem to suggest that xhci-hcd should trick usbcore into abandoning "resuscitation", right? I think that's a sort of complexity that the world would be better off without, and it changes an intentional policy of usbcore, so it's not suitable for an urgent stable fix. The "right" thing to do here is to use Stop Endpoint and Set TR Dequeue after Reset Device or Reset Endpoint (if applicable) and Set TR Dequeue before Reset device, i.e. exclude EP0 from EP_DROP_PENDING logic. Possibly the simplest way out, at least for the already released 7.3, might be partly reverting the offending commits so as not to affect USB2. The original VDEV_PORT_ERROR logic was exclusive to USB3 and the problems which 7.3 was supposed to solve are also exclusive to USB3. Is there any need for this to affect USB2, other than "just in case"? Then there will be a few weeks to sort out remaining USB3 issues, which mostly existed for a while and haven't bothered anybody. Regards, Michal ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-25 10:14 ` Michal Pecio 2026-10-25 11:11 ` Dennis Wissel @ 2026-10-26 9:18 ` Mathias Nyman 2026-10-26 9:51 ` Michal Pecio 1 sibling, 1 reply; 41+ messages in thread From: Mathias Nyman @ 2026-10-26 9:18 UTC (permalink / raw) To: Michal Pecio, Dennis Wissel; +Cc: Yiyu Zhou, linux-usb, regressions On 10/25/26 12:14, Michal Pecio wrote: > Hi, > > On Sun, 25 Oct 2026 01:10:27 +0200, Dennis Wissel wrote: >> On Sat, 24 Oct 2026 13:34:07 -0700, Yiyu Zhou wrote: >>> The fix is queued in Mathias's for-usb-linus branch as 1f36cc9fa949 >>> ("xhci: give back all TDs when skipping endpoint reset after >>> disconnect") and applies cleanly to v7.3: >> [...] >>> Could you test it? If it fixes your case, please reply here so that >>> Mathias can add your Tested-by. If it does not, reverting >>> 042aad8d0db6 and 7e0ef4332ed9 on v7.3 would show whether these >>> commits are involved. >> >> Thanks, I tested both on top of 7.3.0-4-cachyos, booting with the >> mouse plugged in each time. >> >> 1) With 1f36cc9fa949: much better, but not completely fixed. >> >> No reset loop anymore. After one disconnect and re-enumeration all four >> interfaces bind, and both the mouse and the NuPhy keyboard work. >> Before, the boot took about 3 minutes and both were dead. >> >> But hub_wq still stalls for about 11 s after the first reset of the >> mouse. Other devices on the same controller (1-9.2, 1-14) are only >> enumerated after that. Just before the disconnect is handled, xhci >> prints three "not part of TD" messages for ep 0: >> >> [ 3.509460] usb 1-1: new full-speed USB device number 2 using xhci_hcd >> [ 3.510626] hid-generic 0003:3434:D068.0001: input,hidraw0: USB HID v1.11 Mouse [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input0 >> [ 3.510772] hid-generic 0003:3434:D068.0002: input,hidraw1: USB HID v1.11 Keyboard [Keychron Keychron M5 ] on usb-0000:00:14.0-1/input1 >> [ 4.973074] usb 1-1: reset full-speed USB device number 2 using xhci_hcd >> (nothing on the bus for 11 s) >> [ 15.970122] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205260 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 >> [ 15.970767] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205280 for ep 0 status 13 not part of TD at 00000001042052d0 - 00000001042052f0 >> [ 15.971131] xhci_hcd 0000:00:14.0: Event dma 0x0000000104205290 for ep 0 status 1 not part of TD at 00000001042052d0 - 00000001042052f0 > > That's not good, your HC seems to be executing stale URBs, probably > from before the device was reset. I suspect we reuse the default pipe > without recovering it from the broken state left by EP_DROP_PENDING. > (Such bug may have existed since forever, but only in USB3 and cases > which seldom or never happen. 7.3 generalized it to more cases.) > > But is USB core really resetting a device for which the hub has > reported disconnection? Something isn't as I would expect. I suspect udev, xhci virt_dev, and thus xhci ep0 ring stays intact even if device has a short disconnect during reset/enumeration. So even if we give back all pending URBs and clear the EP_DROP_PENDING flag we continue using the stale ring. We should either either move dequeue pointer, set TRBs to no-op, or clear and reinitialize whole ep0 ring at device reset. -Mathias ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 9:18 ` Mathias Nyman @ 2026-10-26 9:51 ` Michal Pecio 2026-10-26 11:38 ` Michal Pecio 2026-10-26 18:56 ` Alan Stern 0 siblings, 2 replies; 41+ messages in thread From: Michal Pecio @ 2026-10-26 9:51 UTC (permalink / raw) To: Mathias Nyman; +Cc: Dennis Wissel, Yiyu Zhou, linux-usb, regressions On Mon, 26 Oct 2026 11:18:34 +0200, Mathias Nyman wrote: > > That's not good, your HC seems to be executing stale URBs, probably > > from before the device was reset. I suspect we reuse the default pipe > > without recovering it from the broken state left by EP_DROP_PENDING. > > (Such bug may have existed since forever, but only in USB3 and cases > > which seldom or never happen. 7.3 generalized it to more cases.) > > > > But is USB core really resetting a device for which the hub has > > reported disconnection? Something isn't as I would expect. > > I suspect udev, xhci virt_dev, and thus xhci ep0 ring stays intact > even if device has a short disconnect during reset/enumeration. But this doesn't make sense, right? If the port reports connect state change, we have no idea if it's still the same device or not, I would expect udev to be discarded. Or is this some "USB persist" magic? I didn't want to dig into the hub driver or bother Alan, I hope we will get that debug log showing what usbcore is doing there. > So even if we give back all pending URBs and clear the > EP_DROP_PENDING flag we continue using the stale ring. We should > either either move dequeue pointer, set TRBs to no-op, or clear and > reinitialize whole ep0 ring at device reset. This may need to be fixed regardless, because EP_DROP_PENDING on EP0 can result from xHCI "Error" aka USB3 "Inactive" state, which (AFAIU) may be cleared with warm reset, without reallocating the udev. That's the "existed since forever" issue I was thinking about. Regards, Michal ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 9:51 ` Michal Pecio @ 2026-10-26 11:38 ` Michal Pecio 2026-10-26 11:54 ` Mathias Nyman 2026-10-26 18:56 ` Alan Stern 1 sibling, 1 reply; 41+ messages in thread From: Michal Pecio @ 2026-10-26 11:38 UTC (permalink / raw) To: Mathias Nyman; +Cc: Dennis Wissel, Yiyu Zhou, linux-usb, regressions On Mon, 26 Oct 2026 10:51:39 +0100, Michal Pecio wrote: > On Mon, 26 Oct 2026 11:18:34 +0200, Mathias Nyman wrote: > > So even if we give back all pending URBs and clear the > > EP_DROP_PENDING flag we continue using the stale ring. We should > > either either move dequeue pointer, set TRBs to no-op, or clear and > > reinitialize whole ep0 ring at device reset. > > This may need to be fixed regardless, because EP_DROP_PENDING on EP0 > can result from xHCI "Error" aka USB3 "Inactive" state, which (AFAIU) > may be cleared with warm reset, without reallocating the udev. That's > the "existed since forever" issue I was thinking about. 4.6.11 isn't 100% explicit what happens if EP 0 is halted at Reset Device, but generally it should "terminate any USB activity, abort any pending events and transition to the Running state". So just a Set TR Dequeue to current enqueue will probably work, but I think this has never been tried before. I see that xhci_discover_or_reset_device() clears EP_DROP_PENDING even in case of Reset Device failure, which looks a little odd. We probably wouldn't want to issue Set TR Deq in such case and don't want to clear this flag without fixing the endpoint. What was the reason for placing this loop after and not before the command_cleanup label? command_cleanup: for (i = 0; i < EP_CTX_PER_DEV; i++) virt_dev->eps[i].ep_state &= ~EP_DROP_PENDING; xhci_free_command(xhci, reset_device_cmd); return ret; } ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 11:38 ` Michal Pecio @ 2026-10-26 11:54 ` Mathias Nyman 0 siblings, 0 replies; 41+ messages in thread From: Mathias Nyman @ 2026-10-26 11:54 UTC (permalink / raw) To: Michal Pecio; +Cc: Dennis Wissel, Yiyu Zhou, linux-usb, regressions On 10/26/26 13:38, Michal Pecio wrote: > On Mon, 26 Oct 2026 10:51:39 +0100, Michal Pecio wrote: >> On Mon, 26 Oct 2026 11:18:34 +0200, Mathias Nyman wrote: >>> So even if we give back all pending URBs and clear the >>> EP_DROP_PENDING flag we continue using the stale ring. We should >>> either either move dequeue pointer, set TRBs to no-op, or clear and >>> reinitialize whole ep0 ring at device reset. >> >> This may need to be fixed regardless, because EP_DROP_PENDING on EP0 >> can result from xHCI "Error" aka USB3 "Inactive" state, which (AFAIU) >> may be cleared with warm reset, without reallocating the udev. That's >> the "existed since forever" issue I was thinking about. > > 4.6.11 isn't 100% explicit what happens if EP 0 is halted at Reset > Device, but generally it should "terminate any USB activity, abort > any pending events and transition to the Running state". > > So just a Set TR Dequeue to current enqueue will probably work, but > I think this has never been tried before. > > I see that xhci_discover_or_reset_device() clears EP_DROP_PENDING > even in case of Reset Device failure, which looks a little odd. We > probably wouldn't want to issue Set TR Deq in such case and don't > want to clear this flag without fixing the endpoint. > > What was the reason for placing this loop after and not before > the command_cleanup label? USB core may reset a device several times without reaching 'addresses' or 'configured' state in between resets. The reset device command in xhci fails with a "context state error" if the slot isn't in a addressed or configured state. Make sure we clear the flag in those cases. -Mathias ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 9:51 ` Michal Pecio 2026-10-26 11:38 ` Michal Pecio @ 2026-10-26 18:56 ` Alan Stern 2026-10-26 18:58 ` Alan Stern 1 sibling, 1 reply; 41+ messages in thread From: Alan Stern @ 2026-10-26 18:56 UTC (permalink / raw) To: Michal Pecio Cc: Mathias Nyman, Dennis Wissel, Yiyu Zhou, linux-usb, regressions On Mon, Oct 26, 2026 at 10:51:39AM +0100, Michal Pecio wrote: > On Mon, 26 Oct 2026 11:18:34 +0200, Mathias Nyman wrote: > > > But is USB core really resetting a device for which the hub has > > > reported disconnection? Something isn't as I would expect. > > > > I suspect udev, xhci virt_dev, and thus xhci ep0 ring stays intact > > even if device has a short disconnect during reset/enumeration. > > But this doesn't make sense, right? If the port reports connect state > change, we have no idea if it's still the same device or not, I would > expect udev to be discarded. Or is this some "USB persist" magic? > > I didn't want to dig into the hub driver or bother Alan, I hope we will > get that debug log showing what usbcore is doing there. You can read the login in hub.c:hub_port_connect_change(). Broadly speaking, if the port is enabled after a connect-change event, the core tries to resuscitate the child device (and checks whether the descriptors have changed). Also, if the child device was suspended when the connect change occurred, the core will try to resuscitate it by treating the change as a wakeup event. Alan Stern ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-26 18:56 ` Alan Stern @ 2026-10-26 18:58 ` Alan Stern 0 siblings, 0 replies; 41+ messages in thread From: Alan Stern @ 2026-10-26 18:58 UTC (permalink / raw) To: Michal Pecio Cc: Mathias Nyman, Dennis Wissel, Yiyu Zhou, linux-usb, regressions On Mon, Oct 26, 2026 at 02:56:49PM -0400, Alan Stern wrote: > On Mon, Oct 26, 2026 at 10:51:39AM +0100, Michal Pecio wrote: > > On Mon, 26 Oct 2026 11:18:34 +0200, Mathias Nyman wrote: > > > > But is USB core really resetting a device for which the hub has > > > > reported disconnection? Something isn't as I would expect. > > > > > > I suspect udev, xhci virt_dev, and thus xhci ep0 ring stays intact > > > even if device has a short disconnect during reset/enumeration. > > > > But this doesn't make sense, right? If the port reports connect state > > change, we have no idea if it's still the same device or not, I would > > expect udev to be discarded. Or is this some "USB persist" magic? > > > > I didn't want to dig into the hub driver or bother Alan, I hope we will > > get that debug log showing what usbcore is doing there. > > You can read the login in hub.c:hub_port_connect_change(). -------------------^^^^^ Meant to write "logic". > > Broadly speaking, if the port is enabled after a connect-change event, > the core tries to resuscitate the child device (and checks whether the > descriptors have changed). Also, if the child device was suspended when > the connect change occurred, the core will try to resuscitate it by > treating the change as a wakeup event. > > Alan Stern ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 2026-10-24 17:47 [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Dennis Wissel 2026-10-24 20:34 ` Yiyu Zhou 2026-10-24 20:35 ` Yiyu Zhou @ 2026-10-25 6:28 ` Greg KH 2 siblings, 0 replies; 41+ messages in thread From: Greg KH @ 2026-10-25 6:28 UTC (permalink / raw) To: Dennis Wissel; +Cc: linux-usb, mathias.nyman, regressions On Sat, Oct 24, 2026 at 07:47:10PM +0200, Dennis Wissel wrote: > My guess, untested: the xhci changes merged for 7.3 that touch > cancelled transfers on control endpoints, e.g. 7c0c31c66a7f ("move > dequeue to next valid td instead of past cancelled one"). The fast -71 > on 7.2 turning into -110 timeouts plus resets on 7.3 seems to fit > that. I haven't bisected or tested a revert yet, but I can if you > point me at what to try. Any chance you can use 'git bisect' to find the offending commit? thanks, greg k-h ^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2026-10-29 7:24 UTC | newest] Thread overview: 41+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-24 17:47 [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Dennis Wissel 2026-10-24 20:34 ` Yiyu Zhou 2026-10-24 20:35 ` Yiyu Zhou 2026-10-24 23:10 ` Dennis Wissel 2026-10-25 8:59 ` Thorsten Leemhuis 2026-10-26 9:28 ` Mathias Nyman 2026-10-26 9:49 ` Thorsten Leemhuis 2026-10-26 10:47 ` Greg KH 2026-10-25 10:14 ` Michal Pecio 2026-10-25 11:11 ` Dennis Wissel 2026-10-26 11:15 ` Michal Pecio 2026-10-26 20:39 ` Yiyu Zhou 2026-10-27 7:29 ` Dennis Wissel 2026-10-27 8:48 ` [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it Yiyu Zhou 2026-10-27 9:10 ` sashiko-bot 2026-10-27 10:36 ` Mathias Nyman 2026-10-27 11:27 ` Michal Pecio 2026-10-27 18:40 ` Yiyu Zhou 2026-10-27 19:21 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman 2026-10-27 19:21 ` [RFT PATCH 1/2] xhci: give back all TDs when skipping endpoint reset after disconnect Mathias Nyman 2026-10-27 19:21 ` [RFT PATCH 2/2] xhci: clean up ep0 ring after disconnect instead of leaving stale TRBs Mathias Nyman 2026-10-27 23:05 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Dennis Wissel 2026-10-28 7:07 ` Michal Pecio 2026-10-29 6:54 ` [PATCH 0/4] Fix problems on disconnected devices in 7.3 Michal Pecio 2026-10-29 6:54 ` [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints Michal Pecio 2026-10-29 7:12 ` sashiko-bot 2026-10-29 6:55 ` [PATCH 2/4] usb: xhci: Give back stranded URBs " Michal Pecio 2026-10-29 7:23 ` sashiko-bot 2026-10-29 6:56 ` [PATCH 3/4] usb: xhci: Give back URBs on halted " Michal Pecio 2026-10-29 7:19 ` sashiko-bot 2026-10-29 6:57 ` [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices Michal Pecio 2026-10-29 7:24 ` sashiko-bot 2026-10-29 4:18 ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Yiyu Zhou 2026-10-27 10:58 ` [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Michal Pecio 2026-10-26 9:18 ` Mathias Nyman 2026-10-26 9:51 ` Michal Pecio 2026-10-26 11:38 ` Michal Pecio 2026-10-26 11:54 ` Mathias Nyman 2026-10-26 18:56 ` Alan Stern 2026-10-26 18:58 ` Alan Stern 2026-10-25 6:28 ` Greg KH
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox