aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)
1496} 1496}
1497 1497
1498static irqreturn_t dwc3_interrupt(int irq, void *_dwc); 1498static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
1499static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
1499 1500
1500static int dwc3_gadget_start(struct usb_gadget *g, 1501static int dwc3_gadget_start(struct usb_gadget *g,
1501 struct usb_gadget_driver *driver) 1502 struct usb_gadget_driver *driver)
@@ -1566,8 +1567,8 @@ static int dwc3_gadget_start(struct usb_gadget *g,
1566 dwc3_ep0_out_start(dwc); 1567 dwc3_ep0_out_start(dwc);
1567 1568
1568 irq = platform_get_irq(to_platform_device(dwc->dev), 0); 1569 irq = platform_get_irq(to_platform_device(dwc->dev), 0);
1569 ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED, 1570 ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
1570 "dwc3", dwc); 1571 IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
1571 if (ret) { 1572 if (ret) {
1572 dev_err(dwc->dev, "failed to request irq #%d --> %d\n", 1573 dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
1573 irq, ret); 1574 irq, ret);
@@ -2432,40 +2433,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
2432 } 2433 }
2433} 2434}
2434 2435
2436static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
2437{
2438 struct dwc3 *dwc = _dwc;
2439 unsigned long flags;
2440 irqreturn_t ret = IRQ_NONE;
2441 int i;
2442
2443 spin_lock_irqsave(&dwc->lock, flags);
2444
2445 for (i = 0; i < dwc->num_event_buffers; i++) {
2446 struct dwc3_event_buffer *evt;
2447 int left;
2448
2449 evt = dwc->ev_buffs[i];
2450 left = evt->count;
2451
2452 if (!(evt->flags & DWC3_EVENT_PENDING))
2453 continue;
2454
2455 while (left > 0) {
2456 union dwc3_event event;
2457
2458 event.raw = *(u32 *) (evt->buf + evt->lpos);
2459
2460 dwc3_process_event_entry(dwc, &event);
2461
2462 /*
2463 * FIXME we wrap around correctly to the next entry as
2464 * almost all entries are 4 bytes in size. There is one
2465 * entry which has 12 bytes which is a regular entry
2466 * followed by 8 bytes data. ATM I don't know how
2467 * things are organized if we get next to the a
2468 * boundary so I worry about that once we try to handle
2469 * that.
2470 */
2471 evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
2472 left -= 4;
2473
2474 dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
2475 }
2476
2477 evt->count = 0;
2478 evt->flags &= ~DWC3_EVENT_PENDING;
2479 ret = IRQ_HANDLED;
2480 }
2481
2482 spin_unlock_irqrestore(&dwc->lock, flags);
2483
2484 return ret;
2485}
2486
2435static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) 2487static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
2436{ 2488{
2437 struct dwc3_event_buffer *evt; 2489 struct dwc3_event_buffer *evt;
2438 int left;
2439 u32 count; 2490 u32 count;
2440 2491
2492 evt = dwc->ev_buffs[buf];
2493
2441 count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf)); 2494 count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
2442 count &= DWC3_GEVNTCOUNT_MASK; 2495 count &= DWC3_GEVNTCOUNT_MASK;
2443 if (!count) 2496 if (!count)
2444 return IRQ_NONE; 2497 return IRQ_NONE;
2445 2498
2446 evt = dwc->ev_buffs[buf]; 2499 evt->count = count;
2447 left = count; 2500 evt->flags |= DWC3_EVENT_PENDING;
2448
2449 while (left > 0) {
2450 union dwc3_event event;
2451
2452 event.raw = *(u32 *) (evt->buf + evt->lpos);
2453
2454 dwc3_process_event_entry(dwc, &event);
2455 /*
2456 * XXX we wrap around correctly to the next entry as almost all
2457 * entries are 4 bytes in size. There is one entry which has 12
2458 * bytes which is a regular entry followed by 8 bytes data. ATM
2459 * I don't know how things are organized if were get next to the
2460 * a boundary so I worry about that once we try to handle that.
2461 */
2462 evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
2463 left -= 4;
2464
2465 dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
2466 }
2467 2501
2468 return IRQ_HANDLED; 2502 return IRQ_WAKE_THREAD;
2469} 2503}
2470 2504
2471static irqreturn_t dwc3_interrupt(int irq, void *_dwc) 2505static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
@@ -2480,7 +2514,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
2480 irqreturn_t status; 2514 irqreturn_t status;
2481 2515
2482 status = dwc3_process_event_buf(dwc, i); 2516 status = dwc3_process_event_buf(dwc, i);
2483 if (status == IRQ_HANDLED) 2517 if (status == IRQ_WAKE_THREAD)
2484 ret = status; 2518 ret = status;
2485 } 2519 }
2486 2520