Skip to content

Commit 58f2fcb

Browse files
pawellcdnsgregkh
authored andcommitted
usb: cdnsp: Fix deadlock issue during using NCM gadget
The interrupt service routine registered for the gadget is a primary handler which mask the interrupt source and a threaded handler which handles the source of the interrupt. Since the threaded handler is voluntary threaded, the IRQ-core does not disable bottom halves before invoke the handler like it does for the forced-threaded handler. Due to changes in networking it became visible that a network gadget's completions handler may schedule a softirq which remains unprocessed. The gadget's completion handler is usually invoked either in hard-IRQ or soft-IRQ context. In this context it is enough to just raise the softirq because the softirq itself will be handled once that context is left. In the case of the voluntary threaded handler, there is nothing that will process pending softirqs. Which means it remain queued until another random interrupt (on this CPU) fires and handles it on its exit path or another thread locks and unlocks a lock with the bh suffix. Worst case is that the CPU goes idle and the NOHZ complains about unhandled softirqs. Disable bottom halves before acquiring the lock (and disabling interrupts) and enable them after dropping the lock. This ensures that any pending softirqs will handled right away. cc: stable@vger.kernel.org Fixes: 3d82904 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver") Signed-off-by: Pawel Laszczak <pawell@cadence.com> Acked-by: Peter Chen <peter.chen@kernel.org> Link: https://lore.kernel.org/r/20231108093125.224963-1-pawell@cadence.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 187fb00 commit 58f2fcb

1 file changed

Lines changed: 3 additions & 0 deletions

File tree

drivers/usb/cdns3/cdnsp-ring.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,7 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data)
15291529
unsigned long flags;
15301530
int counter = 0;
15311531

1532+
local_bh_disable();
15321533
spin_lock_irqsave(&pdev->lock, flags);
15331534

15341535
if (pdev->cdnsp_state & (CDNSP_STATE_HALTED | CDNSP_STATE_DYING)) {
@@ -1541,6 +1542,7 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data)
15411542
cdnsp_died(pdev);
15421543

15431544
spin_unlock_irqrestore(&pdev->lock, flags);
1545+
local_bh_enable();
15441546
return IRQ_HANDLED;
15451547
}
15461548

@@ -1557,6 +1559,7 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data)
15571559
cdnsp_update_erst_dequeue(pdev, event_ring_deq, 1);
15581560

15591561
spin_unlock_irqrestore(&pdev->lock, flags);
1562+
local_bh_enable();
15601563

15611564
return IRQ_HANDLED;
15621565
}

0 commit comments

Comments
 (0)