diff options
author | Nathan Connell <w14185@motorola.com> | 2011-05-02 14:32:36 -0500 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2011-06-14 05:20:32 -0700 |
commit | f4cd754c1af2bbc2101dd208fd4d3d0bf6368d26 (patch) | |
tree | 71b6ba0ca28b41f2f8c4d26eec7cb0ff5a7b28ed | |
parent | 68a04888baab4043d83fc4fd2d9cf95eda444d80 (diff) |
usb: ehci: tegra: Correctly handle GetPortStatus during Resume
Multiple GetPortStatus requests can be made while the
USB bus is resuming. All requests must be handled
properly to prevent incorrect disconnect detection
during Resume and improper indentification of
Resume signaling as a remote wakeup event.
Bug 817128
(cherry-pick from 789333436de3878b2ea878d4c2c030af7ed481ce)
Change-Id: If1a01a5883051290bdaf09537f737e5797209936
Signed-off-by: Nathan Connell <w14185@motorola.com>
Reviewed-on: http://git-master/r/36311
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 28 |
1 files changed, 9 insertions, 19 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 3aa3c9f544bf..c254eac4dcc5 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -148,9 +148,12 @@ static int tegra_ehci_hub_control( goto done; } else if (typeReq == GetPortStatus) { temp = ehci_readl(ehci, status_reg); - if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { + if (tegra->port_resuming && !(temp & PORT_SUSPEND) && + time_after_eq(jiffies, ehci->reset_done[wIndex-1])) { /* Resume completed, re-enable disconnect detection */ tegra->port_resuming = 0; + clear_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); + ehci->reset_done[wIndex-1] = 0; tegra_usb_phy_postresume(tegra->phy, false); } } else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { @@ -196,11 +199,11 @@ static int tegra_ehci_hub_control( if (!(temp & PORT_SUSPEND)) goto done; + tegra->port_resuming = 1; + /* Disable disconnect detection during port resume */ tegra_usb_phy_preresume(tegra->phy, false); - ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); - ehci_dbg(ehci, "%s:USBSTS = 0x%x", __func__, ehci_readl(ehci, &ehci->regs->status)); usbsts_reg = ehci_readl(ehci, &ehci->regs->status); @@ -222,22 +225,11 @@ static int tegra_ehci_hub_control( udelay(20); temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - /* start resume signalling */ + /* start resume signaling */ ehci_writel(ehci, temp | PORT_RESUME, status_reg); - spin_unlock_irqrestore(&ehci->lock, flags); - msleep(20); - spin_lock_irqsave(&ehci->lock, flags); - - /* Poll until the controller clears RESUME and SUSPEND */ - if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) - pr_err("%s: timeout waiting for RESUME\n", __func__); - if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) - pr_err("%s: timeout waiting for SUSPEND\n", __func__); - - ehci->reset_done[wIndex-1] = 0; - - tegra->port_resuming = 1; + ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); + /* whoever resumes must GetPortStatus to complete it!! */ goto done; } @@ -551,8 +543,6 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd) tegra->bus_suspended = 0; } - tegra_usb_phy_preresume(tegra->phy, false); - tegra->port_resuming = 1; return ehci_bus_resume(hcd); } #endif |