diff options
author | vjagadish <vjagadish@nvidia.com> | 2011-08-25 10:25:20 +0530 |
---|---|---|
committer | Cheryl Jones <chjones@nvidia.com> | 2011-08-29 14:18:53 -0700 |
commit | 929cb12d8a403ecef92aa09c0f670f963412ae99 (patch) | |
tree | 00d038d9932d2f9b1ca08f6b116a4dba9368f042 | |
parent | 76faa72117f9848326356f7edc7abe8799a8f59d (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.c | 11 |
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) { |