Skip to content

Commit b223af8

Browse files
author
Desnes Nunes
committed
usb: host: xhci-mem: Cleanup pending secondary event ring events
JIRA: https://issues.redhat.com/browse/RHEL-116016 Conflicts: * Commit bea5892 ("xhci: Limit time spent with xHC interrupts disabled during bus resume") causes a conflicts here by making xhci_enable_interrupter() and xhci_disable_interrupter() public on drivers/usb/host/xhci.h commit 5beb4a5 Author: Wesley Cheng <quic_wcheng@quicinc.com> Date: Wed, 9 Apr 2025 12:47:35 -0700 As part of xHCI bus suspend, the xHCI is halted. However, if there are pending events in the secondary event ring, it is observed that the xHCI controller stops responding to further commands upon host or device initiated bus resume. Iterate through all pending events and update the dequeue pointer to the beginning of the event ring. Tested-by: Puma Hsu <pumahsu@google.com> Tested-by: Daehwan Jung <dh10.jung@samsung.com> Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com> Acked-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20250409194804.3773260-3-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Desnes Nunes <desnesn@redhat.com>
1 parent f6a3bf9 commit b223af8

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1805,7 +1805,7 @@ xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
18051805
tmp &= ERST_SIZE_MASK;
18061806
writel(tmp, &ir->ir_set->erst_size);
18071807

1808-
xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue);
1808+
xhci_update_erst_dequeue(xhci, ir, true);
18091809
}
18101810
}
18111811

@@ -1848,6 +1848,11 @@ void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrup
18481848
return;
18491849
}
18501850

1851+
/*
1852+
* Cleanup secondary interrupter to ensure there are no pending events.
1853+
* This also updates event ring dequeue pointer back to the start.
1854+
*/
1855+
xhci_skip_sec_intr_events(xhci, ir->event_ring, ir);
18511856
intr_num = ir->intr_num;
18521857

18531858
xhci_remove_interrupter(xhci, ir);

drivers/usb/host/xhci-ring.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3050,9 +3050,9 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter
30503050
* - When all events have finished
30513051
* - To avoid "Event Ring Full Error" condition
30523052
*/
3053-
static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
3054-
struct xhci_interrupter *ir,
3055-
bool clear_ehb)
3053+
void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
3054+
struct xhci_interrupter *ir,
3055+
bool clear_ehb)
30563056
{
30573057
u64 temp_64;
30583058
dma_addr_t deq;
@@ -3095,10 +3095,11 @@ static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir)
30953095
* Handle all OS-owned events on an interrupter event ring. It may drop
30963096
* and reaquire xhci->lock between event processing.
30973097
*/
3098-
static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
3098+
static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
3099+
bool skip_events)
30993100
{
31003101
int event_loop = 0;
3101-
int err;
3102+
int err = 0;
31023103
u64 temp;
31033104

31043105
xhci_clear_interrupt_pending(ir);
@@ -3121,7 +3122,8 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
31213122

31223123
/* Process all OS owned event TRBs on this event ring */
31233124
while (unhandled_event_trb(ir->event_ring)) {
3124-
err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue);
3125+
if (!skip_events)
3126+
err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue);
31253127

31263128
/*
31273129
* If half a segment of events have been handled in one go then
@@ -3148,6 +3150,37 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
31483150
return 0;
31493151
}
31503152

3153+
/*
3154+
* Move the event ring dequeue pointer to skip events kept in the secondary
3155+
* event ring. This is used to ensure that pending events in the ring are
3156+
* acknowledged, so the xHCI HCD can properly enter suspend/resume. The
3157+
* secondary ring is typically maintained by an external component.
3158+
*/
3159+
void xhci_skip_sec_intr_events(struct xhci_hcd *xhci,
3160+
struct xhci_ring *ring, struct xhci_interrupter *ir)
3161+
{
3162+
union xhci_trb *current_trb;
3163+
u64 erdp_reg;
3164+
dma_addr_t deq;
3165+
3166+
/* disable irq, ack pending interrupt and ack all pending events */
3167+
xhci_disable_interrupter(ir);
3168+
3169+
/* last acked event trb is in erdp reg */
3170+
erdp_reg = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
3171+
deq = (dma_addr_t)(erdp_reg & ERST_PTR_MASK);
3172+
if (!deq) {
3173+
xhci_err(xhci, "event ring handling not required\n");
3174+
return;
3175+
}
3176+
3177+
current_trb = ir->event_ring->dequeue;
3178+
/* read cycle state of the last acked trb to find out CCS */
3179+
ring->cycle_state = le32_to_cpu(current_trb->event_cmd.flags) & TRB_CYCLE;
3180+
3181+
xhci_handle_events(xhci, ir, true);
3182+
}
3183+
31513184
/*
31523185
* xHCI spec says we can get an interrupt, and if the HC has an error condition,
31533186
* we might get bad data out of the event ring. Section 4.10.2.7 has a list of
@@ -3192,7 +3225,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
31923225
writel(status, &xhci->op_regs->status);
31933226

31943227
/* This is the handler of the primary interrupter */
3195-
xhci_handle_events(xhci, xhci->interrupters[0]);
3228+
xhci_handle_events(xhci, xhci->interrupters[0], false);
31963229
out:
31973230
spin_unlock(&xhci->lock);
31983231

drivers/usb/host/xhci.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,9 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
18551855
u32 imod_interval);
18561856
void xhci_remove_secondary_interrupter(struct usb_hcd
18571857
*hcd, struct xhci_interrupter *ir);
1858+
void xhci_skip_sec_intr_events(struct xhci_hcd *xhci,
1859+
struct xhci_ring *ring,
1860+
struct xhci_interrupter *ir);
18581861

18591862
/* xHCI host controller glue */
18601863
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
@@ -1940,6 +1943,9 @@ unsigned int count_trbs(u64 addr, u64 len);
19401943
int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
19411944
int suspend, gfp_t gfp_flags);
19421945
void xhci_process_cancelled_tds(struct xhci_virt_ep *ep);
1946+
void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
1947+
struct xhci_interrupter *ir,
1948+
bool clear_ehb);
19431949

19441950
/* xHCI roothub code */
19451951
void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,

0 commit comments

Comments
 (0)