From cda82d5273898db9e5f44fbd7ac320851bfc372d Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Fri, 6 Nov 2015 15:11:46 -0800 Subject: [PATCH] usb: dwc3: Clear pending events when it is bigger than event buffer size 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 --- drivers/usb/dwc3/gadget.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 81ef0aacaba1..46bad8c8ebf9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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;