Linux USB
 help / color / mirror / Atom feed
* [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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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; 31+ 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] 31+ 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
                                         ` (3 more replies)
  0 siblings, 4 replies; 31+ 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] 31+ 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
                                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 31+ 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] 31+ 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
  2026-10-28  7:07                       ` Michal Pecio
  3 siblings, 0 replies; 31+ 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] 31+ 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
  3 siblings, 0 replies; 31+ 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] 31+ 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
  3 siblings, 0 replies; 31+ 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] 31+ messages in thread

end of thread, other threads:[~2026-10-28  7:07 UTC | newest]

Thread overview: 31+ 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-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