On 11/11/2016 3:10 AM, Felipe Balbi wrote: > > Hi, > > John Youn <johnyoun@xxxxxxxxxxxx> writes: >> Currently GEVNTCOUNT is written in the threaded interrupt handler while >> processing each event. This commit moves the GEVNTCOUNT write to the >> hard IRQ. We then copy the events to a separate buffer for the event >> handler to read from. >> >> This change is in preparation of working around an issue in core version >> 3.00a where the interrupt cannot be de-asserted in the normal way. >> However, if we enable interrupt moderation, we can also de-assert it by >> writing to GEVNTCOUNT. >> >> Signed-off-by: John Youn <johnyoun@xxxxxxxxxxxx> >> --- >> drivers/usb/dwc3/core.c | 4 ++++ >> drivers/usb/dwc3/core.h | 2 ++ >> drivers/usb/dwc3/gadget.c | 22 +++++++++++++--------- >> 3 files changed, 19 insertions(+), 9 deletions(-) >> >> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c >> index af42346..f0bb6df 100644 >> --- a/drivers/usb/dwc3/core.c >> +++ b/drivers/usb/dwc3/core.c >> @@ -251,6 +251,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, >> >> evt->dwc = dwc; >> evt->length = length; >> + evt->cache = devm_kzalloc(dwc->dev, length, GFP_KERNEL); >> + if (!evt->cache) >> + return ERR_PTR(-ENOMEM); >> + >> evt->buf = dma_alloc_coherent(dwc->dev, length, >> &evt->dma, GFP_KERNEL); >> if (!evt->buf) >> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h >> index 354de24..bf63756 100644 >> --- a/drivers/usb/dwc3/core.h >> +++ b/drivers/usb/dwc3/core.h >> @@ -472,6 +472,7 @@ struct dwc3_trb; >> /** >> * struct dwc3_event_buffer - Software event buffer representation >> * @buf: _THE_ buffer >> + * @cache: The buffer cache used in the threaded interrupt >> * @length: size of this buffer >> * @lpos: event offset >> * @count: cache of last read event count register >> @@ -481,6 +482,7 @@ struct dwc3_trb; >> */ >> struct dwc3_event_buffer { >> void *buf; >> + void *cache; >> unsigned length; >> unsigned int lpos; >> unsigned int count; >> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c >> index 22ccc34..f07dd84 100644 >> --- a/drivers/usb/dwc3/gadget.c >> +++ b/drivers/usb/dwc3/gadget.c >> @@ -2829,18 +2829,16 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) >> { >> struct dwc3 *dwc = evt->dwc; >> irqreturn_t ret = IRQ_NONE; >> - int left; >> + int idx; >> u32 reg; >> >> - left = evt->count; >> - >> if (!(evt->flags & DWC3_EVENT_PENDING)) >> return IRQ_NONE; >> >> - while (left > 0) { >> + for (idx = 0; idx < evt->count; idx += 4) { > > why so many changes on the same patch? Why did you remove left and > evt->lpos? You can still use both for traversing through your cache, > right? What I did was copy the received events from 'buf' to the beginning of 'cache'. So the handler just always traverses an array of 'count' events from the beginning. I could just do a single copy of the entire 'buf' each time. That would be less changes. > >> union dwc3_event event; >> >> - event.raw = *(u32 *) (evt->buf + evt->lpos); >> + event.raw = *(u32 *)(evt->cache + idx); >> >> dwc3_process_event_entry(dwc, &event); >> >> @@ -2853,10 +2851,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) >> * 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(0), 4); >> } >> >> evt->count = 0; >> @@ -2889,6 +2883,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) >> { >> struct dwc3 *dwc = evt->dwc; >> u32 count; >> + u32 amount; > > please keep reverse xmas tree ordering ;-) > >> u32 reg; >> >> if (pm_runtime_suspended(dwc->dev)) { >> @@ -2906,6 +2901,15 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) >> evt->count = count; >> evt->flags |= DWC3_EVENT_PENDING; >> >> + amount = min(count, DWC3_EVENT_BUFFERS_SIZE - evt->lpos); >> + memcpy(evt->cache, evt->buf + evt->lpos, amount); >> + >> + if (amount < count) >> + memcpy(evt->cache + amount, evt->buf, count - amount); >> + >> + evt->lpos = (evt->lpos + count) % DWC3_EVENT_BUFFERS_SIZE; > > evt->lpos is only for the driver, if you don't touch it here you can > still use it on the bottom half handler. Ok, I'll put it back in the BH. > >> + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); > > should you mask first just to make sure we don't have other interrupts > as soon as we clear the ones we just read? > I don't think it matters since we are in interrupt context. But I can move it to be the first thing here. I'm out until Monday, so I won't be able to send a new version until then. Regards, John -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html