summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvjagadish <vjagadish@nvidia.com>2011-08-25 10:25:20 +0530
committerCheryl Jones <chjones@nvidia.com>2011-08-29 14:18:53 -0700
commit929cb12d8a403ecef92aa09c0f670f963412ae99 (patch)
tree00d038d9932d2f9b1ca08f6b116a4dba9368f042
parent76faa72117f9848326356f7edc7abe8799a8f59d (diff)
tegra: usb: ehci: synchronize shutdown and resume
The system is likely to hang if user issues "reboot" command when a user space program is accessing USB device. In this case, the reboot command will cause tegra_ehci_shutdown to be invoked, at the same time, the tegra_ehci_bus_resume may be running and accessing registers when it's not powered on. bug 770426 (cherry picked from commit 31691fafb3e1442c890c8400de0f0e94cce13a8c) (Gerrit link for the original change is http://git-master/r/#change,47340) Change-Id: I2f6ff23ac62a55f67b3c28ad9f3e34704ae6ac54 Reviewed-on: http://git-master/r/49613 Reviewed-by: Venkata Jagadish <vjagadish@nvidia.com> Tested-by: Venkata Jagadish <vjagadish@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r--drivers/usb/host/ehci-tegra.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 116b0806af03..d8813bc68035 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -56,6 +56,7 @@ struct tegra_ehci_hcd {
int power_down_on_bus_suspend;
struct delayed_work work;
enum tegra_usb_phy_port_speed port_speed;
+ struct mutex tegra_ehci_hcd_mutex;
};
static void tegra_ehci_power_up(struct usb_hcd *hcd, bool is_dpd)
@@ -480,6 +481,7 @@ static void tegra_ehci_shutdown(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
+ mutex_lock(&tegra->tegra_ehci_hcd_mutex);
/* ehci_shutdown touches the USB controller registers, make sure
* controller has clocks to it */
if (!tegra->host_resumed)
@@ -489,6 +491,7 @@ static void tegra_ehci_shutdown(struct usb_hcd *hcd)
/* we are ready to shut down, powerdown the phy */
tegra_ehci_power_down(hcd, false);
+ mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
}
static int tegra_ehci_setup(struct usb_hcd *hcd)
@@ -543,13 +546,17 @@ static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
+ int ehci_bus_resumed;
+ mutex_lock(&tegra->tegra_ehci_hcd_mutex);
if (tegra->bus_suspended && tegra->power_down_on_bus_suspend) {
tegra_usb_resume(hcd, false);
tegra->bus_suspended = 0;
}
- return ehci_bus_resume(hcd);
+ ehci_bus_resumed = ehci_bus_resume(hcd);
+ mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
+ return ehci_bus_resumed;
}
#endif
@@ -842,6 +849,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!tegra)
return -ENOMEM;
+ mutex_init(&tegra->tegra_ehci_hcd_mutex);
+
hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd) {