diff mbox series

USB: ehci: drop workaround for forced irq threading

Message ID 20210322111249.32141-1-johan@kernel.org (mailing list archive)
State Accepted
Commit 8219ab4c9a09bc746614daaf5240fec82e7fe0e7
Headers show
Series USB: ehci: drop workaround for forced irq threading | expand

Commit Message

Johan Hovold March 22, 2021, 11:12 a.m. UTC
Force-threaded interrupt handlers used to run with interrupts enabled,
something which could lead to deadlocks in case a threaded handler
shared a lock with code running in hard interrupt context (e.g. timer
callbacks) and did not explicitly disable interrupts.

Since commit 81e2073c175b ("genirq: Disable interrupts for force
threaded handlers") interrupt handlers always run with interrupts
disabled on non-RT so that drivers no longer need to do handle forced
threading ("threadirqs").

Drop the now obsolete workaround added by commit a1227f3c1030 ("usb:
ehci: fix deadlock when threadirqs option is used").

Cc: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/host/ehci-hcd.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

Comments

Alan Stern March 22, 2021, 4:42 p.m. UTC | #1
On Mon, Mar 22, 2021 at 12:12:49PM +0100, Johan Hovold wrote:
> Force-threaded interrupt handlers used to run with interrupts enabled,
> something which could lead to deadlocks in case a threaded handler
> shared a lock with code running in hard interrupt context (e.g. timer
> callbacks) and did not explicitly disable interrupts.
> 
> Since commit 81e2073c175b ("genirq: Disable interrupts for force
> threaded handlers") interrupt handlers always run with interrupts
> disabled on non-RT so that drivers no longer need to do handle forced
> threading ("threadirqs").

What happens on RT systems?  Are they smart enough to avoid the whole 
problem by enabling interrupts during _all_ callbacks?

Alan Stern
Sebastian Andrzej Siewior March 22, 2021, 4:59 p.m. UTC | #2
On 2021-03-22 12:42:00 [-0400], Alan Stern wrote:
> What happens on RT systems?  Are they smart enough to avoid the whole 
> problem by enabling interrupts during _all_ callbacks?

tl;dr: Yes. 

The referenced commit (id 81e2073c175b) disables interrupts only on !RT
configs so for RT everything remains unchanged (the backports are
already adjusted for the old stable trees to use the proper CONFIG_* for
enabled RT).

All hrtimer callbacks run as HRTIMER_MODE_SOFT by default. The
HRTIMER_MODE_HARD ones (which expire in HARDIRQ context) were audited /
explicitly enabled.
The same goes irq_work.
The printk code is different compared to mainline. A printk() on RT in
HARDIRQ context is printed once the HARDIRQ context is left. So the
serial/console/… driver never gets a chance to acquire its lock in
hardirq context.

An interrupt handler which is not forced-threaded must be marked as such
and must not use any spinlock_t based locking. lockdep/might_sleep
complain here already.

> Alan Stern

Sebastian
Alan Stern March 22, 2021, 7:01 p.m. UTC | #3
On Mon, Mar 22, 2021 at 05:59:17PM +0100, Sebastian Andrzej Siewior wrote:
> On 2021-03-22 12:42:00 [-0400], Alan Stern wrote:
> > What happens on RT systems?  Are they smart enough to avoid the whole 
> > problem by enabling interrupts during _all_ callbacks?
> 
> tl;dr: Yes. 
> 
> The referenced commit (id 81e2073c175b) disables interrupts only on !RT
> configs so for RT everything remains unchanged (the backports are
> already adjusted for the old stable trees to use the proper CONFIG_* for
> enabled RT).
> 
> All hrtimer callbacks run as HRTIMER_MODE_SOFT by default. The
> HRTIMER_MODE_HARD ones (which expire in HARDIRQ context) were audited /
> explicitly enabled.
> The same goes irq_work.
> The printk code is different compared to mainline. A printk() on RT in
> HARDIRQ context is printed once the HARDIRQ context is left. So the
> serial/console/… driver never gets a chance to acquire its lock in
> hardirq context.
> 
> An interrupt handler which is not forced-threaded must be marked as such
> and must not use any spinlock_t based locking. lockdep/might_sleep
> complain here already.

Okay, in that case:

Acked-by: Alan Stern <stern@rowland.harvard.edu>
diff mbox series

Patch

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1926b328b6aa..403bd3d6991f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -705,15 +705,8 @@  static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			status, masked_status, pcd_status = 0, cmd;
 	int			bh;
-	unsigned long		flags;
 
-	/*
-	 * For threadirqs option we use spin_lock_irqsave() variant to prevent
-	 * deadlock with ehci hrtimer callback, because hrtimer callbacks run
-	 * in interrupt context even when threadirqs is specified. We can go
-	 * back to spin_lock() variant when hrtimer callbacks become threaded.
-	 */
-	spin_lock_irqsave(&ehci->lock, flags);
+	spin_lock(&ehci->lock);
 
 	status = ehci_readl(ehci, &ehci->regs->status);
 
@@ -731,7 +724,7 @@  static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
 	/* Shared IRQ? */
 	if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
-		spin_unlock_irqrestore(&ehci->lock, flags);
+		spin_unlock(&ehci->lock);
 		return IRQ_NONE;
 	}
 
@@ -842,7 +835,7 @@  static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
 	if (bh)
 		ehci_work (ehci);
-	spin_unlock_irqrestore(&ehci->lock, flags);
+	spin_unlock(&ehci->lock);
 	if (pcd_status)
 		usb_hcd_poll_rh_status(hcd);
 	return IRQ_HANDLED;