diff options
author | vjagadish <vjagadish@nvidia.com> | 2011-09-30 12:45:48 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:49:08 -0800 |
commit | ce12d71685f78f75ef9dacbe3572420e19cbb100 (patch) | |
tree | ba2ddf3cb4c64cf1de18c1ccda164e728727b7a0 /drivers/usb | |
parent | 4afe64e1d6b429be478c9b528b68f6527f9776e6 (diff) |
usb: host: tegra: invalid context error on insertion of USB Drive
kernel mutexes may not be used in hardware or software interrupt
contexts such as tasklets and timers.
Bug 876433
Change-Id: I3fc6a016095ad21988d19e1651bd08e48a440e30
Reviewed-on: http://git-master/r/53734
Reviewed-by: Venkata Jagadish <vjagadish@nvidia.com>
Tested-by: Venkata Jagadish <vjagadish@nvidia.com>
Reviewed-by: Rakesh Bodla <rbodla@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Rebase-Id: R8a7554b6b8ab6156b8451f9123b269d754a271b2
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index d88547634577..2a544fc84f5b 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -69,6 +69,7 @@ struct tegra_ehci_hcd { struct work_struct clk_timer_work; struct timer_list clk_timer; bool clock_enabled; + bool timer_event; int hsic_connect_retries; struct mutex tegra_ehci_hcd_mutex; }; @@ -911,11 +912,10 @@ void clk_timer_callback(unsigned long data) unsigned long flags; if (!timer_pending(&tegra->clk_timer)) { - clk_disable(tegra->emc_clk); - clk_disable(tegra->sclk_clk); spin_lock_irqsave(&tegra->ehci->lock, flags); - tegra->clock_enabled = 0; + tegra->timer_event = 1; spin_unlock_irqrestore(&tegra->ehci->lock, flags); + schedule_work(&tegra->clk_timer_work); } } @@ -924,11 +924,23 @@ static void clk_timer_work_handler(struct work_struct* clk_timer_work) { struct tegra_ehci_hcd, clk_timer_work); int ret; unsigned long flags; - bool clock_enabled; + bool clock_enabled, timer_event; spin_lock_irqsave(&tegra->ehci->lock, flags); clock_enabled = tegra->clock_enabled; + timer_event = tegra->timer_event; spin_unlock_irqrestore(&tegra->ehci->lock, flags); + + if (timer_event) { + clk_disable(tegra->emc_clk); + clk_disable(tegra->sclk_clk); + spin_lock_irqsave(&tegra->ehci->lock, flags); + tegra->clock_enabled = 0; + tegra->timer_event = 0; + spin_unlock_irqrestore(&tegra->ehci->lock, flags); + return; + } + if ((!clock_enabled)) { ret = mod_timer(&tegra->clk_timer, jiffies + msecs_to_jiffies(2000)); if (ret) |