summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2011-06-30 16:57:15 +0300
committerFelipe Balbi <balbi@ti.com>2013-03-18 11:17:11 +0200
commitb15a762f02acb4f1e695a17435f719350f9d5bc1 (patch)
tree3153d80d78c504213d3580b8262b182bd0df3ecd /drivers/usb/dwc3
parent60d04bbee0b729dc1e95d4dc669f68dea2a32570 (diff)
usb: dwc3: gadget: move to threaded IRQ
by moving to threaded IRQs, we allow our IRQ priorities to be configurable when running with realtime patch. Also, since we're running in thread context, we can call functions which might sleep, such as sysfs_notify() without problems. Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/gadget.c86
1 files changed, 60 insertions, 26 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 73b0b7fc77f1..742eb8268e9a 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1496,6 +1496,7 @@ static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
@@ -1566,8 +1567,8 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc3_ep0_out_start(dwc);
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
- ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
- "dwc3", dwc);
+ ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+ IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
@@ -2432,40 +2433,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
}
}
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ int i;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ for (i = 0; i < dwc->num_event_buffers; i++) {
+ struct dwc3_event_buffer *evt;
+ int left;
+
+ evt = dwc->ev_buffs[i];
+ left = evt->count;
+
+ if (!(evt->flags & DWC3_EVENT_PENDING))
+ continue;
+
+ while (left > 0) {
+ union dwc3_event event;
+
+ event.raw = *(u32 *) (evt->buf + evt->lpos);
+
+ dwc3_process_event_entry(dwc, &event);
+
+ /*
+ * FIXME we wrap around correctly to the next entry as
+ * almost all entries are 4 bytes in size. There is one
+ * entry which has 12 bytes which is a regular entry
+ * followed by 8 bytes data. ATM I don't know how
+ * things are organized if we get next to the a
+ * boundary so I worry about that once we try to handle
+ * that.
+ */
+ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+ left -= 4;
+
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
+ }
+
+ evt->count = 0;
+ evt->flags &= ~DWC3_EVENT_PENDING;
+ ret = IRQ_HANDLED;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
{
struct dwc3_event_buffer *evt;
- int left;
u32 count;
+ evt = dwc->ev_buffs[buf];
+
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
return IRQ_NONE;
- evt = dwc->ev_buffs[buf];
- left = count;
-
- while (left > 0) {
- union dwc3_event event;
-
- event.raw = *(u32 *) (evt->buf + evt->lpos);
-
- dwc3_process_event_entry(dwc, &event);
- /*
- * XXX we wrap around correctly to the next entry as almost all
- * entries are 4 bytes in size. There is one entry which has 12
- * bytes which is a regular entry followed by 8 bytes data. ATM
- * I don't know how things are organized if were get next to the
- * a boundary so I worry about that once we try to handle that.
- */
- evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
- left -= 4;
-
- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
- }
+ evt->count = count;
+ evt->flags |= DWC3_EVENT_PENDING;
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
@@ -2480,7 +2514,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
irqreturn_t status;
status = dwc3_process_event_buf(dwc, i);
- if (status == IRQ_HANDLED)
+ if (status == IRQ_WAKE_THREAD)
ret = status;
}