diff options
author | Felipe Balbi <balbi@ti.com> | 2011-06-30 17:57:15 +0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-03-18 13:17:11 +0400 |
commit | b15a762f02acb4f1e695a17435f719350f9d5bc1 (patch) | |
tree | 3153d80d78c504213d3580b8262b182bd0df3ecd /drivers | |
parent | 60d04bbee0b729dc1e95d4dc669f68dea2a32570 (diff) | |
download | linux-b15a762f02acb4f1e695a17435f719350f9d5bc1.tar.xz |
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')
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 86 |
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; } |