diff options
author | vjagadish <vjagadish@nvidia.com> | 2011-09-30 12:45:48 +0530 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2011-10-11 07:10:34 -0700 |
commit | ebe88906855200ce846059e80b722d1badced378 (patch) | |
tree | fbb4489d67446b2fa2157a0d99dc190b3f2668a0 | |
parent | 7304266897a867abd479149df8aaa22c467fd1e7 (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/53734
(cherry picked from commit 17f7d52511d38e98c7305319818f62c641d42c0e)
Change-Id: I87f3918d3772100e255185af2236ccdabb97fe85
Reviewed-on: http://git-master/r/56938
Reviewed-by: Suresh Mangipudi <smangipudi@nvidia.com>
Tested-by: Suresh Mangipudi <smangipudi@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@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 2ee41aa81124..fcce552769ba 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; }; @@ -838,11 +839,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); } } @@ -851,11 +851,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) |