bcm53xx: backport XHCI patch modifying xhci_run_finished()
[openwrt/staging/jow.git] / target / linux / bcm53xx / patches-5.15 / 081-xhci-Keep-interrupt-disabled-in-initialization-until.patch
1 From a808925075fb750804a60ff0710614466c396db4 Mon Sep 17 00:00:00 2001
2 From: Hongyu Xie <xy521521@gmail.com>
3 Date: Thu, 23 Jun 2022 14:19:42 +0300
4 Subject: [PATCH] xhci: Keep interrupt disabled in initialization until host is
5 running.
6
7 irq is disabled in xhci_quiesce(called by xhci_halt, with bit:2 cleared
8 in USBCMD register), but xhci_run(called by usb_add_hcd) re-enable it.
9 It's possible that you will receive thousands of interrupt requests
10 after initialization for 2.0 roothub. And you will get a lot of
11 warning like, "xHCI dying, ignoring interrupt. Shouldn't IRQs be
12 disabled?". This amount of interrupt requests will cause the entire
13 system to freeze.
14 This problem was first found on a device with ASM2142 host controller
15 on it.
16
17 [tidy up old code while moving it, reword header -Mathias]
18
19 Cc: stable@kernel.org
20 Signed-off-by: Hongyu Xie <xiehongyu1@kylinos.cn>
21 Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
22 Link: https://lore.kernel.org/r/20220623111945.1557702-2-mathias.nyman@linux.intel.com
23 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
24 ---
25 drivers/usb/host/xhci.c | 35 ++++++++++++++++++++++-------------
26 1 file changed, 22 insertions(+), 13 deletions(-)
27
28 --- a/drivers/usb/host/xhci.c
29 +++ b/drivers/usb/host/xhci.c
30 @@ -611,8 +611,27 @@ static int xhci_init(struct usb_hcd *hcd
31
32 static int xhci_run_finished(struct xhci_hcd *xhci)
33 {
34 + unsigned long flags;
35 + u32 temp;
36 +
37 + /*
38 + * Enable interrupts before starting the host (xhci 4.2 and 5.5.2).
39 + * Protect the short window before host is running with a lock
40 + */
41 + spin_lock_irqsave(&xhci->lock, flags);
42 +
43 + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable interrupts");
44 + temp = readl(&xhci->op_regs->command);
45 + temp |= (CMD_EIE);
46 + writel(temp, &xhci->op_regs->command);
47 +
48 + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable primary interrupter");
49 + temp = readl(&xhci->ir_set->irq_pending);
50 + writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
51 +
52 if (xhci_start(xhci)) {
53 xhci_halt(xhci);
54 + spin_unlock_irqrestore(&xhci->lock, flags);
55 return -ENODEV;
56 }
57 xhci->shared_hcd->state = HC_STATE_RUNNING;
58 @@ -623,6 +642,9 @@ static int xhci_run_finished(struct xhci
59
60 xhci_dbg_trace(xhci, trace_xhci_dbg_init,
61 "Finished xhci_run for USB3 roothub");
62 +
63 + spin_unlock_irqrestore(&xhci->lock, flags);
64 +
65 return 0;
66 }
67
68 @@ -671,19 +693,6 @@ int xhci_run(struct usb_hcd *hcd)
69 temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
70 writel(temp, &xhci->ir_set->irq_control);
71
72 - /* Set the HCD state before we enable the irqs */
73 - temp = readl(&xhci->op_regs->command);
74 - temp |= (CMD_EIE);
75 - xhci_dbg_trace(xhci, trace_xhci_dbg_init,
76 - "// Enable interrupts, cmd = 0x%x.", temp);
77 - writel(temp, &xhci->op_regs->command);
78 -
79 - temp = readl(&xhci->ir_set->irq_pending);
80 - xhci_dbg_trace(xhci, trace_xhci_dbg_init,
81 - "// Enabling event ring interrupter %p by writing 0x%x to irq_pending",
82 - xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
83 - writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
84 -
85 if (xhci->quirks & XHCI_NEC_HOST) {
86 struct xhci_command *command;
87