Commit f977cda1 authored by David Brownell's avatar David Brownell Committed by Linus Torvalds

[PATCH] USB: OHCI "resume"/smp fix

I noticed an SMP deadlock when connecting devices to
an autosuspended root hub.

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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 373390dc
...@@ -306,17 +306,25 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -306,17 +306,25 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ports, i, changed = 0, length = 1; int ports, i, changed = 0, length = 1;
int can_suspend = 1; int can_suspend = 1;
unsigned long flags;
/* if !USB_SUSPEND, root hub timers won't get shut down ... */ spin_lock_irqsave (&ohci->lock, flags);
if (!HCD_IS_RUNNING(ohci->hcd.state))
return 0; /* 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; ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) { if (ports > MAX_ROOT_PORTS) {
ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports, ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports,
ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
/* retry later; "should not happen" */ /* retry later; "should not happen" */
return 0; goto done;
} }
/* init status */ /* init status */
...@@ -352,6 +360,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -352,6 +360,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
continue; continue;
can_suspend = 0; can_suspend = 0;
} }
done:
spin_unlock_irqrestore (&ohci->lock, flags);
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* save power by suspending idle root hubs; /* save power by suspending idle root hubs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment