OSDN Git Service

usb: dwc3: Clear pending events when it is bigger than event buffer size
authorMayank Rana <mrana@codeaurora.org>
Fri, 6 Nov 2015 23:11:46 +0000 (15:11 -0800)
committerDavid Keitel <dkeitel@codeaurora.org>
Tue, 22 Mar 2016 18:06:58 +0000 (11:06 -0700)
Currently there exists a race condition between dwc3_gadget_run_stop()
and dwc3 gadget interrupt handling. run_stop() could get cleared and set
again in between hard IRQ and threaded IRQ contexts, the DWC3_GEVNTCOUNT
could first get set to 0, and then written again in the threaded handler
with a non-zero value. Writing back to this register will cause hardware
to decrement the value, and since it is 0 will result in a high unsigned
value (~65k).

To handle this condition mark received events as processed and return
IRQ_HANDLED if events count is bigger than event buffer size. Note that
the root cause of this condition will be addressed in another patch that
prevents the race by synchronizing the hard and threaded interrupt handlers
with dwc3_gadget_run_stop() getting called asynchronously.

Change-Id: I4d6ade8243867885f26876a5233a8456a7e8bf42
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
drivers/usb/dwc3/gadget.c

index 81ef0aa..46bad8c 100644 (file)
@@ -3070,6 +3070,13 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
        if (!count)
                return IRQ_NONE;
 
+       if (count > evt->length) {
+               dbg_event(0xFF, "HUGE_EVCNT", count);
+               evt->lpos = (evt->lpos + count) % DWC3_EVENT_BUFFERS_SIZE;
+               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), count);
+               return IRQ_HANDLED;
+       }
+
        evt->count = count;
        evt->flags |= DWC3_EVENT_PENDING;