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;

Reply via email to