diff options
| author | Azhar Shaikh <azhars@codeaurora.org> | 2015-08-04 18:45:57 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:07:00 -0700 |
| commit | 9230a73e6bbdfc4010d041e6437c48aa078b61f3 (patch) | |
| tree | 511c15e9275b3c0bc4c56e832b084f9934475a62 /drivers/usb | |
| parent | 6fc5b622c81e58d86b8a19e0389185dc132f915b (diff) | |
usb: dwc3: Offload IRQ handling to softirq context
Move interrupt handling from threaded IRQ context to a tasklet.
This may help in reducing latencies associated with starvation
caused by high priority softirq over threaded USB IRQ.
Change-Id: I2f988be9c484a6ee59236d9dfd7f06f07414ee96
Signed-off-by: Azhar Shaikh <azhars@codeaurora.org>
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/dwc3/core.h | 4 | ||||
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 29 |
2 files changed, 27 insertions, 6 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index d81eb941108f..89d6c06a2073 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -804,6 +804,8 @@ struct dwc3_scratchpad_array { * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode. * @in_lpm: indicates if controller is in low power mode (no clocks) * @tx_fifo_size: Available RAM size for TX fifo allocation + * @irq: irq number + * @bh: tasklet which handles the interrupt * @irq_cnt: total irq count * @bh_completion_time: time taken for taklet completion * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt @@ -966,6 +968,8 @@ struct dwc3 { int tx_fifo_size; /* IRQ timing statistics */ + int irq; + struct tasklet_struct bh; unsigned long irq_cnt; unsigned bh_completion_time[MAX_INTR_STATS]; unsigned bh_handled_evt_cnt[MAX_INTR_STATS]; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2246a5b9444e..5a9ea5a3731f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1792,8 +1792,8 @@ static int dwc3_gadget_start(struct usb_gadget *g, u32 reg; irq = platform_get_irq(to_platform_device(dwc->dev), 0); - ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED, "dwc3", dwc); + dwc->irq = irq; + ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED, "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); @@ -1911,9 +1911,12 @@ static int dwc3_gadget_stop(struct usb_gadget *g) unsigned long flags; int irq; + dwc3_gadget_disable_irq(dwc); + + tasklet_kill(&dwc->bh); + spin_lock_irqsave(&dwc->lock, flags); - dwc3_gadget_disable_irq(dwc); __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); @@ -3032,6 +3035,15 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) 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) { struct dwc3 *dwc = _dwc; @@ -3121,10 +3133,12 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) dwc->irq_event_count[dwc->irq_dbg_index] = temp_cnt / 4; dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS; - if (ret == IRQ_WAKE_THREAD) - pm_runtime_get(dwc->dev); + if (ret == IRQ_WAKE_THREAD) { + disable_irq_nosync(irq); + tasklet_schedule(&dwc->bh); + } - return ret; + return IRQ_HANDLED; } /** @@ -3170,6 +3184,9 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err3; } + dwc->bh.func = dwc3_interrupt_bh; + dwc->bh.data = (unsigned long)dwc; + dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; |
