Commit edc47759 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman

xhci: Decouple handling an event from checking for unhandled events

Some sequences, will require traversing through the entire event ring
without handling the event TRB.  This is ideal for when secondary
interrupters that are utilized by external entities need to clean up the
interrupter's event rings during halting of the XHCI HCD.
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarWesley Cheng <quic_wcheng@quicinc.com>
Link: https://lore.kernel.org/r/20240217001017.29969-10-quic_wcheng@quicinc.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 84008be8
...@@ -2962,25 +2962,18 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2962,25 +2962,18 @@ static int handle_tx_event(struct xhci_hcd *xhci,
} }
/* /*
* This function handles all OS-owned events on the event ring. It may drop * This function handles one OS-owned event on the event ring. It may drop
* xhci->lock between event processing (e.g. to pass up port status changes). * xhci->lock between event processing (e.g. to pass up port status changes).
* Returns >0 for "possibly more events to process" (caller should call again),
* otherwise 0 if done. In future, <0 returns should indicate error code.
*/ */
static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir) static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
union xhci_trb *event)
{ {
union xhci_trb *event;
u32 trb_type; u32 trb_type;
event = ir->event_ring->dequeue;
if (!unhandled_event_trb(ir->event_ring))
return 0;
trace_xhci_handle_event(ir->event_ring, &event->generic); trace_xhci_handle_event(ir->event_ring, &event->generic);
/* /*
* Barrier between reading the TRB_CYCLE (valid) flag above and any * Barrier between reading the TRB_CYCLE (valid) flag before, and any
* speculative reads of the event's flags/data below. * speculative reads of the event's flags/data below.
*/ */
rmb(); rmb();
...@@ -3010,15 +3003,11 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir) ...@@ -3010,15 +3003,11 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
* to make sure a watchdog timer didn't mark the host as non-responsive. * to make sure a watchdog timer didn't mark the host as non-responsive.
*/ */
if (xhci->xhc_state & XHCI_STATE_DYING) { if (xhci->xhc_state & XHCI_STATE_DYING) {
xhci_dbg(xhci, "xHCI host dying, returning from " xhci_dbg(xhci, "xHCI host dying, returning from event handler.\n");
"event handler.\n"); return -ENODEV;
return 0;
} }
/* Are there more items on the event ring? Caller will call us again to return 0;
* check.
*/
return 1;
} }
/* /*
...@@ -3068,9 +3057,14 @@ static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci, ...@@ -3068,9 +3057,14 @@ static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci,
} }
} }
/*
* Handle all OS-owned events on an interrupter event ring. It may drop
* and reaquire xhci->lock between event processing.
*/
static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir) static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
{ {
int event_loop = 0; int event_loop = 0;
int err;
u64 temp; u64 temp;
xhci_clear_interrupt_pending(xhci, ir); xhci_clear_interrupt_pending(xhci, ir);
...@@ -3091,7 +3085,10 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir ...@@ -3091,7 +3085,10 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
return -ENODEV; return -ENODEV;
} }
while (xhci_handle_event(xhci, ir) > 0) { /* Process all OS owned event TRBs on this event ring */
while (unhandled_event_trb(ir->event_ring)) {
err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue);
/* /*
* If half a segment of events have been handled in one go then * If half a segment of events have been handled in one go then
* update ERDP, and force isoc trbs to interrupt more often * update ERDP, and force isoc trbs to interrupt more often
...@@ -3107,6 +3104,9 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir ...@@ -3107,6 +3104,9 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
/* Update SW event ring dequeue pointer */ /* Update SW event ring dequeue pointer */
inc_deq(xhci, ir->event_ring); inc_deq(xhci, ir->event_ring);
if (err)
break;
} }
xhci_update_erst_dequeue(xhci, ir, true); xhci_update_erst_dequeue(xhci, ir, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment