]> git.hungrycats.org Git - linux/commitdiff
[PATCH] USB: EHCI SMP fix
authorDavid Brownell <david-b@pacbell.net>
Tue, 12 Oct 2004 08:01:51 +0000 (01:01 -0700)
committerGreg Kroah-Hartman <greg@kroah.com>
Tue, 12 Oct 2004 08:01:51 +0000 (01:01 -0700)
This addresses an SMP-only issue with the EHCI driver, where only one CPU
should scan the schedule at a time (scanning is not re-entrant) but either
the IRQ handler or a watchdog timer could end up starting it.  Many thanks
to Olaf Hering for isolating the failure mode, and testing this fix!

Once once CPU starts scanning, any other might as well finish right
away.  This fix just adds a flag to detect that case.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci.h

index 408d4f98fa3ed9d71993ba91b14ae208a37f87a7..e25adf501967c50c357081c8c6c3fffe18bb801f 100644 (file)
@@ -695,9 +695,18 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
        timer_action_done (ehci, TIMER_IO_WATCHDOG);
        if (ehci->reclaim_ready)
                end_unlink_async (ehci, regs);
+
+       /* another CPU may drop ehci->lock during a schedule scan while
+        * it reports urb completions.  this flag guards against bogus
+        * attempts at re-entrant schedule scanning.
+        */
+       if (ehci->scanning)
+               return;
+       ehci->scanning = 1;
        scan_async (ehci, regs);
        if (ehci->next_uframe != -1)
                scan_periodic (ehci, regs);
+       ehci->scanning = 0;
 
        /* the IO watchdog guards against hardware or driver bugs that
         * misplace IRQs, and should let us run completely without IRQs.
index 6439a4be911d6d0e25245e96617250d7134f9b8f..0e8541133ff1ad4bf3cbf5da6524f05fbf43bbc8 100644 (file)
@@ -53,6 +53,7 @@ struct ehci_hcd {                     /* one per controller */
        struct ehci_qh          *async;
        struct ehci_qh          *reclaim;
        unsigned                reclaim_ready : 1;
+       unsigned                scanning : 1;
 
        /* periodic schedule support */
 #define        DEFAULT_I_TDPS          1024            /* some HCs can do less */