drivers/usb/gadget/udc/dummy_hcd.c | 72 +++++++++++++----------------- 1 file changed, 30 insertions(+), 42 deletions(-)
This series fixes several bugs in dummy_hcd found while testing a
virtio-usb transport under a type-1 hypervisor, using two Linux VMs:
host VM guest VM
+----------------+ +----------------+
| testusb | | g_zero |
+-------|--------+ +--------^-------+
v |
+----------------+ +----------------+
| dummy_hcd | | dummy_hcd |
| (host port) |<---- virtio ---->| (virtual UDC) |
+----------------+ +----------------+
Most of the failures we hit were in our own virtio-usb code, but
after switching the testing from HighSpeed to SuperSpeed a few
issues traced back to dummy_hcd itself:
- patch 1 fixes an incorrect SuperSpeed ep0 maxpacket value
- patch 2 fixes a false -EOVERFLOW reported for legitimate bounded
IN completions
- patch 3 fixes broken SG transfer handling when a URB is serviced
across multiple chunks
- patch 4 sets no_sg_constraint, since dummy_hcd has no hardware DMA
alignment requirement and should not reject SG URBs based on
maxpacket alignment
Igor Skalkin (4):
usb: gadget: dummy_hcd: fix SuperSpeed ep0 maxpacket
usb: gadget: dummy_hcd: fix false overflow on bounded IN
usb: gadget: dummy_hcd: fix SG transfer handling across chunks
usb: gadget: dummy_hcd: set no_sg_constraint on the host controller
drivers/usb/gadget/udc/dummy_hcd.c | 72 +++++++++++++-----------------
1 file changed, 30 insertions(+), 42 deletions(-)
--
2.49.0
This is v2 of the dummy_hcd fixes found while testing our upcoming
virtio-usb transport driver (patches for that will follow separately).
Changes since v1:
- Patch 1 (ep0 maxpacket) is unchanged; carrying forward Alan
Stern's Acked-by.
- Patch 2 (false overflow on bounded IN) is dropped. Alan Stern
pointed out the fix was wrong: an IN short packet where the
device has more data queued than the host's buffer can hold is a
genuine overflow, not a normal bounded completion. Agreed, and
there's no replacement fix queued for this report.
- Patch 3 (SG transfer handling across chunks) is dropped from this
version. Alan Stern confirmed the underlying issue and suggested
a simpler fix (resync the sg_miter with sg_miter_skip() after each
consumed chunk instead of restarting and re-walking from
urb->actual_length on every call). The original failure was
reliably reproducible against an earlier, debug-instrumented
version of our (not yet posted) virtio-usb transport driver, but
is not currently reproducing against the current version of that
driver, which makes it hard to verify a replacement fix with any
confidence. I'd rather confirm a fix against a real reproduction
before resending than resend an unverified change, so this patch
is held back for now and will follow separately once reproduced
again.
- Patch 4 (no_sg_constraint) is reworked per Alan Stern's review:
instead of unconditionally relaxing the SG alignment constraint,
it is now only relaxed on the SuperSpeed bus, preserving the
EHCI-style alignment emulation on the HighSpeed bus.
Igor Skalkin (2):
usb: gadget: dummy_hcd: fix SuperSpeed ep0 maxpacket
usb: gadget: dummy_hcd: set no_sg_constraint only on the SuperSpeed
bus
drivers/usb/gadget/udc/dummy_hcd.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
--
2.49.0
For USB_SPEED_SUPER, dummy_hcd sets ep0 maxpacket to 9.
That is incorrect for SuperSpeed ep0 and breaks short packet handling
in control transfer tests.
Set ep0 maxpacket to 512 for SuperSpeed.
Fixes: 1cd8fd2887e1 ("usb: gadget: dummy_hcd: add SuperSpeed support")
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Igor Skalkin <igor.skalkin@oss.qualcomm.com>
---
drivers/usb/gadget/udc/dummy_hcd.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index f47903461ed5..29f671c7b319 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -896,7 +896,7 @@ static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
static void dummy_udc_update_ep0(struct dummy *dum)
{
if (dum->gadget.speed == USB_SPEED_SUPER)
- dum->ep[0].ep.maxpacket = 9;
+ dum->ep[0].ep.maxpacket = 512;
else
dum->ep[0].ep.maxpacket = 64;
}
--
2.49.0
dummy_hcd registers two separate root hubs/buses: a HighSpeed one
emulating an EHCI-class controller, and a SuperSpeed one emulating an
xHCI-class controller. usb_submit_urb() rejects SG URBs whose
non-final segments are not a multiple of the endpoint maxpacket size,
unless the bus has no_sg_constraint set.
For SuperSpeed bulk endpoints maxpacket is 1024 bytes; usbtest
generates SG lists with varying segment sizes (e.g. 512 bytes) that
are valid transfers but not maxpacket-aligned, causing usb_submit_urb
to return -EINVAL before the URB reaches the host controller.
xHCI-class controllers have no such DMA alignment requirement, so set
no_sg_constraint on the SS bus to match. Leave the HS bus unchanged:
EHCI-class controllers do have this requirement in hardware, and
dummy_hcd's HS roothub is meant to emulate that behaviour, so the
constraint should stay enforced there.
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Assisted-by: OpenCode:claude-sonnet-5
Signed-off-by: Igor Skalkin <igor.skalkin@oss.qualcomm.com>
---
drivers/usb/gadget/udc/dummy_hcd.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 29f671c7b319..0ae600159478 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -2578,6 +2578,15 @@ static int dummy_setup(struct usb_hcd *hcd)
dum->ss_hcd->dum = dum;
hcd->speed = HCD_USB3;
hcd->self.root_hub->speed = USB_SPEED_SUPER;
+
+ /*
+ * xHCI-class SuperSpeed controllers have no maxpacket
+ * alignment requirement for non-final SG segments. Only
+ * relax the constraint on the SS bus; the HS bus keeps
+ * emulating the alignment requirement of EHCI-class
+ * controllers.
+ */
+ hcd->self.no_sg_constraint = 1;
}
return 0;
}
--
2.49.0
On Wed, Aug 12, 2026 at 10:19:10AM +0200, Igor Skalkin wrote: > dummy_hcd registers two separate root hubs/buses: a HighSpeed one > emulating an EHCI-class controller, and a SuperSpeed one emulating an > xHCI-class controller. usb_submit_urb() rejects SG URBs whose > non-final segments are not a multiple of the endpoint maxpacket size, > unless the bus has no_sg_constraint set. > > For SuperSpeed bulk endpoints maxpacket is 1024 bytes; usbtest > generates SG lists with varying segment sizes (e.g. 512 bytes) that > are valid transfers but not maxpacket-aligned, causing usb_submit_urb > to return -EINVAL before the URB reaches the host controller. > > xHCI-class controllers have no such DMA alignment requirement, so set > no_sg_constraint on the SS bus to match. Leave the HS bus unchanged: > EHCI-class controllers do have this requirement in hardware, and > dummy_hcd's HS roothub is meant to emulate that behaviour, so the > constraint should stay enforced there. > > Suggested-by: Alan Stern <stern@rowland.harvard.edu> > Assisted-by: OpenCode:claude-sonnet-5 > Signed-off-by: Igor Skalkin <igor.skalkin@oss.qualcomm.com> > --- Acked-by: Alan Stern <stern@rowland.harvard.edu> > drivers/usb/gadget/udc/dummy_hcd.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c > index 29f671c7b319..0ae600159478 100644 > --- a/drivers/usb/gadget/udc/dummy_hcd.c > +++ b/drivers/usb/gadget/udc/dummy_hcd.c > @@ -2578,6 +2578,15 @@ static int dummy_setup(struct usb_hcd *hcd) > dum->ss_hcd->dum = dum; > hcd->speed = HCD_USB3; > hcd->self.root_hub->speed = USB_SPEED_SUPER; > + > + /* > + * xHCI-class SuperSpeed controllers have no maxpacket > + * alignment requirement for non-final SG segments. Only > + * relax the constraint on the SS bus; the HS bus keeps > + * emulating the alignment requirement of EHCI-class > + * controllers. > + */ > + hcd->self.no_sg_constraint = 1; > } > return 0; > } > -- > 2.49.0 >
© 2016 - 2026 Red Hat, Inc.