Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
From c5191902ddf76f99a21b2c36c19a82bb04966e1f Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Tue, 24 Jun 2025 13:41:32 +0100
Subject: [PATCH] usb: dwc2: masquerade split-interrupt transfers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Masquerading Interrupt split transfers as Control puts the transfer into
the non-periodic handler in the hub. This stops the hub dropping
complete-split data in the microframe after a CSPLIT should have
arrived, improving resilience to host IRQ latency. Devices are none
the wiser - the handshake tokens are the same.

Originally devised by Hans Petter Selasky @ FreeBSD.

(v2: dwc2 needs an un-masquerade prior to channel interrupt handling)

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
(cherry picked from commit 5329a41ef5655b559fb5274123ce13a0287db878)
Upstream: https://github.com/raspberrypi/linux/pull/6936
Signed-off-by: Jan Čermák <sairon@sairon.cz>
---
drivers/usb/dwc2/hcd.c | 12 ++++++++++++
drivers/usb/dwc2/hcd_intr.c | 3 +++
2 files changed, 15 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 04cebb7b3cedd..23b1dde7a07dd 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -676,6 +676,18 @@ static void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
hcchar |= HCCHAR_EPDIR;
if (chan->speed == USB_SPEED_LOW)
hcchar |= HCCHAR_LSPDDEV;
+
+ /*
+ * Masquerading Interrupt split transfers as Control puts the transfer
+ * into the non-periodic handler in the hub. This stops the hub
+ * dropping complete-split data in the microframe after a CSPLIT
+ * should have arrived, improving resilience to host IRQ latency.
+ * Devices are none the wiser - the handshake tokens are the same.
+ * The fakery is undone in dwc2_hc_n_intr().
+ */
+ if (chan->do_split && chan->ep_type == USB_ENDPOINT_XFER_INT)
+ chan->ep_type = USB_ENDPOINT_XFER_CONTROL;
+
hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
dwc2_writel(hsotg, hcchar, HCCHAR(hc_num));
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index 5c7538d498dd1..60622ef76b6be 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -2048,6 +2048,9 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)

chan->hcint = hcintraw;

+ /* Un-masquerade the transfer type */
+ if (chan->do_split)
+ chan->ep_type = chan->qh->ep_type;
Comment on lines +59 to +61

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null-check for chan->qh before un-masquerading

dwc2_hc_n_intr() runs on channel interrupts; teardown/dequeue paths can momentarily leave chan->qh unset. Guarding avoids a potential NULL dereference.

Apply this diff within the patch:

-+    /* Un-masquerade the transfer type */
-+    if (chan->do_split)
-+        chan->ep_type = chan->qh->ep_type;
+     /* Un-masquerade the transfer type */
+     if (chan->do_split && chan->qh)
+         chan->ep_type = chan->qh->ep_type;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
+ /* Un-masquerade the transfer type */
+ if (chan->do_split)
+ chan->ep_type = chan->qh->ep_type;
/* Un-masquerade the transfer type */
if (chan->do_split && chan->qh)
chan->ep_type = chan->qh->ep_type;
🤖 Prompt for AI Agents
In
buildroot-external/board/raspberrypi/patches/linux/0004-usb-dwc2-masquerade-split-interrupt-transfers.patch
around lines 59 to 61, the code un-masquerades chan->ep_type by reading chan->qh
without checking for NULL; modify the condition to guard the access by checking
chan->qh (e.g., only assign chan->ep_type when chan->do_split && chan->qh) so
the interrupt path cannot dereference a NULL chan->qh.

/*
* If the channel was halted due to a dequeue, the qtd list might
* be empty or at least the first entry will not be the active qtd.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
From 31aede5422f40ed2f42b7238016c140f7dc1a3fe Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Fri, 4 Jul 2025 14:15:19 +0100
Subject: [PATCH] Fixup! usb: dwc2: limit "maximum packet size" for split-IN
transfers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Control Setup phase transfers needs an 8 byte maxpacket override, or
drivers doing a GET with a small buffer as a split transaction would
cause broken transfers.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
(cherry picked from commit 3829e1b98f3d2750b8b38abfdb4a142a0d8e4590)
Upstream: https://github.com/raspberrypi/linux/pull/6936
Signed-off-by: Jan Čermák <sairon@sairon.cz>
---
drivers/usb/dwc2/hcd.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 23b1dde7a07dd..12242649f5650 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -2350,6 +2350,7 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
else
chan->xfer_buf = urb->setup_packet;
chan->xfer_len = 8;
+ chan->max_packet = 8;
break;

case DWC2_CONTROL_DATA: