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: 32+ 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-24 16:23 ` sashiko-bot
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-24 16:25 ` sashiko-bot
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:28 ` sashiko-bot
2026-09-24 16:09 ` [PATCH 4/8] virtio-usb: add OTG role query support Igor Skalkin
2026-09-24 16:19 ` sashiko-bot
2026-09-24 16:09 ` [PATCH 5/8] virtio-usb: add USB On-The-Go role-switching support Igor Skalkin
2026-09-24 16:24 ` sashiko-bot
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:30 ` sashiko-bot
2026-09-24 16:09 ` Igor Skalkin [this message]
2026-09-24 16:35 ` [PATCH 7/8] virtio-usb: add SuperSpeed device-role support sashiko-bot
2026-09-24 16:09 ` [PATCH 8/8] virtio-usb: support a guest UDC name prefix from the bind event Igor Skalkin
2026-09-24 16:35 ` sashiko-bot
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.