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 17:55:34 -0400 |
commit | 32fe01985aa2cb2562f6fc171e526e279abe10db (patch) | |
tree | 0c1865a1d3e91ae0839147430480c4099b16a06f /drivers/usb/host/ehci-hcd.c | |
parent | 17f060224fb9f435c6f9306b7b61419d038def13 (diff) |
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/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index db00492588b6..c1514442883e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd) | |||
570 | * are explicitly handed to companion controller(s), so no TT is | 570 | * are explicitly handed to companion controller(s), so no TT is |
571 | * involved with the root hub. (Except where one is integrated, | 571 | * involved with the root hub. (Except where one is integrated, |
572 | * and there's no companion controller unless maybe for USB OTG.) | 572 | * and there's no companion controller unless maybe for USB OTG.) |
573 | * | ||
574 | * Turning on the CF flag will transfer ownership of all ports | ||
575 | * from the companions to the EHCI controller. If any of the | ||
576 | * companions are in the middle of a port reset at the time, it | ||
577 | * could cause trouble. Write-locking ehci_cf_port_reset_rwsem | ||
578 | * guarantees that no resets are in progress. | ||
573 | */ | 579 | */ |
580 | down_write(&ehci_cf_port_reset_rwsem); | ||
574 | hcd->state = HC_STATE_RUNNING; | 581 | hcd->state = HC_STATE_RUNNING; |
575 | ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); | 582 | ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); |
576 | ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ | 583 | ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ |
584 | up_write(&ehci_cf_port_reset_rwsem); | ||
577 | 585 | ||
578 | temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); | 586 | temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); |
579 | ehci_info (ehci, | 587 | ehci_info (ehci, |