diff options
author | Wang Zhi <zhi.wang@windriver.com> | 2011-08-16 22:39:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-22 16:38:52 -0400 |
commit | d0f2fb2500b1c5fe4967eb45d8c9bc758d7aef80 (patch) | |
tree | 396bb27c52730fc3f53547c5232f8f9ca428801c /drivers/usb | |
parent | 7e1805844da18a37e6d251d286f93c94b52d791e (diff) |
USB: EHCI: Do not rely on PORT_SUSPEND to stop USB resuming in ehci_bus_resume().
From EHCI Spec p.28 HC should clear PORT_SUSPEND when SW clears
PORT_RESUME. In Intel Oaktrail platform, MPH (Multi-Port Host
Controller) core clears PORT_SUSPEND directly when SW sets PORT_RESUME
bit. If we rely on PORT_SUSPEND bit to stop USB resume, we will miss
the action of clearing PORT_RESUME. This will cause unexpected long
resume signal on USB bus.
Signed-off-by: Wang Zhi <zhi.wang@windriver.com>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 7 |
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index e051b30c1847..4c32cb19b405 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -343,7 +343,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
343 | u32 temp; | 343 | u32 temp; |
344 | u32 power_okay; | 344 | u32 power_okay; |
345 | int i; | 345 | int i; |
346 | u8 resume_needed = 0; | 346 | unsigned long resume_needed = 0; |
347 | 347 | ||
348 | if (time_before (jiffies, ehci->next_statechange)) | 348 | if (time_before (jiffies, ehci->next_statechange)) |
349 | msleep(5); | 349 | msleep(5); |
@@ -416,7 +416,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
416 | if (test_bit(i, &ehci->bus_suspended) && | 416 | if (test_bit(i, &ehci->bus_suspended) && |
417 | (temp & PORT_SUSPEND)) { | 417 | (temp & PORT_SUSPEND)) { |
418 | temp |= PORT_RESUME; | 418 | temp |= PORT_RESUME; |
419 | resume_needed = 1; | 419 | set_bit(i, &resume_needed); |
420 | } | 420 | } |
421 | ehci_writel(ehci, temp, &ehci->regs->port_status [i]); | 421 | ehci_writel(ehci, temp, &ehci->regs->port_status [i]); |
422 | } | 422 | } |
@@ -431,8 +431,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
431 | i = HCS_N_PORTS (ehci->hcs_params); | 431 | i = HCS_N_PORTS (ehci->hcs_params); |
432 | while (i--) { | 432 | while (i--) { |
433 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); | 433 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); |
434 | if (test_bit(i, &ehci->bus_suspended) && | 434 | if (test_bit(i, &resume_needed)) { |
435 | (temp & PORT_SUSPEND)) { | ||
436 | temp &= ~(PORT_RWC_BITS | PORT_RESUME); | 435 | temp &= ~(PORT_RWC_BITS | PORT_RESUME); |
437 | ehci_writel(ehci, temp, &ehci->regs->port_status [i]); | 436 | ehci_writel(ehci, temp, &ehci->regs->port_status [i]); |
438 | ehci_vdbg (ehci, "resumed port %d\n", i + 1); | 437 | ehci_vdbg (ehci, "resumed port %d\n", i + 1); |