summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorAzhar Shaikh <azhars@codeaurora.org>2015-08-04 18:45:57 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:07:00 -0700
commit9230a73e6bbdfc4010d041e6437c48aa078b61f3 (patch)
tree511c15e9275b3c0bc4c56e832b084f9934475a62 /drivers/usb
parent6fc5b622c81e58d86b8a19e0389185dc132f915b (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.h4
-rw-r--r--drivers/usb/dwc3/gadget.c29
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;