Skip to content

Commit 5c00785

Browse files
matnymanSasha Levin
authored andcommitted
xhci: move event processing for one interrupter to a separate function
[ Upstream commit 84ac5e4 ] Split the main XHCI interrupt handler into a different API, so that other potential interrupters can utilize similar event ring handling. A scenario would be if a secondary interrupter required to skip pending events in the event ring, which would warrant a similar set of operations. Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com> Link: https://lore.kernel.org/r/20240217001017.29969-7-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Stable-dep-of: 5bfc311 ("usb: xhci: correct return value in case of STS_HCE") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 66c826a commit 5c00785

File tree

1 file changed

+42
-45
lines changed

1 file changed

+42
-45
lines changed

drivers/usb/host/xhci-ring.c

Lines changed: 42 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3075,6 +3075,46 @@ static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci,
30753075
}
30763076
}
30773077

3078+
static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
3079+
{
3080+
int event_loop = 0;
3081+
u64 temp;
3082+
3083+
xhci_clear_interrupt_pending(xhci, ir);
3084+
3085+
if (xhci->xhc_state & XHCI_STATE_DYING ||
3086+
xhci->xhc_state & XHCI_STATE_HALTED) {
3087+
xhci_dbg(xhci, "xHCI dying, ignoring interrupt. Shouldn't IRQs be disabled?\n");
3088+
3089+
/* Clear the event handler busy flag (RW1C) */
3090+
temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
3091+
xhci_write_64(xhci, temp | ERST_EHB, &ir->ir_set->erst_dequeue);
3092+
return -ENODEV;
3093+
}
3094+
3095+
while (xhci_handle_event(xhci, ir) > 0) {
3096+
/*
3097+
* If half a segment of events have been handled in one go then
3098+
* update ERDP, and force isoc trbs to interrupt more often
3099+
*/
3100+
if (event_loop++ > TRBS_PER_SEGMENT / 2) {
3101+
xhci_update_erst_dequeue(xhci, ir, false);
3102+
3103+
if (ir->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
3104+
ir->isoc_bei_interval = ir->isoc_bei_interval / 2;
3105+
3106+
event_loop = 0;
3107+
}
3108+
3109+
/* Update SW event ring dequeue pointer */
3110+
inc_deq(xhci, ir->event_ring);
3111+
}
3112+
3113+
xhci_update_erst_dequeue(xhci, ir, true);
3114+
3115+
return 0;
3116+
}
3117+
30783118
/*
30793119
* xHCI spec says we can get an interrupt, and if the HC has an error condition,
30803120
* we might get bad data out of the event ring. Section 4.10.2.7 has a list of
@@ -3083,11 +3123,8 @@ static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci,
30833123
irqreturn_t xhci_irq(struct usb_hcd *hcd)
30843124
{
30853125
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
3086-
struct xhci_interrupter *ir;
30873126
irqreturn_t ret = IRQ_NONE;
3088-
u64 temp_64;
30893127
u32 status;
3090-
int event_loop = 0;
30913128

30923129
spin_lock(&xhci->lock);
30933130
/* Check if the xHC generated the interrupt, or the irq is shared */
@@ -3120,50 +3157,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
31203157
*/
31213158
status |= STS_EINT;
31223159
writel(status, &xhci->op_regs->status);
3123-
3124-
/* This is the handler of the primary interrupter */
3125-
ir = xhci->interrupters[0];
3126-
3127-
xhci_clear_interrupt_pending(xhci, ir);
3128-
3129-
if (xhci->xhc_state & XHCI_STATE_DYING ||
3130-
xhci->xhc_state & XHCI_STATE_HALTED) {
3131-
xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
3132-
"Shouldn't IRQs be disabled?\n");
3133-
/* Clear the event handler busy flag (RW1C);
3134-
* the event ring should be empty.
3135-
*/
3136-
temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
3137-
xhci_write_64(xhci, temp_64 | ERST_EHB,
3138-
&ir->ir_set->erst_dequeue);
3139-
ret = IRQ_HANDLED;
3140-
goto out;
3141-
}
3142-
3143-
/* FIXME this should be a delayed service routine
3144-
* that clears the EHB.
3145-
*/
3146-
while (xhci_handle_event(xhci, ir) > 0) {
3147-
/*
3148-
* If half a segment of events have been handled in one go then
3149-
* update ERDP, and force isoc trbs to interrupt more often
3150-
*/
3151-
if (event_loop++ > TRBS_PER_SEGMENT / 2) {
3152-
xhci_update_erst_dequeue(xhci, ir, false);
3153-
3154-
if (ir->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
3155-
ir->isoc_bei_interval = ir->isoc_bei_interval / 2;
3156-
3157-
event_loop = 0;
3158-
}
3159-
3160-
/* Update SW event ring dequeue pointer */
3161-
inc_deq(xhci, ir->event_ring);
3162-
}
3163-
3164-
xhci_update_erst_dequeue(xhci, ir, true);
31653160
ret = IRQ_HANDLED;
31663161

3162+
/* This is the handler of the primary interrupter */
3163+
xhci_handle_events(xhci, xhci->interrupters[0]);
31673164
out:
31683165
spin_unlock(&xhci->lock);
31693166

0 commit comments

Comments
 (0)