Linux USB
 help / color / mirror / Atom feed
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 */

  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