summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Connell <w14185@motorola.com>2011-05-02 14:32:36 -0500
committerManish Tuteja <mtuteja@nvidia.com>2011-06-21 06:03:24 -0700
commit818572709891af4fe8c574dfea64310de473acd6 (patch)
tree53fab190e3221ab11b9ce8312cce23d6279ece1e
parent3da1897f8944b3e5273a6176f85f89d28c99612f (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 Signed-off-by: Nathan Connell <w14185@motorola.com> Reviewed-on: http://git-master/r/36311 (cherry picked from commit f4cd754c1af2bbc2101dd208fd4d3d0bf6368d26) Change-Id: I5e4a7aeaef97f0416ff8ea32e6391fe8450e4c26 Reviewed-on: http://git-master/r/37413 Reviewed-by: Manish Tuteja <mtuteja@nvidia.com> Tested-by: Manish Tuteja <mtuteja@nvidia.com>
-rw-r--r--drivers/usb/host/ehci-tegra.c28
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