Re: [PATCH v5 00/75] usb: dwc3: sync code with Linux v6.16
Anders Roxell <[email protected]>
| Newsgroups | gmane.comp.boot-loaders.u-boot.general,gmane.comp.boot-loaders.u-boot |
|---|---|
| Message-ID | <anmKNYbNQ73Kv3iX@monster> |
On 2026-08-06 18:47, Anshul Dalal wrote: > On Thu, 16 Jul 2026 15:41:30 +0200, Anders Roxell <[email protected]> wrote: > > [...] > > This is compile-tested only. > > > > The series needs the dwc2 endpoint fixes from Mattijs [3]. They are > > already on the list and should go in first. > > > > The branch is also available at [4]. > > Hi Andres, Hi Anshul, Thanks for testing on real hardware. > > I was unable to get DFU boot to work on TI devices with this patch series. I > tested on AM62p EVM where I don't see any error logs on the console but the > DFU device never shows up on the host side (verified with dfu-util and lsusb). > > I'm not that familiar with dwc3 but the issue seems to be that dwc3_interrupt > doesn't report any interrupts. The event path is broken in three places. The main one: in the kernel dwc3_check_event_buf() copies the event ring into evt->cache and dwc3_process_event_buf() reads from evt->cache. We took the reader but not the copy, so it walks a buffer nothing fills. Before the resync we read evt->buf directly, so it worked. I think this is what you are hitting, but you have the board. We also never write the count back to GEVNTCOUNT, and dwc3_thread_interrupt() gets the controller where it wants the event buffer. Fix below, it follows the kernel dwc3_invalidate_cache() is ours, it was in io.h before the resync and got lost. --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -48,4 +48,12 @@ static inline void dwc3_flush_cache(uintptr_t addr, int length) flush_dcache_range((unsigned long)start_addr, (unsigned long)end_addr); } +static inline void dwc3_invalidate_cache(uintptr_t addr, int length) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(CACHELINE_SIZE - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + length, CACHELINE_SIZE); + + invalidate_dcache_range((unsigned long)start_addr, (unsigned long)end_addr); +} + #endif /* __DRIVERS_USB_DWC3_IO_H */ --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4201,23 +4201,46 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; + u32 amount; u32 count; - u32 reg; evt = dwc->ev_buf; + if (evt->flags & DWC3_EVENT_PENDING) + return IRQ_HANDLED; + count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); count &= DWC3_GEVNTCOUNT_MASK; if (!count) return IRQ_NONE; + if (count > evt->length) { + dev_err(dwc->dev, "invalid count(%u) > evt->length(%u)\n", + count, evt->length); + return IRQ_NONE; + } + evt->count = count; evt->flags |= DWC3_EVENT_PENDING; /* Mask interrupt */ - reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0)); - reg |= DWC3_GEVNTSIZ_INTMASK; - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(evt->length)); + + /* The controller filled the buffer over DMA, drop our stale lines */ + dwc3_invalidate_cache((uintptr_t)evt->buf, evt->length); + + amount = min(count, evt->length - evt->lpos); + memcpy(evt->cache + evt->lpos, evt->buf + evt->lpos, amount); + + if (amount < count) + memcpy(evt->cache, evt->buf, count - amount); + + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); return IRQ_WAKE_THREAD; } And in dwc3_gadget_uboot_handle_interrupt(), same file: - struct dwc3_event_buffer *evt; - dwc3_thread_interrupt(0, dwc); + struct dwc3_event_buffer *evt = dwc->ev_buf; + dwc3_thread_interrupt(0, evt); evt was used there without being set as well. All of this is in v6 that I plan to send out. I have no AM62p and it is only compile tested, so please try it on your board so we know if it solves your issue before I send out v6. Cheers, Anders