FAILED: patch "[PATCH] usb: dwc3: gadget: fix IRQ storm on invalid event buffer" failed to apply to 6.1-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 1ff77cbefe5a653ea12874c213ea4bd0d72c1067
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026100540-ember-mystified-7271@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 1ff77cbefe5a653ea12874c213ea4bd0d72c1067 Mon Sep 17 00:00:00 2001
From: Jiazi Liu <[email protected]>
Date: Tue, 15 Sep 2026 19:06:37 +0800
Subject: [PATCH] usb: dwc3: gadget: fix IRQ storm on invalid event buffer
count
When dwc3_check_event_buf() reads a GEVNTCOUNT value exceeding the event buffer length, commit 63ccd26cd1f6 ("usb: dwc3: gadget: check that event count does not exceed event buffer length") returns IRQ_NONE without writing back GEVNTCOUNT. Since the DWC3 interrupt is level-triggered, the uncleared IRQ source keeps the line asserted, causing a tight IRQ storm that accumulates 99,900 unhandled interrupts and triggers spurious.c:184 BUG -> kernel panic.
The resulting call stack:
__report_bad_irq+0xac/0xc8 note_interrupt+0x340/0x468 handle_irq_event+0xac/0xc0 handle_fasteoi_irq+0x120/0x228 gic_handle_irq+0x68/0x108 ... kernel BUG at kernel/irq/spurious.c:184
To reproduce, write a bogus value exceeding the event buffer length directly to the GEVNTCOUNT register:
devmem <DWC3_BASE + 0xc40c> 4 0x1004
Write the bogus count back to GEVNTCOUNT to clear the IRQ source, consistent with the stale event clearing pattern in dwc3_event_buffers_setup(), and schedule error recovery to reinitialize the controller.
drivers/usb/dwc3/core.h +19 -0
@@ -49,6 +49,7 @@#define DWC3_ENDPOINTS_NUM 32#define DWC3_XHCI_RESOURCES_NUM 2#define DWC3_ISOC_MAX_RETRIES 5 +#define DWC3_ERR_RECOVERY_MAX 3#define DWC3_SCRATCHBUF_SIZE 4096/* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_BUFFERS_SIZE 4096
@@ -841,6 +842,12 @@ enum dwc3_link_state { DWC3_LINK_STATE_MASK = 0x0f, }; +enum dwc3_err_state { +DWC3_ERR_NONE =0 , +DWC3_ERR_RECOVERY , +DWC3_ERR_UNRECOVERABLE , +}; +/* TRB Length, PCM and Status */ #define DWC3_TRB_SIZE_MASK (0x00ffffff)#define DWC3_TRB_SIZE_LENGTH (n) ((n) & DWC3_TRB_SIZE_MASK)
@@ -1004,6 +1011,7 @@ struct dwc3_glue_ops {/** * struct dwc3 - representation of our controller * @drd_work: workqueue used for role swapping +* @err_recovery_work: workqueue used for controller error recovery * @ep0_trb: trb which is used for the ctrl_req * @bounce: address of bounce buffer * @setup_buf: used while precessing STD USB requests
@@ -1013,6 +1021,7 @@ struct dwc3_glue_ops {* @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing * @mutex: for mode switching +* @connect_mutex: for the pull-up and err_recovery_work * @dev: pointer to our struct device * @sysdev: pointer to the DMA-capable device * @xhci: pointer to our xHCI child
@@ -1079,6 +1088,9 @@ struct dwc3_glue_ops {* @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state +* @err_state: current error recovery state. +* @err_recovery_count: number of consecutive error recovery attempts until +* confirmed healthy and reset to 0 on reset event. * @speed: device speed (super, high, full, low) * @hwparams: copy of hwparams registers * @regset: debugfs pointer to regdump file
@@ -1189,6 +1201,7 @@ struct dwc3_glue_ops {*/ struct dwc3 {struct work_struct drd_work; +struct work_struct err_recovery_work;struct dwc3_trb *ep0_trb;void *bounce;u8 *setup_buf;
@@ -1203,6 +1216,9 @@ struct dwc3 {/* mode switching lock */ struct mutex mutex; +/* serializes pull-up run/stop vs error recovery */ +struct mutex connect_mutex; +struct device *dev;struct device *sysdev;
@@ -1332,6 +1348,9 @@ struct dwc3 {enum dwc3_ep0_next ep0_next_event;enum dwc3_ep0_state ep0state;enum dwc3_link_state link_state; +enum dwc3_err_state err_state; + +u32 err_recovery_count;u16 u2sel;u16 u2pel;
drivers/usb/dwc3/ep0.c +9 -0
@@ -200,6 +200,11 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,int ret;spin_lock_irqsave (&dwc->lock, flags); +if (dwc->err_state !=DWC3_ERR_NONE ) { + ret = -ESHUTDOWN ; + goto out; + } +if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {dev_err (dwc->dev,"%s: can't queue to disabled endpoint\n" , dep->name);
@@ -271,6 +276,10 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)int ret;spin_lock_irqsave (&dwc->lock, flags); +if (dwc->err_state !=DWC3_ERR_NONE ) { +spin_unlock_irqrestore (&dwc->lock, flags); +return -ESHUTDOWN ; + } ret =__dwc3_gadget_ep0_set_halt (ep, value);spin_unlock_irqrestore (&dwc->lock, flags);
drivers/usb/dwc3/gadget.c +106 -2
191 lines not on this page · raw message
Sasha Levin
maintainerPATCH 1/1 usb: dwc3: gadget: fix IRQ storm on invalid event buffer count
From: Jiazi Liu <[email protected]>
[ Upstream commit 1ff77cbefe5a653ea12874c213ea4bd0d72c1067 ]
When dwc3_check_event_buf() reads a GEVNTCOUNT value exceeding the event buffer length, commit 63ccd26cd1f6 ("usb: dwc3: gadget: check that event count does not exceed event buffer length") returns IRQ_NONE without writing back GEVNTCOUNT. Since the DWC3 interrupt is level-triggered, the uncleared IRQ source keeps the line asserted, causing a tight IRQ storm that accumulates 99,900 unhandled interrupts and triggers spurious.c:184 BUG -> kernel panic.
The resulting call stack:
__report_bad_irq+0xac/0xc8 note_interrupt+0x340/0x468 handle_irq_event+0xac/0xc0 handle_fasteoi_irq+0x120/0x228 gic_handle_irq+0x68/0x108 ... kernel BUG at kernel/irq/spurious.c:184
To reproduce, write a bogus value exceeding the event buffer length directly to the GEVNTCOUNT register:
devmem <DWC3_BASE + 0xc40c> 4 0x1004
Write the bogus count back to GEVNTCOUNT to clear the IRQ source, consistent with the stale event clearing pattern in dwc3_event_buffers_setup(), and schedule error recovery to reinitialize the controller.
--- drivers/usb/dwc3/core.h | 19 +++++++ drivers/usb/dwc3/ep0.c | 9 ++++ drivers/usb/dwc3/gadget.c | 104 +++++++++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-)
drivers/usb/dwc3/core.h +19 -0
@@ -42,6 +42,7 @@#define DWC3_ENDPOINTS_NUM 32#define DWC3_XHCI_RESOURCES_NUM 2#define DWC3_ISOC_MAX_RETRIES 5 +#define DWC3_ERR_RECOVERY_MAX 3#define DWC3_SCRATCHBUF_SIZE 4096/* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_BUFFERS_SIZE 4096
@@ -817,6 +818,12 @@ enum dwc3_link_state { DWC3_LINK_STATE_MASK = 0x0f, }; +enum dwc3_err_state { +DWC3_ERR_NONE =0 , +DWC3_ERR_RECOVERY , +DWC3_ERR_UNRECOVERABLE , +}; +/* TRB Length, PCM and Status */ #define DWC3_TRB_SIZE_MASK (0x00ffffff)#define DWC3_TRB_SIZE_LENGTH (n) ((n) & DWC3_TRB_SIZE_MASK)
@@ -972,6 +979,7 @@ struct dwc3_scratchpad_array {/** * struct dwc3 - representation of our controller * @drd_work: workqueue used for role swapping +* @err_recovery_work: workqueue used for controller error recovery * @ep0_trb: trb which is used for the ctrl_req * @bounce: address of bounce buffer * @scratchbuf: address of scratch buffer
@@ -983,6 +991,7 @@ struct dwc3_scratchpad_array {* @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing * @mutex: for mode switching +* @connect_mutex: for the pull-up and err_recovery_work * @dev: pointer to our struct device * @sysdev: pointer to the DMA-capable device * @xhci: pointer to our xHCI child
@@ -1041,6 +1050,9 @@ struct dwc3_scratchpad_array {* @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state +* @err_state: current error recovery state. +* @err_recovery_count: number of consecutive error recovery attempts until +* confirmed healthy and reset to 0 on reset event. * @speed: device speed (super, high, full, low) * @hwparams: copy of hwparams registers * @regset: debugfs pointer to regdump file
@@ -1133,6 +1145,7 @@ struct dwc3_scratchpad_array {*/ struct dwc3 {struct work_struct drd_work; +struct work_struct err_recovery_work;struct dwc3_trb *ep0_trb;void *bounce;void *scratchbuf;
@@ -1149,6 +1162,9 @@ struct dwc3 {/* mode switching lock */ struct mutex mutex; +/* serializes pull-up run/stop vs error recovery */ +struct mutex connect_mutex; +struct device *dev;struct device *sysdev;
@@ -1265,6 +1281,9 @@ struct dwc3 {enum dwc3_ep0_next ep0_next_event;enum dwc3_ep0_state ep0state;enum dwc3_link_state link_state; +enum dwc3_err_state err_state; + +u32 err_recovery_count;u16 u2sel;u16 u2pel;
drivers/usb/dwc3/ep0.c +9 -0
@@ -198,6 +198,11 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,int ret;spin_lock_irqsave (&dwc->lock, flags); +if (dwc->err_state !=DWC3_ERR_NONE ) { + ret = -ESHUTDOWN ; + goto out; + } +if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {dev_err (dwc->dev,"%s: can't queue to disabled endpoint\n" , dep->name);
@@ -269,6 +274,10 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)int ret;spin_lock_irqsave (&dwc->lock, flags); +if (dwc->err_state !=DWC3_ERR_NONE ) { +spin_unlock_irqrestore (&dwc->lock, flags); +return -ESHUTDOWN ; + } ret =__dwc3_gadget_ep0_set_halt (ep, value);spin_unlock_irqrestore (&dwc->lock, flags);
drivers/usb/dwc3/gadget.c +102 -2
181 lines not on this page · raw message
Signature · 1 line
2.53.0