summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorNathan Connell <w14185@motorola.com>2011-05-02 14:32:36 -0500
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:37:10 -0800
commitd7b37edf72e8a054bc6adeae10ea1d226594966e (patch)
tree7b974238a9a4c203ca7b823a01f4f0a7d894a596 /drivers/usb
parentbd0ff305b983bd1b565bec61fc48da64102076bd (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. Change-Id: Ib07f83a2bab5699b2d95533d26d0a6bf541c697d Signed-off-by: Nathan Connell <w14185@motorola.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-tegra.c30
1 files changed, 9 insertions, 21 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 97db3bfa61c7..c1b4e4b0904d 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -159,9 +159,12 @@ static int tegra_ehci_hub_control(
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);
}
}
@@ -214,11 +217,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);
- 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);
@@ -240,24 +243,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;
-
- 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;
}
@@ -476,8 +466,6 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
tegra->bus_suspended = 0;
}
- tegra_usb_phy_preresume(tegra->phy);
- tegra->port_resuming = 1;
return ehci_bus_resume(hcd);
}
#endif