I noticed an SMP deadlock when connecting devices to
an autosuspended root hub.
This fixes it for me ... please merge.
- Dave
This fix just makes the OHCI hub status reporting logic (used
exclusively by khubd) be a NOP until after the worker task
(keventd) finishes resuming the port, so they can't deadlock.
Signed-off-by: David Brownell <[EMAIL PROTECTED]>
--- 1.47/drivers/usb/host/ohci-hub.c 2004-11-15 14:28:15 -08:00
+++ edited/drivers/usb/host/ohci-hub.c 2004-12-07 07:53:43 -08:00
@@ -306,17 +306,25 @@
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ports, i, changed = 0, length = 1;
int can_suspend = 1;
+ unsigned long flags;
- /* if !USB_SUSPEND, root hub timers won't get shut down ... */
- if (!HCD_IS_RUNNING(ohci->hcd.state))
- return 0;
+ spin_lock_irqsave (&ohci->lock, flags);
+
+ /* handle autosuspended root: finish resuming before
+ * letting khubd or root hub timer see state changes.
+ */
+ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
+ || !HCD_IS_RUNNING(ohci->hcd.state)) {
+ can_suspend = 0;
+ goto done;
+ }
ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) {
ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports,
ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
/* retry later; "should not happen" */
- return 0;
+ goto done;
}
/* init status */
@@ -352,6 +360,8 @@
continue;
can_suspend = 0;
}
+done:
+ spin_unlock_irqrestore (&ohci->lock, flags);
#ifdef CONFIG_PM
/* save power by suspending idle root hubs;