* [RFC PATCH 0/2] fix xhci endpoint restart at EPROTO
@ 2026-03-23 12:25 Mathias Nyman
2026-03-23 12:25 ` [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error Mathias Nyman
2026-03-23 12:25 ` [RFC PATCH 2/2] xhci: Ensure URB is given back when endpoint halts on a multi-TD URB Mathias Nyman
0 siblings, 2 replies; 8+ messages in thread
From: Mathias Nyman @ 2026-03-23 12:25 UTC (permalink / raw)
To: linux-usb
Cc: stern, Thinh.Nguyen, michal.pecio, oneukum, niklas.neronin,
Mathias Nyman
Hi
These patches are related to the 'correctly handling EPROTO' discussion,
and aim to fix the xhci endpoint automatic restart issue.
It also makes sure that multi TD URBs are given back with proper
EPROTO/EPIPE status if a stall/transaction error is triggered on
any TD of the URB, not just the last one.
endpoints will still be restarted when a new URB is queued, this does
not fix the issue with BH URBs completion, but will print a debug message
if a new URB is queued before previous 'tainted' pending URBs are cancelled.
I haven't been able to test the actual codepaths in these patches yet.
Can't easily queue several URBs and somehow trigger stall or transaction
error on early URBs, but would like to get feeback on this solution early.
Thanks
Mathias
Mathias Nyman (2):
xhci: prevent automatic endpoint restart after stall or error
xhci: Ensure URB is given back when endpoint halts on a multi-TD URB
drivers/usb/host/xhci-ring.c | 50 +++++++++++++++++++++++++++++++-----
drivers/usb/host/xhci.c | 7 +++++
drivers/usb/host/xhci.h | 4 ++-
3 files changed, 53 insertions(+), 8 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
2026-03-23 12:25 [RFC PATCH 0/2] fix xhci endpoint restart at EPROTO Mathias Nyman
@ 2026-03-23 12:25 ` Mathias Nyman
2026-03-25 1:52 ` Thinh Nguyen
2026-03-23 12:25 ` [RFC PATCH 2/2] xhci: Ensure URB is given back when endpoint halts on a multi-TD URB Mathias Nyman
1 sibling, 1 reply; 8+ messages in thread
From: Mathias Nyman @ 2026-03-23 12:25 UTC (permalink / raw)
To: linux-usb
Cc: stern, Thinh.Nguyen, michal.pecio, oneukum, niklas.neronin,
Mathias Nyman
Avoid automatically restarting bulk or interrupt transfers after a
URB is given back due to stall or error.
Introduce a 'TD_TAINTED' state for pending TDs queued on a endpoint when
it halted. The actual TD the endpoint halted on is marked TD_HALTED,
and its URB is given back with proper EPROTO or EPIPE error code.
Don't automatically restart an endpoint if the next queued TD after
the TD_HALTED one is marked tainted.
class driver is expected to cancel all those pending URBs before
submitting more URBs, or before clearing halt, but is not forced to.
Always start the endpoint when a new URB is queued, but print a debug
message if there are still tainted URBs left uncancelled.
The same code is used for clearing up cached TDs from xHC in both
the URB stall/error case as when a class driver cancels URBs.
In the cancel case endpoint is restarted after removing the cancelled
URB.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 48 ++++++++++++++++++++++++++++++------
drivers/usb/host/xhci.c | 7 ++++++
drivers/usb/host/xhci.h | 4 ++-
3 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 1cbefee3c4ca..f01f343a7e37 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -981,6 +981,31 @@ static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id,
return ret;
}
+/*
+ * Mark the TD the endpoint halted on as TD_HALTED and add it to the cancelled
+ * td list, ensuring invalidate_cancelled_tds() clears the TD from xHC cache.
+ * Mark the other TDs on that bulk or interrupt endpoint as TD_TAINTED to
+ * prevent the ring from being restarted too early.
+ */
+
+static void xhci_cancel_halted_tds(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ struct xhci_td *td)
+{
+ struct xhci_ring *ring;
+ struct xhci_td *tdi;
+
+ ring = xhci_urb_to_transfer_ring(xhci, td->urb);
+
+ td->cancel_status = TD_HALTED;
+ if (list_empty(&td->cancelled_td_list))
+ list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
+
+ list_for_each_entry(tdi, &ring->td_list, td_list) {
+ if (!tdi->cancel_status && ring->type != TYPE_CTRL)
+ tdi->cancel_status = TD_TAINTED;
+ }
+}
+
static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci,
struct xhci_virt_ep *ep,
struct xhci_td *td,
@@ -999,10 +1024,8 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci,
/* 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;
- 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 (td)
+ xhci_cancel_halted_tds(xhci, ep, td);
}
if (ep->ep_state & EP_HALTED) {
@@ -1079,6 +1102,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
case TD_CLEARED: /* TD is already no-op */
case TD_CLEARING_CACHE: /* set TR deq command already queued */
break;
+ case TD_TAINTED:
case TD_DIRTY: /* TD is cached, clear it */
case TD_HALTED:
case TD_CLEARING_CACHE_DEFERRED:
@@ -1406,6 +1430,14 @@ void xhci_hc_died(struct xhci_hcd *xhci)
usb_hc_died(xhci_to_hcd(xhci));
}
+bool next_td_is_tainted(struct xhci_ring *ring)
+{
+ struct xhci_td *td;
+
+ td = list_first_entry_or_null(&ring->td_list, struct xhci_td, td_list);
+ return td && td->cancel_status == TD_TAINTED;
+}
+
/*
* When we get a completion for a Set Transfer Ring Dequeue Pointer command,
* we need to clear the set deq pending flag in the endpoint ring state, so that
@@ -1543,13 +1575,15 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
__func__);
xhci_invalidate_cancelled_tds(ep);
/* Try to restart the endpoint if all is done */
- ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+ if (!next_td_is_tainted(ep_ring))
+ ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
/* Start giving back any TDs invalidated above */
xhci_giveback_invalidated_tds(ep);
} else {
/* Restart any rings with pending URBs */
- xhci_dbg(ep->xhci, "%s: All TDs cleared, ring doorbell\n", __func__);
- ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+ xhci_dbg(ep->xhci, "%s: All cancelled TDs cleared\n", __func__);
+ if (!next_td_is_tainted(ep_ring))
+ ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
}
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ef6d8662adec..8f417836ae1f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1625,6 +1625,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
unsigned long flags;
int ret = 0;
unsigned int slot_id, ep_index;
+ struct xhci_ring *ring;
unsigned int *ep_state;
struct urb_priv *urb_priv;
int num_tds;
@@ -1661,6 +1662,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
}
slot_id = urb->dev->slot_id;
+ ring = xhci_urb_to_transfer_ring(xhci, urb);
if (!HCD_HW_ACCESSIBLE(hcd)) {
ret = -ESHUTDOWN;
@@ -1694,6 +1696,10 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
goto free_priv;
}
+ ring = xhci_urb_to_transfer_ring(xhci, urb);
+ if (ring && next_td_is_tainted(ring))
+ xhci_dbg(xhci, "WARN, enqueue URB without canceling old tainted URBs\n");
+
switch (usb_endpoint_type(&urb->ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
@@ -3354,6 +3360,7 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
/* Bail out if toggle is already being cleared by a endpoint reset */
spin_lock_irqsave(&xhci->lock, flags);
+
if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) {
ep->ep_state &= ~EP_HARD_CLEAR_TOGGLE;
spin_unlock_irqrestore(&xhci->lock, flags);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 2b0796f6d00e..0be040f87abf 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1292,7 +1292,8 @@ struct xhci_segment {
};
enum xhci_cancelled_td_status {
- TD_DIRTY = 0,
+ TD_TAINTED = 1,
+ TD_DIRTY,
TD_HALTED,
TD_CLEARING_CACHE,
TD_CLEARING_CACHE_DEFERRED,
@@ -1951,6 +1952,7 @@ void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
unsigned int count_trbs(u64 addr, u64 len);
+bool next_td_is_tainted(struct xhci_ring *ring);
int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
int suspend, gfp_t gfp_flags);
void xhci_process_cancelled_tds(struct xhci_virt_ep *ep);
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC PATCH 2/2] xhci: Ensure URB is given back when endpoint halts on a multi-TD URB
2026-03-23 12:25 [RFC PATCH 0/2] fix xhci endpoint restart at EPROTO Mathias Nyman
2026-03-23 12:25 ` [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error Mathias Nyman
@ 2026-03-23 12:25 ` Mathias Nyman
1 sibling, 0 replies; 8+ messages in thread
From: Mathias Nyman @ 2026-03-23 12:25 UTC (permalink / raw)
To: linux-usb
Cc: stern, Thinh.Nguyen, michal.pecio, oneukum, niklas.neronin,
Mathias Nyman
Make sure URB is given back by xhci driver after a stall (EPIPE)
or transaction error (EPROTO) on one of the TDs in the URB.
Most bulk, interrupt and control transfer URBs consist of one TD,
so adding that TD to the cancel list was enough to give back the
entire URB when invalidating and giving back cancelled TDs
Some bulk URBs that need an additional zero length packet consist
of two TDs. Make sure the second TD is added to the cancel list so
that URB is given back when clearing the internal endpoint halt.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index f01f343a7e37..5305ad7be025 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -982,8 +982,9 @@ static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id,
}
/*
- * Mark the TD the endpoint halted on as TD_HALTED and add it to the cancelled
- * td list, ensuring invalidate_cancelled_tds() clears the TD from xHC cache.
+ * Mark the TD the endpoint halted on as TD_HALTED, add all TDs of that URB
+ * to the cancelled td list, ensuring invalidate_cancelled_tds() clears the
+ * TD from xHC cache and URB is given back.
* Mark the other TDs on that bulk or interrupt endpoint as TD_TAINTED to
* prevent the ring from being restarted too early.
*/
@@ -997,10 +998,11 @@ static void xhci_cancel_halted_tds(struct xhci_hcd *xhci, struct xhci_virt_ep *e
ring = xhci_urb_to_transfer_ring(xhci, td->urb);
td->cancel_status = TD_HALTED;
- if (list_empty(&td->cancelled_td_list))
- list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
list_for_each_entry(tdi, &ring->td_list, td_list) {
+ if (tdi->urb == td->urb && list_empty(&tdi->cancelled_td_list))
+ list_add_tail(&tdi->cancelled_td_list, &ep->cancelled_td_list);
+
if (!tdi->cancel_status && ring->type != TYPE_CTRL)
tdi->cancel_status = TD_TAINTED;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
2026-03-23 12:25 ` [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error Mathias Nyman
@ 2026-03-25 1:52 ` Thinh Nguyen
2026-03-25 9:38 ` Mathias Nyman
0 siblings, 1 reply; 8+ messages in thread
From: Thinh Nguyen @ 2026-03-25 1:52 UTC (permalink / raw)
To: Mathias Nyman
Cc: linux-usb@vger.kernel.org, stern@rowland.harvard.edu,
Thinh Nguyen, michal.pecio@gmail.com, oneukum@suse.com,
niklas.neronin@linux.intel.com
On Mon, Mar 23, 2026, Mathias Nyman wrote:
> Avoid automatically restarting bulk or interrupt transfers after a
> URB is given back due to stall or error.
>
> Introduce a 'TD_TAINTED' state for pending TDs queued on a endpoint when
> it halted. The actual TD the endpoint halted on is marked TD_HALTED,
> and its URB is given back with proper EPROTO or EPIPE error code.
>
> Don't automatically restart an endpoint if the next queued TD after
> the TD_HALTED one is marked tainted.
Sounds good for -EPROTO, but will a clear-halt ring the corresponding
the endpoint's doorbell for STALL endpoint?
BR,
Thinh
>
> class driver is expected to cancel all those pending URBs before
> submitting more URBs, or before clearing halt, but is not forced to.
> Always start the endpoint when a new URB is queued, but print a debug
> message if there are still tainted URBs left uncancelled.
>
> The same code is used for clearing up cached TDs from xHC in both
> the URB stall/error case as when a class driver cancels URBs.
> In the cancel case endpoint is restarted after removing the cancelled
> URB.
>
> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
> ---
> drivers/usb/host/xhci-ring.c | 48 ++++++++++++++++++++++++++++++------
> drivers/usb/host/xhci.c | 7 ++++++
> drivers/usb/host/xhci.h | 4 ++-
> 3 files changed, 51 insertions(+), 8 deletions(-)
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
2026-03-25 1:52 ` Thinh Nguyen
@ 2026-03-25 9:38 ` Mathias Nyman
2026-03-26 1:19 ` Thinh Nguyen
0 siblings, 1 reply; 8+ messages in thread
From: Mathias Nyman @ 2026-03-25 9:38 UTC (permalink / raw)
To: Thinh Nguyen
Cc: linux-usb@vger.kernel.org, stern@rowland.harvard.edu,
michal.pecio@gmail.com, oneukum@suse.com,
niklas.neronin@linux.intel.com
On 3/25/26 03:52, Thinh Nguyen wrote:
> On Mon, Mar 23, 2026, Mathias Nyman wrote:
>> Avoid automatically restarting bulk or interrupt transfers after a
>> URB is given back due to stall or error.
>>
>> Introduce a 'TD_TAINTED' state for pending TDs queued on a endpoint when
>> it halted. The actual TD the endpoint halted on is marked TD_HALTED,
>> and its URB is given back with proper EPROTO or EPIPE error code.
>>
>> Don't automatically restart an endpoint if the next queued TD after
>> the TD_HALTED one is marked tainted.
>
> Sounds good for -EPROTO, but will a clear-halt ring the corresponding
> the endpoint's doorbell for STALL endpoint?
>
With this change xhci would not restart the stalled endpoint after a clear-halt
request. The first usb_enqueue() call after clear-halt would start it.
Could make sense to restart the endpoint after a clear-halt, and just add a small
debug message if the next queued URB is marked 'tainted'.
Thanks for the feedback
Mathias
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
2026-03-25 9:38 ` Mathias Nyman
@ 2026-03-26 1:19 ` Thinh Nguyen
2026-03-26 11:25 ` Mathias Nyman
0 siblings, 1 reply; 8+ messages in thread
From: Thinh Nguyen @ 2026-03-26 1:19 UTC (permalink / raw)
To: Mathias Nyman
Cc: Thinh Nguyen, linux-usb@vger.kernel.org,
stern@rowland.harvard.edu, michal.pecio@gmail.com,
oneukum@suse.com, niklas.neronin@linux.intel.com
On Wed, Mar 25, 2026, Mathias Nyman wrote:
> On 3/25/26 03:52, Thinh Nguyen wrote:
> > On Mon, Mar 23, 2026, Mathias Nyman wrote:
> > > Avoid automatically restarting bulk or interrupt transfers after a
> > > URB is given back due to stall or error.
> > >
> > > Introduce a 'TD_TAINTED' state for pending TDs queued on a endpoint when
> > > it halted. The actual TD the endpoint halted on is marked TD_HALTED,
> > > and its URB is given back with proper EPROTO or EPIPE error code.
> > >
> > > Don't automatically restart an endpoint if the next queued TD after
> > > the TD_HALTED one is marked tainted.
> >
> > Sounds good for -EPROTO, but will a clear-halt ring the corresponding
> > the endpoint's doorbell for STALL endpoint?
> >
>
> With this change xhci would not restart the stalled endpoint after a clear-halt
> request. The first usb_enqueue() call after clear-halt would start it.
>
> Could make sense to restart the endpoint after a clear-halt, and just add a small
> debug message if the next queued URB is marked 'tainted'.
>
The -EPROTO should be handled differently than -EPIPE. A STALL endpoint
is part of a normal usb flow. Should the class driver submit a new URB
while the endpoint is STALL, we would always expect a STALL error
response after the endpoint is restarted. That's not the case with
-EPROTO where the data may be corrupted and/or the host and device are
out of sync. We should not continue until the class driver do some
recovery. IMHO, we can keep the handling of -EPIPE how it was before.
Let the xHC tell whether the STALL error still persists instead of
managing it by the xhci driver.
Thanks,
Thinh
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
2026-03-26 1:19 ` Thinh Nguyen
@ 2026-03-26 11:25 ` Mathias Nyman
2026-03-26 23:24 ` Thinh Nguyen
0 siblings, 1 reply; 8+ messages in thread
From: Mathias Nyman @ 2026-03-26 11:25 UTC (permalink / raw)
To: Thinh Nguyen
Cc: linux-usb@vger.kernel.org, stern@rowland.harvard.edu,
michal.pecio@gmail.com, oneukum@suse.com,
niklas.neronin@linux.intel.com
On 3/26/26 03:19, Thinh Nguyen wrote:
> On Wed, Mar 25, 2026, Mathias Nyman wrote:
>> On 3/25/26 03:52, Thinh Nguyen wrote:
>>> On Mon, Mar 23, 2026, Mathias Nyman wrote:
>>>> Avoid automatically restarting bulk or interrupt transfers after a
>>>> URB is given back due to stall or error.
>>>>
>>>> Introduce a 'TD_TAINTED' state for pending TDs queued on a endpoint when
>>>> it halted. The actual TD the endpoint halted on is marked TD_HALTED,
>>>> and its URB is given back with proper EPROTO or EPIPE error code.
>>>>
>>>> Don't automatically restart an endpoint if the next queued TD after
>>>> the TD_HALTED one is marked tainted.
>>>
>>> Sounds good for -EPROTO, but will a clear-halt ring the corresponding
>>> the endpoint's doorbell for STALL endpoint?
>>>
>>
>> With this change xhci would not restart the stalled endpoint after a clear-halt
>> request. The first usb_enqueue() call after clear-halt would start it.
>>
>> Could make sense to restart the endpoint after a clear-halt, and just add a small
>> debug message if the next queued URB is marked 'tainted'.
>>
>
> The -EPROTO should be handled differently than -EPIPE. A STALL endpoint
> is part of a normal usb flow. Should the class driver submit a new URB
> while the endpoint is STALL, we would always expect a STALL error
> response after the endpoint is restarted. That's not the case with
> -EPROTO where the data may be corrupted and/or the host and device are
> out of sync. We should not continue until the class driver do some
> recovery. IMHO, we can keep the handling of -EPIPE how it was before.
> Let the xHC tell whether the STALL error still persists instead of
> managing it by the xhci driver.
>
I agree that that we should restart the endpoint if class/core enqueues a new
URB _after_ xhci gave back an URB with EPIPE after endpoint STALL.
But I don't think we should restart the ring to continue processing URBs that
were queued before the endpoint stalled. This would prevent the class/core
from even attempting to retire the pending URBs, something USB2.0 spec,
'5.8.5 Bulk Transfer Data Sequences' requires:
"If a halt condition is detected on a bulk pipe due to transmission errors or
a STALL handshake being returned from the endpoint, all pending IRPs are
retired. Removal of the halt condition is achieved via software intervention
through a separate control pipe."
Thanks
Mathias
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
2026-03-26 11:25 ` Mathias Nyman
@ 2026-03-26 23:24 ` Thinh Nguyen
0 siblings, 0 replies; 8+ messages in thread
From: Thinh Nguyen @ 2026-03-26 23:24 UTC (permalink / raw)
To: Mathias Nyman
Cc: Thinh Nguyen, linux-usb@vger.kernel.org,
stern@rowland.harvard.edu, michal.pecio@gmail.com,
oneukum@suse.com, niklas.neronin@linux.intel.com
On Thu, Mar 26, 2026, Mathias Nyman wrote:
> On 3/26/26 03:19, Thinh Nguyen wrote:
> > On Wed, Mar 25, 2026, Mathias Nyman wrote:
> > > On 3/25/26 03:52, Thinh Nguyen wrote:
> > > > On Mon, Mar 23, 2026, Mathias Nyman wrote:
> > > > > Avoid automatically restarting bulk or interrupt transfers after a
> > > > > URB is given back due to stall or error.
> > > > >
> > > > > Introduce a 'TD_TAINTED' state for pending TDs queued on a endpoint when
> > > > > it halted. The actual TD the endpoint halted on is marked TD_HALTED,
> > > > > and its URB is given back with proper EPROTO or EPIPE error code.
> > > > >
> > > > > Don't automatically restart an endpoint if the next queued TD after
> > > > > the TD_HALTED one is marked tainted.
> > > >
> > > > Sounds good for -EPROTO, but will a clear-halt ring the corresponding
> > > > the endpoint's doorbell for STALL endpoint?
> > > >
> > >
> > > With this change xhci would not restart the stalled endpoint after a clear-halt
> > > request. The first usb_enqueue() call after clear-halt would start it.
> > >
> > > Could make sense to restart the endpoint after a clear-halt, and just add a small
> > > debug message if the next queued URB is marked 'tainted'.
> > >
> >
> > The -EPROTO should be handled differently than -EPIPE. A STALL endpoint
> > is part of a normal usb flow. Should the class driver submit a new URB
> > while the endpoint is STALL, we would always expect a STALL error
> > response after the endpoint is restarted. That's not the case with
> > -EPROTO where the data may be corrupted and/or the host and device are
> > out of sync. We should not continue until the class driver do some
> > recovery. IMHO, we can keep the handling of -EPIPE how it was before.
> > Let the xHC tell whether the STALL error still persists instead of
> > managing it by the xhci driver.
> >
> I agree that that we should restart the endpoint if class/core enqueues a new
> URB _after_ xhci gave back an URB with EPIPE after endpoint STALL.
>
> But I don't think we should restart the ring to continue processing URBs that
> were queued before the endpoint stalled. This would prevent the class/core
> from even attempting to retire the pending URBs, something USB2.0 spec,
> '5.8.5 Bulk Transfer Data Sequences' requires:
>
> "If a halt condition is detected on a bulk pipe due to transmission errors or
> a STALL handshake being returned from the endpoint, all pending IRPs are
> retired. Removal of the halt condition is achieved via software intervention
> through a separate control pipe."
>
Fair point. Then the core will need to track the endpoint's STALL state
and parse the clear-halt request to know which endpoint and when to
clear the STALL before it can accept new URB. So the first usb_enqueue()
call after clear-halt can start the endpoint again. The xhci will also
need to have access to this state.
Currently you have the xhci driver to "retire" the halted URBs. However,
you also noted that class/core may attempt to retire the pending URBs.
Who's expected to handle the retirement here?
On a separate note, will you plan to implement the clear-halt for EPROTO
in xhci?
Thanks!
Thinh
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-03-26 23:24 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-23 12:25 [RFC PATCH 0/2] fix xhci endpoint restart at EPROTO Mathias Nyman
2026-03-23 12:25 ` [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error Mathias Nyman
2026-03-25 1:52 ` Thinh Nguyen
2026-03-25 9:38 ` Mathias Nyman
2026-03-26 1:19 ` Thinh Nguyen
2026-03-26 11:25 ` Mathias Nyman
2026-03-26 23:24 ` Thinh Nguyen
2026-03-23 12:25 ` [RFC PATCH 2/2] xhci: Ensure URB is given back when endpoint halts on a multi-TD URB Mathias Nyman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox