diff options
author | vjagadish <vjagadish@nvidia.com> | 2011-09-30 12:45:48 +0530 |
---|---|---|
committer | Lokesh Pathak <lpathak@nvidia.com> | 2011-11-09 07:27:51 -0800 |
commit | d1aabf0354c997865bffd8b91ff0bdeac5dd4018 (patch) | |
tree | 4a83d3a1c4cdb15aec6b4f6c5b5c6337a071b53d | |
parent | 2eef9356f38e3cdfa3378cb61a615a39272b203f (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
Reviewed-on: http://git-master/r/56938
(cherry picked from commit ebe88906855200ce846059e80b722d1badced378)
Change-Id: Id324b53e57eec08d75b147ac18498844ae59b6d2
Reviewed-on: http://git-master/r/62323
Reviewed-by: Lokesh Pathak <lpathak@nvidia.com>
Tested-by: Lokesh Pathak <lpathak@nvidia.com>
-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 01c32e89b4bb..92ff80a044a2 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -70,6 +70,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; }; @@ -835,11 +836,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); } } @@ -849,11 +849,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) |