Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error

Alan Stern
2026-04-22T14:57:56Z

On Wed, Apr 22, 2026 at 07:30:54AM +0200, Michal Pecio wrote:
> On Tue, 21 Apr 2026 22:11:41 -0400, Alan Stern wrote:
> > Can you confirm that it's also possible for xhci-hcd to prevent
> > control endpoints from restarting when a transaction error (-EPROTO)
> > occurs? Up until usb_reset_endpoint() or a new callback?
>
> Doable. They halt like any other and it's SW's choice how to restart.
>
> BTW, what about EOVERFLOW? It's treated similarly by xhci-hcd.

That also counts as a transaction error. So do EILSEQ, ETIME, ECOMM,
and ENOSR (even if xhci-hcd never generates them).

> > I've been thinking about how to implement all this, and some issues
> > have to be solved. In particular, suppose we have sent a Clear-Halt
> > request for an endpoint that has gotten an error, and either the
> > request times out or the device replies with a stall.
>
> (... or the TT replies with STALL due to downstream bus EPROTO).
>
> > My feeling is that either of these events would mean that the device
> > is so far out of whack that the only thing to do is try resetting it.
> > Any proposals for something a little less drastic?
>
> Let's look at possible causes:
>
> 1. disconnected device
> Doesn't matter what happens.
>
> 2. completely brain dead host controller
> Ditto. Just be sure not to lock up so xhci-hcd can be reloaded.
>
> 3. temporary EMI or low link quality
> This should clear itself after a few retries.

In this case we would get an error, not a timeout or stall. Unless the
problem is on the downstream side of a TT, in which case we would get a
stall. (Oddly, this case seems to be missing from the state diagrams of
Figures 11-55 and 11-59 in the USB 2.0 spec.)

I guess to be safe, we should treat stall the same as an error.

> 4. broken D+/D- wire in a LS/FS cable
> Issues can last arbitrarily long and yet still clear.
> Least disruptive solution: wait forever with sporadic retries.
> Acceptable alternative: request user attention, i.e. disconnect.
>
> Note: we would disconnect instantly if the opposite wire broke.

Same as above, except for the "temporary" part.

> 5. crashed device firmware
> In this case a reset seems more productive than retrying forever.
>
> A compromise betwen 4 and 5 could be to retry for some time, then
> reset a few times, then disconnect.

My plan is to retry up until about 1 second and then do a reset. If the
reset fails, the device is logically disconnected.

> 6. device doesn't support clear-halt, stalls or does something odd
>
> Nightmare fuel.

Devices are required to support clear-halt for bulk and interrupt
endpoints. And the only reason for stalling a clear-halt request, as
far as I know, is if the request is invalid in some way (such as
specifying an endpoint that doesn't exist).

Either way, I can't think of anything else to do besides retries and
then reset.

> > Also, it seems reasonable to devote only a single thread to endpoint
> > error recovery. Another possibility would be to have one thread for
> > each device having problems, but I think the likelihood of this
> > happening to multiple devices at once is pretty small unless the
> > problem affects a hub upstream from all of them -- in which case
> > having multiple threads wouldn't really help much. Other opinions?
>
> Well, another option is asynchronous URBs and "callback hell". For
> instance, besides hcd methods, all xhci-hcd endpoint management is
> asynchronous, tracks current state with bit flags and defers actions
> blocked by flags until the flags are cleared. This includes waiting
> for Reset Endpoint commands, TT clearing, ongoing unlinks, etc.
>
> One practical complication is that hcd->endpoint_reset() may sleep.
> But it will only extremely rarely take 5 seconds and time out.

Even so, that means the recovery has to be done by a thread.

Alan Stern