irq is disabled in xhci_quiesce(called by xhci_halt, with bit:2 cleared in USBCMD register), but xhci_run(called by usb_add_hcd) re-enable it. It's possible that you will receive thousands of interrupt requests after initialization for 2.0 roothub. And you will get a lot of warning like, "xHCI dying, ignoring interrupt. Shouldn't IRQs be disabled?". This amount of interrupt requests will cause the entire system to freeze. This problem was first found on a device with ASM2142 host controller on it. Signed-off-by: Hongyu Xie <xiehongyu1@xxxxxxxxxx> --- drivers/usb/host/xhci.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9ac56e9ffc64..8e4b86e84486 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -611,6 +611,7 @@ static int xhci_init(struct usb_hcd *hcd) static int xhci_run_finished(struct xhci_hcd *xhci) { + u32 temp; if (xhci_start(xhci)) { xhci_halt(xhci); return -ENODEV; @@ -620,6 +621,19 @@ static int xhci_run_finished(struct xhci_hcd *xhci) if (xhci->quirks & XHCI_NEC_HOST) xhci_ring_cmd_db(xhci); + /* Set the HCD state before we enable the irqs */ + temp = readl(&xhci->op_regs->command); + temp |= (CMD_EIE); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Enable interrupts, cmd = 0x%x.", temp); + writel(temp, &xhci->op_regs->command); + + temp = readl(&xhci->ir_set->irq_pending); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Enabling event ring interrupter %p by writing 0x%x + to irq_pending", xhci->ir_set, + (unsigned int) ER_IRQ_ENABLE(temp)); + writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending); return 0; } @@ -668,19 +682,6 @@ int xhci_run(struct usb_hcd *hcd) temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK; writel(temp, &xhci->ir_set->irq_control); - /* Set the HCD state before we enable the irqs */ - temp = readl(&xhci->op_regs->command); - temp |= (CMD_EIE); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Enable interrupts, cmd = 0x%x.", temp); - writel(temp, &xhci->op_regs->command); - - temp = readl(&xhci->ir_set->irq_pending); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Enabling event ring interrupter %p by writing 0x%x to irq_pending", - xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp)); - writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending); - if (xhci->quirks & XHCI_NEC_HOST) { struct xhci_command *command; -- 2.25.1