From: Igor Skalkin <igor.skalkin@oss.qualcomm.com>
To: "Michael S . Tsirkin" <mst@redhat.com>,
Jason Wang <jasowangio@gmail.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: virtualization@lists.linux.dev, linux-usb@vger.kernel.org,
Vasilii Ianikeev <vasilii.ianikeev@oss.qualcomm.com>,
Aiswarya Cyriac <aiswarya.cyriac@oss.qualcomm.com>,
Anton Yakovlev <anton.yakovlev@oss.qualcomm.com>,
Trilok Soni <trilok.soni@oss.qualcomm.com>,
Igor Skalkin <igor.skalkin@oss.qualcomm.com>
Subject: [PATCH 7/8] virtio-usb: add SuperSpeed device-role support
Date: Thu, 24 Sep 2026 18:09:06 +0200 [thread overview]
Message-ID: <20260924160907.145405-8-igor.skalkin@oss.qualcomm.com> (raw)
In-Reply-To: <20260924160907.145405-1-igor.skalkin@oss.qualcomm.com>
Stop hardcoding the gadget's max_speed to USB_SPEED_HIGH on DEV_BIND;
parse max_speed from the bind event sent by the host backend and
clamp it to a supported set (LOW/FULL/HIGH/SUPER/SUPER_PLUS),
defaulting to HIGH on invalid data. Update set_speed() to clamp the
negotiated speed against gadget.max_speed and configure the EP0 max
packet size for SuperSpeed and SuperSpeed Plus (512 bytes both, per
USB 3.1), while preserving existing HS/FS behavior.
Also send the SuperSpeed endpoint companion descriptor together with
the endpoint descriptor on EP_ENABLE, as an additional scatter-gather
payload, so the host backend can configure burst/mult parameters
instead of relying on the endpoint descriptor alone.
This aligns the guest-side speed configuration with the host's
capability and enables SuperSpeed path bring-up.
Signed-off-by: Igor Skalkin <igor.skalkin@oss.qualcomm.com>
---
drivers/usb/virtio_usb/device.c | 54 +++++++++++++++++++++++++++++++++++-----
include/uapi/linux/virtio_usb.h | 8 +++++
2 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/virtio_usb/device.c b/drivers/usb/virtio_usb/device.c
index 9ee1f05..ee41ea9 100644
--- a/drivers/usb/virtio_usb/device.c
+++ b/drivers/usb/virtio_usb/device.c
@@ -439,12 +439,14 @@ static void vep_enable_work(struct work_struct *work)
container_of(work, struct virtio_usb_ep, enable_work);
struct virtio_usb_dc *vudc = vep->vudc;
const struct usb_endpoint_descriptor *desc = vep->ep.desc;
- struct scatterlist sg;
- struct scatterlist *psg_data = &sg;
+ const struct usb_ss_ep_comp_descriptor *comp = vep->ep.comp_desc;
+ struct scatterlist sgs[2];
+ struct scatterlist *psg_data = sgs;
struct virtio_usb_dev_cmd_hdr *hdr;
struct virtio_usb_cmd *cmd;
unsigned long flags;
u16 endpoint;
+ u8 n_sgs = 1;
int rc;
if (!desc)
@@ -461,7 +463,13 @@ static void vep_enable_work(struct work_struct *work)
goto done;
}
- sg_init_one(psg_data, desc, sizeof(*desc));
+ if (virtio_usb_ep_comp_valid(comp))
+ n_sgs = 2;
+
+ sg_init_table(psg_data, n_sgs);
+ sg_set_buf(&psg_data[0], desc, sizeof(*desc));
+ if (n_sgs == 2)
+ sg_set_buf(&psg_data[1], comp, sizeof(*comp));
hdr = virtio_usb_cmd_request(cmd);
hdr->endpoint = cpu_to_le16(endpoint);
@@ -564,6 +572,7 @@ static int virtio_ep_enable(struct usb_ep *ep,
{
struct virtio_usb_ep *vep = usb_ep_to_virtio_ep(ep);
struct virtio_usb_dc *vudc = vep->vudc;
+ const struct usb_ss_ep_comp_descriptor *comp = ep->comp_desc;
unsigned long flags;
spin_lock_irqsave(&vudc->lock, flags);
@@ -579,6 +588,16 @@ static int virtio_ep_enable(struct usb_ep *ep,
return -EBUSY;
}
+ if (comp) {
+ if (!virtio_usb_ep_comp_valid(comp) || comp->bMaxBurst > 15) {
+ spin_unlock_irqrestore(&vudc->lock, flags);
+ return -EINVAL;
+ }
+ } else if (vudc->gadget.speed >= USB_SPEED_SUPER) {
+ spin_unlock_irqrestore(&vudc->lock, flags);
+ return -EINVAL;
+ }
+
ep->desc = desc;
ep->maxpacket = usb_endpoint_maxp(desc);
vep->state = EP_ENABLING;
@@ -1119,9 +1138,13 @@ static void virtio_usb_dc_set_speed(struct usb_gadget *gadget,
struct virtio_usb_dc *vudc =
container_of(gadget, struct virtio_usb_dc, gadget);
- vudc->gadget.speed = min_t(u8, USB_SPEED_HIGH, speed);
+ vudc->gadget.speed = min_t(u8, vudc->gadget.max_speed, speed);
- switch (speed) {
+ switch (vudc->gadget.speed) {
+ case USB_SPEED_SUPER_PLUS:
+ case USB_SPEED_SUPER:
+ vudc->veps[0].ep.maxpacket = 512;
+ break;
case USB_SPEED_HIGH:
case USB_SPEED_FULL:
vudc->veps[0].ep.maxpacket = 64;
@@ -1375,6 +1398,8 @@ static int virtio_usb_dc_parent_create(struct virtio_usb_dc *vudc)
static void virtio_usb_dc_event_process(struct virtio_usb_event *event)
{
struct virtio_usb_dev_event *evt = virtio_usb_event_buf(event);
+ struct virtio_usb_dev_bind_event *bind_evt =
+ (struct virtio_usb_dev_bind_event *)evt;
struct virtio_usb_dev_setup_event *setup_evt;
struct virtio_usb *vusb = event->vusb;
struct virtio_usb_dc *vudc;
@@ -1395,6 +1420,8 @@ static void virtio_usb_dc_event_process(struct virtio_usb_event *event)
switch (le32_to_cpu(evt->code)) {
case VIRTIO_USB_EVT_DEV_BIND: {
+ u8 max_speed;
+
if (vudc->registered) {
dev_err(&vusb->vdev->dev,
"port %d: BIND while still registered, ignoring\n",
@@ -1405,6 +1432,8 @@ static void virtio_usb_dc_event_process(struct virtio_usb_event *event)
memzero_explicit(&vudc->gadget, sizeof(struct usb_gadget));
vudc->gadget.sg_supported = 1;
+ max_speed = bind_evt->max_speed;
+
rc = virtio_usb_dc_get_endpoint_count(vudc);
if (rc) {
dev_err(&vusb->vdev->dev,
@@ -1436,7 +1465,20 @@ static void virtio_usb_dc_event_process(struct virtio_usb_event *event)
break;
}
vudc->gadget.ops = &virtio_gadget_ops;
- vudc->gadget.max_speed = USB_SPEED_HIGH;
+ switch (max_speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
+ vudc->gadget.max_speed = max_speed;
+ break;
+ default:
+ pr_info("virtio-usb: unrecognized max_speed %u from host, defaulting to HIGH\n",
+ max_speed);
+ vudc->gadget.max_speed = USB_SPEED_HIGH;
+ break;
+ }
//vudc->gadget.dev.init_name = gadget_name;
vudc->gadget.dev.parent = &vudc->pdev->dev;
diff --git a/include/uapi/linux/virtio_usb.h b/include/uapi/linux/virtio_usb.h
index 29cec5d..d89223d 100644
--- a/include/uapi/linux/virtio_usb.h
+++ b/include/uapi/linux/virtio_usb.h
@@ -222,6 +222,14 @@ struct virtio_usb_dev_event {
__u8 padding[10];
};
+/* VIRTIO_USB_EVT_DEV_BIND */
+struct virtio_usb_dev_bind_event {
+ __le32 code; /* VIRTIO_USB_EVT_DEV_BIND */
+ __le16 port; /* Device ID */
+ __u8 max_speed; /* enum usb_device_speed */
+ __u8 padding[9];
+};
+
/* VIRTIO_USB_EVT_DEV_SETUP */
struct virtio_usb_dev_setup_event {
__le32 code; /* VIRTIO_USB_EVT_DEV_SETUP */
next prev parent reply other threads:[~2026-09-24 16:09 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 16:08 [PATCH 0/8] virtio-usb: add dual-role virtio USB driver Igor Skalkin
2026-09-24 16:09 ` [PATCH 1/8] virtio-usb: add protocol header and skeleton dual-role driver Igor Skalkin
2026-09-25 5:14 ` Greg Kroah-Hartman
2026-09-28 14:19 ` Igor Skalkin
2026-09-25 5:21 ` Greg Kroah-Hartman
2026-09-28 14:14 ` Igor Skalkin
2026-09-24 16:09 ` [PATCH 2/8] virtio-usb: add host role (USB Host Controller) support Igor Skalkin
2026-09-25 5:18 ` Greg Kroah-Hartman
2026-09-28 14:01 ` Igor Skalkin
2026-09-24 16:09 ` [PATCH 3/8] virtio-usb: add device role (USB Device " Igor Skalkin
2026-09-24 16:09 ` [PATCH 4/8] virtio-usb: add OTG role query support Igor Skalkin
2026-09-24 16:09 ` [PATCH 5/8] virtio-usb: add USB On-The-Go role-switching support Igor Skalkin
2026-09-24 16:09 ` [PATCH 6/8] virtio-usb: rework endpoint lifecycle to an async split-phase state machine Igor Skalkin
2026-09-24 16:09 ` Igor Skalkin [this message]
2026-09-24 16:09 ` [PATCH 8/8] virtio-usb: support a guest UDC name prefix from the bind event Igor Skalkin
2026-09-25 5:17 ` [PATCH 0/8] virtio-usb: add dual-role virtio USB driver Greg Kroah-Hartman
2026-09-28 13:55 ` Igor Skalkin
2026-09-28 14:44 ` Greg Kroah-Hartman
2026-09-28 15:56 ` Igor Skalkin
2026-09-28 16:10 ` Greg Kroah-Hartman
2026-09-29 9:47 ` Michael S. Tsirkin
2026-09-29 16:01 ` Greg Kroah-Hartman
2026-09-29 19:02 ` Vasilii Ianikeev
2026-09-29 19:58 ` Vasilii Ianikeev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260924160907.145405-8-igor.skalkin@oss.qualcomm.com \
--to=igor.skalkin@oss.qualcomm.com \
--cc=aiswarya.cyriac@oss.qualcomm.com \
--cc=anton.yakovlev@oss.qualcomm.com \
--cc=gregkh@linuxfoundation.org \
--cc=jasowangio@gmail.com \
--cc=linux-usb@vger.kernel.org \
--cc=mst@redhat.com \
--cc=trilok.soni@oss.qualcomm.com \
--cc=vasilii.ianikeev@oss.qualcomm.com \
--cc=virtualization@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox