|
| 1 | +From d620b6d96be120677cb4072dc253368ca8e96ebd Mon Sep 17 00:00:00 2001 |
| 2 | +From: Rob Kleffner <rob@oscium.com> |
| 3 | +Date: Wed, 22 Jul 2026 19:35:39 -0600 |
| 4 | +Subject: [PATCH] usb: host: max3421-hcd: fix SMP race that leaves the IRQ |
| 5 | + disabled forever |
| 6 | + |
| 7 | +The hard interrupt handler and the SPI thread hand ownership of the |
| 8 | +interrupt line back and forth through the ENABLE_IRQ bit in |
| 9 | +max3421_hcd->todo. The handler does |
| 10 | + |
| 11 | + if (!test_and_set_bit(ENABLE_IRQ, &max3421_hcd->todo)) |
| 12 | + disable_irq_nosync(spi->irq); |
| 13 | + |
| 14 | +and the SPI thread's idle path does |
| 15 | + |
| 16 | + if (test_and_clear_bit(ENABLE_IRQ, &max3421_hcd->todo)) |
| 17 | + enable_irq(spi->irq); |
| 18 | + |
| 19 | +Each bit operation is atomic, but nothing makes the {bit operation, |
| 20 | +IRQ-depth operation} pair atomic on either side. On an SMP system the |
| 21 | +thread's test_and_clear_bit() can land between the handler's |
| 22 | +test_and_set_bit() and its disable_irq_nosync(). The thread then calls |
| 23 | +enable_irq() while the line is still enabled: |
| 24 | + |
| 25 | + WARNING: CPU: 1 PID: 245 at kernel/irq/manage.c:790 __enable_irq+0x54/0x90 |
| 26 | + Unbalanced enable for IRQ 37 |
| 27 | + Call trace: |
| 28 | + __enable_irq+0x54/0x90 |
| 29 | + enable_irq+0x58/0xb8 |
| 30 | + max3421_spi_thread+0x850/0xbd0 |
| 31 | + |
| 32 | +and the handler's disable_irq_nosync() lands afterwards, leaving the |
| 33 | +line masked at depth 1 with ENABLE_IRQ clear. From then on the thread's |
| 34 | +idle path never sees the bit set, so nothing ever re-enables the IRQ: |
| 35 | +the chip's interrupt is dead, in-flight transfers never complete, and |
| 36 | +the attached device eventually drops off the bus after a storm of |
| 37 | +-ETIMEDOUT resets. Only unbinding and rebinding the driver (or a |
| 38 | +reboot) recovers. |
| 39 | + |
| 40 | +Observed in the field on a quad-core Raspberry Pi CM4 driving a |
| 41 | +full-speed spectrum analyzer: the chip's ~1 kHz FRAME interrupt cadence |
| 42 | +exercises the race window about a thousand times per second, and |
| 43 | +continuous bulk-IN streaming kills the bus within minutes to hours. |
| 44 | + |
| 45 | +Serialize both pairs with a dedicated spinlock. The handler runs in |
| 46 | +hard-IRQ context with local interrupts off, so a plain spin_lock() is |
| 47 | +sufficient there; the thread side takes the lock with |
| 48 | +spin_lock_irqsave() so the handler cannot preempt it on the same CPU |
| 49 | +inside the critical section and spin on the lock forever. The lock is |
| 50 | +initialized in probe before the SPI thread starts, because the thread's |
| 51 | +idle path takes it from its very first iteration. |
| 52 | + |
| 53 | +Also move the handler's wake_up_process() after the locked section. A |
| 54 | +wakeup issued before ENABLE_IRQ is published can be spent on the thread |
| 55 | +passing its idle check while the bit is still clear and then going to |
| 56 | +sleep; the freshly-set bit is then not noticed until some unrelated |
| 57 | +wakeup (a URB submission or hub activity) happens along, stalling the |
| 58 | +stream in the meantime. |
| 59 | + |
| 60 | +Fixes: 2d53139f3162 ("Add support for using a MAX3421E chip as a host driver.") |
| 61 | +Cc: stable@vger.kernel.org |
| 62 | +--- |
| 63 | + drivers/usb/host/max3421-hcd.c | 39 ++++++++++++++++++++++++++++++++-- |
| 64 | + 1 file changed, 37 insertions(+), 2 deletions(-) |
| 65 | + |
| 66 | +diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c |
| 67 | +index 52b0fcc..3d3333d 100644 |
| 68 | +--- a/drivers/usb/host/max3421-hcd.c |
| 69 | ++++ b/drivers/usb/host/max3421-hcd.c |
| 70 | +@@ -123,6 +123,17 @@ struct max3421_dma_buf { |
| 71 | + struct max3421_hcd { |
| 72 | + spinlock_t lock; |
| 73 | + |
| 74 | ++ /* |
| 75 | ++ * Serializes the {ENABLE_IRQ bit, interrupt-line disable/enable} |
| 76 | ++ * pairs in max3421_irq_handler() and the SPI thread's idle path. |
| 77 | ++ * With the atomic bit alone the thread's test_and_clear_bit() can |
| 78 | ++ * slip between the handler's test_and_set_bit() and its |
| 79 | ++ * disable_irq_nosync(); the thread then enables an already-enabled |
| 80 | ++ * line ("Unbalanced enable for IRQ") and the handler's disable is |
| 81 | ++ * never paired again, leaving the interrupt masked for good. |
| 82 | ++ */ |
| 83 | ++ spinlock_t irq_lock; |
| 84 | ++ |
| 85 | + struct task_struct *spi_thread; |
| 86 | + |
| 87 | + enum max3421_rh_state rh_state; |
| 88 | +@@ -1145,10 +1156,19 @@ max3421_irq_handler(int irq, void *dev_id) |
| 89 | + struct spi_device *spi = to_spi_device(hcd->self.controller); |
| 90 | + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); |
| 91 | + |
| 92 | +- if (max3421_hcd->spi_thread) |
| 93 | +- wake_up_process(max3421_hcd->spi_thread); |
| 94 | ++ /* In hard-IRQ context local interrupts are off: plain spin_lock. */ |
| 95 | ++ spin_lock(&max3421_hcd->irq_lock); |
| 96 | + if (!test_and_set_bit(ENABLE_IRQ, &max3421_hcd->todo)) |
| 97 | + disable_irq_nosync(spi->irq); |
| 98 | ++ spin_unlock(&max3421_hcd->irq_lock); |
| 99 | ++ /* |
| 100 | ++ * Wake the thread only after ENABLE_IRQ is published: a wakeup |
| 101 | ++ * issued before the bit is set can be spent on the thread passing |
| 102 | ++ * its idle check (bit still clear) and going to sleep, and this |
| 103 | ++ * interrupt then sits unnoticed until an unrelated wakeup arrives. |
| 104 | ++ */ |
| 105 | ++ if (max3421_hcd->spi_thread) |
| 106 | ++ wake_up_process(max3421_hcd->spi_thread); |
| 107 | + return IRQ_HANDLED; |
| 108 | + } |
| 109 | + |
| 110 | +@@ -1383,6 +1403,7 @@ max3421_spi_thread(void *dev_id) |
| 111 | + struct spi_device *spi = to_spi_device(hcd->self.controller); |
| 112 | + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); |
| 113 | + int i, i_worked = 1; |
| 114 | ++ unsigned long flags; |
| 115 | + |
| 116 | + /* set full-duplex SPI mode, low-active interrupt pin: */ |
| 117 | + spi_wr8(hcd, MAX3421_REG_PINCTL, |
| 118 | +@@ -1410,8 +1431,15 @@ max3421_spi_thread(void *dev_id) |
| 119 | + spi_wr8(hcd, MAX3421_REG_HIEN, max3421_hcd->hien); |
| 120 | + |
| 121 | + set_current_state(TASK_INTERRUPTIBLE); |
| 122 | ++ /* |
| 123 | ++ * _irqsave: if the MAX3421 interrupt fired on this |
| 124 | ++ * CPU inside the critical section, its handler |
| 125 | ++ * would spin on irq_lock forever. |
| 126 | ++ */ |
| 127 | ++ spin_lock_irqsave(&max3421_hcd->irq_lock, flags); |
| 128 | + if (test_and_clear_bit(ENABLE_IRQ, &max3421_hcd->todo)) |
| 129 | + enable_irq(spi->irq); |
| 130 | ++ spin_unlock_irqrestore(&max3421_hcd->irq_lock, flags); |
| 131 | + schedule(); |
| 132 | + __set_current_state(TASK_RUNNING); |
| 133 | + } |
| 134 | +@@ -1887,6 +1915,13 @@ max3421_probe(struct spi_device *spi) |
| 135 | + INIT_LIST_HEAD(&max3421_hcd->ep_list); |
| 136 | + spi_set_drvdata(spi, max3421_hcd); |
| 137 | + |
| 138 | ++ /* |
| 139 | ++ * Initialize before kthread_run() and request_irq(): the SPI |
| 140 | ++ * thread's idle path takes irq_lock from its first iteration |
| 141 | ++ * (max3421_start() would be too late). |
| 142 | ++ */ |
| 143 | ++ spin_lock_init(&max3421_hcd->irq_lock); |
| 144 | ++ |
| 145 | + max3421_hcd->tx = kmalloc(sizeof(*max3421_hcd->tx), GFP_KERNEL); |
| 146 | + if (!max3421_hcd->tx) |
| 147 | + goto error; |
0 commit comments