diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-10-10 16:27:07 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 14:55:34 -0700 |
commit | 32fe01985aa2cb2562f6fc171e526e279abe10db (patch) | |
tree | 0c1865a1d3e91ae0839147430480c4099b16a06f /drivers/usb/core/hub.c | |
parent | 17f060224fb9f435c6f9306b7b61419d038def13 (diff) | |
download | linux-32fe01985aa2cb2562f6fc171e526e279abe10db.tar.gz linux-32fe01985aa2cb2562f6fc171e526e279abe10db.tar.bz2 linux-32fe01985aa2cb2562f6fc171e526e279abe10db.zip |
USB: mutual exclusion for EHCI init and port resets
This patch (as999) fixes a problem that sometimes shows up when host
controller driver modules are loaded in the wrong order. If ehci-hcd
happens to initialize an EHCI controller while the companion OHCI or
UHCI controller is in the middle of a port reset, the reset can fail
and the companion may get very confused. The patch adds an
rw-semaphore and uses it to keep EHCI initialization and port resets
mutually exclusive.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: David Brownell <david-b@pacbell.net>
Cc: David Miller <davem@davemloft.net>
Cc: Dely L Sy <dely.l.sy@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 481dca641ea2..d20cb545a6e4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " "first one fails"); +/* Mutual exclusion for EHCI CF initialization. This interferes with + * port reset on some companion controllers. + */ +DECLARE_RWSEM(ehci_cf_port_reset_rwsem); +EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); + static inline char *portspeed(int portstatus) { @@ -1581,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; + /* Block EHCI CF initialization during the port reset. + * Some companion controllers don't like it when they mix. + */ + down_read(&ehci_cf_port_reset_rwsem); + /* Reset the port */ for (i = 0; i < PORT_RESET_TRIES; i++) { status = set_port_feature(hub->hdev, @@ -1612,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); - return status; + goto done; } dev_dbg (hub->intfdev, @@ -1625,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, "Cannot enable port %i. Maybe the USB cable is bad?\n", port1); + done: + up_read(&ehci_cf_port_reset_rwsem); return status; } |