Re: [PATCH 1/1] usb: dwc3: gadget: fix IRQ storm on invalid event buffer count
From: Liu Jiazi
Date: Fri Aug 07 2026 - 07:04:37 EST
Hi @Thinh.Nguyen@xxxxxxxxxxxx
Thanks for the review suggestions. I've updated the patch accordingly.
On thing I'd like to discuss: in dwc3_err_recovery_work(), after
soft_disconnect succeeds, should we attempt soft_connect to
recover the controller, or just leave it disconnected and let the
upper layer (e.g. function driver like ADB) handle reconnection
on its own?
In my testing, calling soft_connect after soft_disconnect triggers an
RCU stall. Simply doing soft_disconnect and notifying the
gadget driver via dwc3_disconnect_gadget_sleepable() is sufficient —
ADB recovers on its own after that.
What's your recommendation here?
Brs
Jiazi
kernel test robot <lkp@xxxxxxxxx> 于2026年8月6日周四 17:03写道:
>
> Hi Jiazi,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on usb/usb-testing]
> [also build test WARNING on usb/usb-next usb/usb-linus linus/master v7.2-rc6 next-20260805]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Jiazi-Liu/usb-dwc3-gadget-fix-IRQ-storm-on-invalid-event-buffer-count/20260806-005046
> base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
> patch link: https://lore.kernel.org/r/20260727094015.5101-1-liujiazi%40amazon.com
> patch subject: [PATCH 1/1] usb: dwc3: gadget: fix IRQ storm on invalid event buffer count
> config: i386-randconfig-r132-20260806 (https://download.01.org/0day-ci/archive/20260806/202608061759.sIcC6h4C-lkp@xxxxxxxxx/config)
> compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
> sparse: v0.6.5-rc1
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260806/202608061759.sIcC6h4C-lkp@xxxxxxxxx/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@xxxxxxxxx>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202608061759.sIcC6h4C-lkp@xxxxxxxxx/
>
> sparse warnings: (new ones prefixed by >>)
> >> drivers/usb/dwc3/gadget.c:4681:32: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct dwc3 *dwc @@ got void [noderef] __iomem *regs @@
> drivers/usb/dwc3/gadget.c:4681:32: sparse: expected struct dwc3 *dwc
> drivers/usb/dwc3/gadget.c:4681:32: sparse: got void [noderef] __iomem *regs
>
> vim +4681 drivers/usb/dwc3/gadget.c
>
> 4636
> 4637 static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
> 4638 {
> 4639 struct dwc3 *dwc = evt->dwc;
> 4640 u32 amount;
> 4641 u32 count;
> 4642
> 4643 if (pm_runtime_suspended(dwc->dev)) {
> 4644 dwc->pending_events = true;
> 4645 /*
> 4646 * Trigger runtime resume. The get() function will be balanced
> 4647 * after processing the pending events in dwc3_process_pending
> 4648 * events().
> 4649 */
> 4650 pm_runtime_get(dwc->dev);
> 4651 disable_irq_nosync(dwc->irq_gadget);
> 4652 return IRQ_HANDLED;
> 4653 }
> 4654
> 4655 /*
> 4656 * With PCIe legacy interrupt, test shows that top-half irq handler can
> 4657 * be called again after HW interrupt deassertion. Check if bottom-half
> 4658 * irq event handler completes before caching new event to prevent
> 4659 * losing events.
> 4660 */
> 4661 if (evt->flags & DWC3_EVENT_PENDING)
> 4662 return IRQ_HANDLED;
> 4663
> 4664 count = dwc3_readl(dwc, DWC3_GEVNTCOUNT(0));
> 4665 count &= DWC3_GEVNTCOUNT_MASK;
> 4666 if (!count)
> 4667 return IRQ_NONE;
> 4668
> 4669 if (count > evt->length) {
> 4670 dev_err_ratelimited(dwc->dev, "invalid count(%u) > evt->length(%u)\n",
> 4671 count, evt->length);
> 4672 /*
> 4673 * The DWC3 interrupt is level-triggered. Returning IRQ_NONE
> 4674 * without clearing the IRQ source leaves the line asserted,
> 4675 * causing a tight IRQ storm that triggers spurious.c:184 BUG.
> 4676 * Write the bogus count back to GEVNTCOUNT to clear the source,
> 4677 * consistent with the stale event clearing in
> 4678 * dwc3_event_buffers_setup(), then schedule a soft disconnect
> 4679 * to recover the controller state.
> 4680 */
> > 4681 dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
> 4682 schedule_work(&dwc->softcon_work);
> 4683 return IRQ_HANDLED;
> 4684 }
> 4685
> 4686 evt->count = count;
> 4687 evt->flags |= DWC3_EVENT_PENDING;
> 4688
> 4689 /* Mask interrupt */
> 4690 dwc3_writel(dwc, DWC3_GEVNTSIZ(0),
> 4691 DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(evt->length));
> 4692
> 4693 amount = min(count, evt->length - evt->lpos);
> 4694 memcpy(evt->cache + evt->lpos, evt->buf + evt->lpos, amount);
> 4695
> 4696 if (amount < count)
> 4697 memcpy(evt->cache, evt->buf, count - amount);
> 4698
> 4699 dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), count);
> 4700
> 4701 return IRQ_WAKE_THREAD;
> 4702 }
> 4703
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki