usb: dwc3: Remove tasklet bottom half handler

There is a possibility of tasklet bottom half handler racing
with dwc3_msm_suspend(). As a result before disabling the dwc3
irq, dwc3 interrupts are fired and once the suspend routine
disables the clocks bottom half handler gets a chance to run
and tries to access dwc3 register resulting into un-clocked
register access. Since dwc3 interrupt is already running in
threaded irq context, interrupt can be directly handled in
same context and avoid this race.

Change-Id: Ife9e165f6aa2112c1440819d659b97b5502a3f07
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
This commit is contained in:
Hemant Kumar 2016-08-09 12:28:55 -07:00
parent e94b446eac
commit 1cb5c91b99
2 changed files with 2 additions and 20 deletions

View file

@ -1005,7 +1005,6 @@ struct dwc3 {
/* IRQ timing statistics */ /* IRQ timing statistics */
int irq; int irq;
struct tasklet_struct bh;
unsigned long irq_cnt; unsigned long irq_cnt;
unsigned bh_completion_time[MAX_INTR_STATS]; unsigned bh_completion_time[MAX_INTR_STATS];
unsigned bh_handled_evt_cnt[MAX_INTR_STATS]; unsigned bh_handled_evt_cnt[MAX_INTR_STATS];

View file

@ -2141,8 +2141,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
atomic_read(&dwc->dev->power.usage_count)); atomic_read(&dwc->dev->power.usage_count));
dwc3_gadget_disable_irq(dwc); dwc3_gadget_disable_irq(dwc);
tasklet_kill(&dwc->bh);
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
__dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[0]);
@ -3380,15 +3378,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
return ret; return ret;
} }
static void dwc3_interrupt_bh(unsigned long param)
{
struct dwc3 *dwc = (struct dwc3 *) param;
pm_runtime_get(dwc->dev);
dwc3_thread_interrupt(dwc->irq, dwc);
enable_irq(dwc->irq);
}
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
{ {
struct dwc3 *dwc = _dwc; struct dwc3 *dwc = _dwc;
@ -3412,7 +3401,6 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
dwc->bh_completion_time[dwc->bh_dbg_index] = temp_time; dwc->bh_completion_time[dwc->bh_dbg_index] = temp_time;
dwc->bh_dbg_index = (dwc->bh_dbg_index + 1) % 10; dwc->bh_dbg_index = (dwc->bh_dbg_index + 1) % 10;
pm_runtime_put(dwc->dev);
return ret; return ret;
} }
@ -3478,10 +3466,8 @@ irqreturn_t dwc3_interrupt(int irq, void *_dwc)
dwc->irq_event_count[dwc->irq_dbg_index] = temp_cnt / 4; dwc->irq_event_count[dwc->irq_dbg_index] = temp_cnt / 4;
dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS; dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS;
if (ret == IRQ_WAKE_THREAD) { if (ret == IRQ_WAKE_THREAD)
disable_irq_nosync(irq); dwc3_thread_interrupt(dwc->irq, dwc);
tasklet_schedule(&dwc->bh);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -3529,9 +3515,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err3; goto err3;
} }
dwc->bh.func = dwc3_interrupt_bh;
dwc->bh.data = (unsigned long)dwc;
dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true; dwc->gadget.sg_supported = true;