summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvjagadish <vjagadish@nvidia.com>2011-09-30 12:45:48 +0530
committerLokesh Pathak <lpathak@nvidia.com>2011-11-09 07:27:51 -0800
commitd1aabf0354c997865bffd8b91ff0bdeac5dd4018 (patch)
tree4a83d3a1c4cdb15aec6b4f6c5b5c6337a071b53d
parent2eef9356f38e3cdfa3378cb61a615a39272b203f (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.c20
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)