Skip to contentSkip to conversation

usb: host: move EH SINGLE_STEP_SET_FEATURE implementation to core

PATCH Superseded Li Jun 4 participants 10 messages May 7, 2021 – Aug 21, 2021

Subsystems (3)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Li Jun

author
#0 lore raw

PATCH v3 1/3 usb: host: move EH SINGLE_STEP_SET_FEATURE implementation to core

From: Peter Chen <[email protected]>

It is needed at USB Certification test for Embedded Host 2.0, and the detail is at CH6.4.1.1 of On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification. Since other USB 2.0 capable host like XHCI also need it, so move it to HCD core.

---
Change for v3:
- Add Alan's A-b tag.

Change for v2:
- No change.

 drivers/usb/core/hcd.c      | 134 ++++++++++++++++++++++++++++++++++
 drivers/usb/host/ehci-hcd.c |   4 ++
 drivers/usb/host/ehci-hub.c | 139 ------------------------------------
 drivers/usb/host/ehci-q.c   |   2 +-
 include/linux/usb/hcd.h     |  13 +++-
 5 files changed, 151 insertions(+), 141 deletions(-)
drivers/usb/core/hcd.c +134 -0
index 6119fb41d736..d7eb9f179ca6 100644
@@ -2110,6 +2110,140 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
 	return hcd->driver->get_frame_number (hcd);
 }
 
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+static void usb_ehset_completion(struct urb *urb)
+{
+	struct completion  *done = urb->context;
+
+	complete(done);
+}
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+	struct usb_device	*udev,
+	void			*dr,
+	void			*buf,
+	struct completion	*done)
+{
+	struct urb *urb;
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+	struct usb_host_endpoint *ep;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return NULL;
+
+	urb->pipe = usb_rcvctrlpipe(udev, 0);
+	ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+				[usb_pipeendpoint(urb->pipe)];
+	if (!ep) {
+		usb_free_urb(urb);
+		return NULL;
+	}
+
+	urb->ep = ep;
+	urb->dev = udev;
+	urb->setup_packet = (void *)dr;
+	urb->transfer_buffer = buf;
+	urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+	urb->complete = usb_ehset_completion;
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->transfer_flags = URB_DIR_IN;
+	usb_get_urb(urb);
+	atomic_inc(&urb->use_count);
+	atomic_inc(&urb->dev->urbnum);
+	urb->setup_dma = dma_map_single(
+			hcd->self.sysdev,
+			urb->setup_packet,
+			sizeof(struct usb_ctrlrequest),
+			DMA_TO_DEVICE);
+	urb->transfer_dma = dma_map_single(
+			hcd->self.sysdev,
+			urb->transfer_buffer,
+			urb->transfer_buffer_length,
+			DMA_FROM_DEVICE);
+	urb->context = done;
+	return urb;
+}
+
+int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+	int retval = -ENOMEM;
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
+	struct usb_device *udev;
+	struct usb_device_descriptor *buf;
+	DECLARE_COMPLETION_ONSTACK(done);
+
+	/* Obtain udev of the rhub's child port */
+	udev = usb_hub_find_child(hcd->self.root_hub, port);
+	if (!udev) {
+		dev_err(hcd->self.controller, "No device attached to the RootHub\n");
+		return -ENODEV;
+	}
+	buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!dr) {
+		kfree(buf);
+		return -ENOMEM;
+	}
+
+	/* Fill Setup packet for GetDescriptor */
+	dr->bRequestType = USB_DIR_IN;
+	dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+	dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+	dr->wIndex = 0;
+	dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+	urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+	if (!urb)
+		goto cleanup;
+
+	/* Submit just the SETUP stage */
+	retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 1);
+	if (retval)
+		goto out1;
+	if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+		usb_kill_urb(urb);
+		retval = -ETIMEDOUT;
+		dev_err(hcd->self.controller,
+			"%s SETUP stage timed out on ep0\n", __func__);
+		goto out1;
+	}
+	msleep(15 * 1000);
+
+	/* Complete remaining DATA and STATUS stages using the same URB */
+	urb->status = -EINPROGRESS;
+	usb_get_urb(urb);
+	atomic_inc(&urb->use_count);
+	atomic_inc(&urb->dev->urbnum);
+	retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0);
+	if (!retval && !wait_for_completion_timeout(&done,
+						msecs_to_jiffies(2000))) {
+		usb_kill_urb(urb);
+		retval = -ETIMEDOUT;
+		dev_err(hcd->self.controller,
+			"%s IN stage timed out on ep0\n", __func__);
+	}
+out1:
+	usb_free_urb(urb);
+cleanup:
+	kfree(dr);
+	kfree(buf);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(ehset_single_step_set_feature);
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef	CONFIG_PM
drivers/usb/host/ehci-hcd.c +4 -0
index 94b5e64ae9a2..35eec0c0edcd 100644
@@ -1238,6 +1238,10 @@ static const struct hc_driver ehci_hc_driver = {
 	 * device support
 	 */
 	.free_dev =		ehci_remove_device,
+#ifdef CONFIG_USB_HCD_TEST_MODE
+	/* EH SINGLE_STEP_SET_FEATURE test support */
+	.submit_single_step_set_feature	= ehci_submit_single_step_set_feature,
+#endif
 };
 
 void ehci_init_driver(struct hc_driver *drv,
drivers/usb/host/ehci-hub.c +0 -139

145 lines not on this page · raw message

drivers/usb/host/ehci-q.c +1 -1
index a826715ae9bd..2cbf4f85bff3 100644
@@ -1165,7 +1165,7 @@ submit_async (
  * performed; TRUE - SETUP and FALSE - IN+STATUS
  * Returns 0 if success
  */
-static int submit_single_step_set_feature(
+static int ehci_submit_single_step_set_feature(
 	struct usb_hcd  *hcd,
 	struct urb      *urb,
 	int             is_setup
include/linux/usb/hcd.h +12 -1
index 96281cd50ff6..22c5d1c0acf3 100644
@@ -409,7 +409,10 @@ struct hc_driver {
 	int	(*find_raw_port_number)(struct usb_hcd *, int);
 	/* Call for power on/off the port if necessary */
 	int	(*port_power)(struct usb_hcd *hcd, int portnum, bool enable);
-
+	/* Call for SINGLE_STEP_SET_FEATURE Test for USB2 EH certification */
+#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
+	int	(*submit_single_step_set_feature)(struct usb_hcd *,
+			struct urb *, int);
 };
 
 static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
@@ -474,6 +477,14 @@ int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
 
 struct platform_device;
 extern void usb_hcd_platform_shutdown(struct platform_device *dev);
+#ifdef CONFIG_USB_HCD_TEST_MODE
+extern int ehset_single_step_set_feature(struct usb_hcd *hcd, int port);
+#else
+static inline int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+	return 0;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
 
 #ifdef CONFIG_USB_PCI
 struct pci_dev;
Signature · 1 line
2.25.1
author
#1 lore raw

PATCH v3 2/3 usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

From: Peter Chen <[email protected]>

This function is similar with EHCI's, but implemented using XHCI. The USB2 host needs to send SETUP packet first, then wait 15 seconds before DATA (IN) + STATUS stage.

---
Change for v3:
- No change.

Change for v2:
- No change.

 drivers/usb/host/xhci-hub.c  |  10 +++
 drivers/usb/host/xhci-ring.c | 123 +++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci.c      |   1 +
 drivers/usb/host/xhci.h      |  10 +++
 4 files changed, 144 insertions(+)
drivers/usb/host/xhci-hub.c +10 -0
index e9b18fc17617..c64ee95cc89b 100644
@@ -1511,6 +1511,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 			/* 4.19.6 Port Test Modes (USB2 Test Mode) */
 			if (hcd->speed != HCD_USB2)
 				goto error;
+
+#ifdef CONFIG_USB_HCD_TEST_MODE
+			if (test_mode == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
+				spin_unlock_irqrestore(&xhci->lock, flags);
+				retval = ehset_single_step_set_feature(hcd,
+								wIndex + 1);
+				spin_lock_irqsave(&xhci->lock, flags);
+				break;
+			}
+#endif
 			if (test_mode > USB_TEST_FORCE_ENABLE ||
 			    test_mode < USB_TEST_J)
 				goto error;
drivers/usb/host/xhci-ring.c +123 -0

129 lines not on this page · raw message

drivers/usb/host/xhci.c +1 -0
index ca9385d22f68..a27616775845 100644
@@ -5426,6 +5426,7 @@ static const struct hc_driver xhci_hc_driver = {
 	.disable_usb3_lpm_timeout =	xhci_disable_usb3_lpm_timeout,
 	.find_raw_port_number =	xhci_find_raw_port_number,
 	.clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
+	.submit_single_step_set_feature	= xhci_submit_single_step_set_feature,
 };
 
 void xhci_init_driver(struct hc_driver *drv,
drivers/usb/host/xhci.h +10 -0
index 2595a8f057c4..f93fc8f59af6 100644
@@ -2165,6 +2165,16 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
 struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
 
 void xhci_hc_died(struct xhci_hcd *xhci);
+#ifdef CONFIG_USB_HCD_TEST_MODE
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+	struct urb *urb, int is_setup);
+#else
+static inline int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+	struct urb *urb, int is_setup)
+{
+	return 0;
+}
+#endif
 
 #ifdef CONFIG_PM
 int xhci_bus_suspend(struct usb_hcd *hcd);
Signature · 1 line
2.25.1
author
#2 lore raw

RE: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Quoted 226 lines

-----Original Message-----
From: Jun Li <[email protected]>
Sent: Friday, May 7, 2021 2:58 PM
To: [email protected]; [email protected]; [email protected]
Cc: [email protected]; Jun Li <[email protected]>; [email protected]; [email protected]; dl-linux-imx <[email protected]>
Subject: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

From: Peter Chen <[email protected]>

This function is similar with EHCI's, but implemented using XHCI. The USB2 host needs to send SETUP packet first, then wait 15 seconds before DATA (IN) + STATUS stage.

---
Change for v3:
- No change.

Change for v2:
- No change.

 drivers/usb/host/xhci-hub.c  |  10 +++
 drivers/usb/host/xhci-ring.c | 123 +++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci.c      |   1 +
 drivers/usb/host/xhci.h      |  10 +++
 4 files changed, 144 insertions(+)
drivers/usb/host/xhci-hub.c +10 -0
index e9b18fc17617..c64ee95cc89b 100644
@@ -1511,6 +1511,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq,
 u16 wValue,
 			/* 4.19.6 Port Test Modes (USB2 Test Mode) */
 			if (hcd->speed != HCD_USB2)
 				goto error;
+
+#ifdef CONFIG_USB_HCD_TEST_MODE
+			if (test_mode == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
+				spin_unlock_irqrestore(&xhci->lock, flags);
+				retval = ehset_single_step_set_feature(hcd,
+								wIndex + 1);
+				spin_lock_irqsave(&xhci->lock, flags);
+				break;
+			}
+#endif
 			if (test_mode > USB_TEST_FORCE_ENABLE ||
 			    test_mode < USB_TEST_J)
drivers/usb/host/xhci-hub.c +0 -0
 				goto error;
drivers/usb/host/xhci-ring.c +124 -0
index 05c38dd3ee36..87a9c1e3325a 100644
@@ -3793,6 +3793,129 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t
 mem_flags,
 	return 0;
 }
 
+#ifdef CONFIG_USB_HCD_TEST_MODE
+/*
+ * This function prepare TRBs and submits them for the
+ * SINGLE_STEP_SET_FEATURE Test.
+ * This is done in two parts: first SETUP req for GetDesc is sent then
+ * 15 seconds later, the IN stage for GetDesc starts to req data from
+dev
+ *
+ * is_setup : argument decides which of the two stage needs to be
+ * performed; TRUE - SETUP and FALSE - IN+STATUS
+ * Returns 0 if success
+ */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+	struct urb *urb, int is_setup)
+{
+	int slot_id;
+	unsigned int ep_index;
+	struct xhci_ring *ep_ring;
+	int ret;
+	struct usb_ctrlrequest *setup;
+	struct xhci_generic_trb *start_trb;
+	int start_cycle;
+	u32 field, length_field, remainder;
+	struct urb_priv *urb_priv;
+	struct xhci_td *td;
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	/* urb_priv will be free after transcation has completed */
+	urb_priv = kzalloc(sizeof(struct urb_priv) +
+			sizeof(struct xhci_td), GFP_KERNEL);
+	if (!urb_priv)
+		return -ENOMEM;
+
+	td = &urb_priv->td[0];
+	urb_priv->num_tds = 1;
+	urb_priv->num_tds_done = 0;
+	urb->hcpriv = urb_priv;
+
+	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+	if (!ep_ring) {
+		ret = -EINVAL;
+		goto free_priv;
+	}
+
+	slot_id = urb->dev->slot_id;
+	ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+
+	setup = (struct usb_ctrlrequest *) urb->setup_packet;
+	if (is_setup) {
+		ret = prepare_transfer(xhci, xhci->devs[slot_id],
+				ep_index, urb->stream_id,
+				1, urb, 0, GFP_KERNEL);
+		if (ret < 0)
+			goto free_priv;
+
+		start_trb = &ep_ring->enqueue->generic;
+		start_cycle = ep_ring->cycle_state;
+		/* Save the DMA address of the last TRB in the TD */
+		td->last_trb = ep_ring->enqueue;
+		field = TRB_IOC | TRB_IDT | TRB_TYPE(TRB_SETUP) | start_cycle;
+		/* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
+		if ((xhci->hci_version >= 0x100) ||
+				(xhci->quirks & XHCI_MTK_HOST))
+			field |= TRB_TX_TYPE(TRB_DATA_IN);
+
+		queue_trb(xhci, ep_ring, false,
+			  setup->bRequestType | setup->bRequest << 8 |
+			  le16_to_cpu(setup->wValue) << 16,
+			  le16_to_cpu(setup->wIndex) |
+			  le16_to_cpu(setup->wLength) << 16,
+			  TRB_LEN(8) | TRB_INTR_TARGET(0),
+			  /* Immediate data in pointer */
+			  field);
+		giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
+				start_cycle, start_trb);
+		return 0;
+	}
+
+	ret = prepare_transfer(xhci, xhci->devs[slot_id],
+			ep_index, urb->stream_id,
+			2, urb, 0, GFP_KERNEL);
+	if (ret < 0)
+		goto free_priv;
+
+	start_trb = &ep_ring->enqueue->generic;
+	start_cycle = ep_ring->cycle_state;
+	field = TRB_ISP | TRB_TYPE(TRB_DATA);
+
+	remainder = xhci_td_remainder(xhci, 0,
+				   urb->transfer_buffer_length,
+				   urb->transfer_buffer_length,
+				   urb, 1);
+
+	length_field = TRB_LEN(urb->transfer_buffer_length) |
+		TRB_TD_SIZE(remainder) |
+		TRB_INTR_TARGET(0);
+
+	if (urb->transfer_buffer_length > 0) {
+		field |= TRB_DIR_IN;
+		queue_trb(xhci, ep_ring, true,
+				lower_32_bits(urb->transfer_dma),
+				upper_32_bits(urb->transfer_dma),
+				length_field,
+				field | ep_ring->cycle_state);
+	}
+
+	td->last_trb = ep_ring->enqueue;
+	field = TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
+	queue_trb(xhci, ep_ring, false,
+			0,
+			0,
+			TRB_INTR_TARGET(0),
+			field);
+
+	giveback_first_trb(xhci, slot_id, ep_index, 0,
+			start_cycle, start_trb);
+
+	return 0;
+free_priv:
+	xhci_urb_free_priv(urb_priv);
+	return ret;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
 /*
  * The transfer burst count field of the isochronous TRB defines the number

of
* bursts that are required to move all packets in this TD. Only SuperSpeed

drivers/usb/host/xhci.c index renamed from drivers/usb/host/xhci.c +0 -0

ca9385d22f68..a27616775845 100644

drivers/usb/host/xhci.c +1 -0
@@ -5426,6 +5426,7 @@ static const struct hc_driver xhci_hc_driver = {
 	.disable_usb3_lpm_timeout =	xhci_disable_usb3_lpm_timeout,
 	.find_raw_port_number =	xhci_find_raw_port_number,
 	.clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
+	.submit_single_step_set_feature	=
 xhci_submit_single_step_set_feature,
 };
 

void xhci_init_driver(struct hc_driver *drv, diff --git
a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2595a8f057c4..f93fc8f59af6 100644

drivers/usb/host/xhci.h +10 -0
@@ -2165,6 +2165,16 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd,
 int port1);  struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
 
 void xhci_hc_died(struct xhci_hcd *xhci);
+#ifdef CONFIG_USB_HCD_TEST_MODE
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+	struct urb *urb, int is_setup);
+#else
+static inline int xhci_submit_single_step_set_feature(struct usb_hcd
 *hcd,
+	struct urb *urb, int is_setup)
+{
+	return 0;
+}
+#endif
 
 #ifdef CONFIG_PM
Quoted 3 lines

int xhci_bus_suspend(struct usb_hcd *hcd);
--
2.25.1

A gentle ping.

Li Jun

author
#3 lore raw

RE: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Hi Mathias,

Quoted 240 lines

-----Original Message-----
From: Jun Li
Sent: Friday, June 11, 2021 5:19 PM
To: [email protected]
Cc: [email protected]; [email protected]; [email protected]; dl-linux-imx <[email protected]>; [email protected]; [email protected]
Subject: RE: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Quoted 228 lines

-----Original Message-----
From: Jun Li <[email protected]>
Sent: Friday, May 7, 2021 2:58 PM
To: [email protected]; [email protected]; [email protected]
Cc: [email protected]; Jun Li <[email protected]>; [email protected]; [email protected]; dl-linux-imx <[email protected]>
Subject: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

From: Peter Chen <[email protected]>

This function is similar with EHCI's, but implemented using XHCI. The USB2 host needs to send SETUP packet first, then wait 15 seconds before DATA (IN) + STATUS stage.

---
Change for v3:
- No change.

Change for v2:
- No change.

drivers/usb/host/xhci-hub.c | 10 +++ drivers/usb/host/xhci-ring.c
| 123 +++++++++++++++++++++++++++++++++++

 drivers/usb/host/xhci.c      |   1 +
 drivers/usb/host/xhci.h      |  10 +++
 4 files changed, 144 insertions(+)
drivers/usb/host/xhci-hub.c +10 -0
index e9b18fc17617..c64ee95cc89b 100644
@@ -1511,6 +1511,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16
 typeReq,
 u16 wValue,
 			/* 4.19.6 Port Test Modes (USB2 Test Mode) */
 			if (hcd->speed != HCD_USB2)
 				goto error;
+
+#ifdef CONFIG_USB_HCD_TEST_MODE
+			if (test_mode == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
+				spin_unlock_irqrestore(&xhci->lock, flags);
+				retval = ehset_single_step_set_feature(hcd,
+								wIndex + 1);
+				spin_lock_irqsave(&xhci->lock, flags);
+				break;
+			}
+#endif
 			if (test_mode > USB_TEST_FORCE_ENABLE ||
drivers/usb/host/xhci-hub.c +0 -0
 			    test_mode < USB_TEST_J)
 				goto error;
(quoted diff) +0 -0

b/drivers/usb/host/xhci-ring.c index 05c38dd3ee36..87a9c1e3325a 100644

drivers/usb/host/xhci-ring.c +125 -0
@@ -3793,6 +3793,129 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci,
 gfp_t mem_flags,
 	return 0;
 }
 
+#ifdef CONFIG_USB_HCD_TEST_MODE
+/*
+ * This function prepare TRBs and submits them for the
+ * SINGLE_STEP_SET_FEATURE Test.
+ * This is done in two parts: first SETUP req for GetDesc is sent
+then
+ * 15 seconds later, the IN stage for GetDesc starts to req data from
+dev
+ *
+ * is_setup : argument decides which of the two stage needs to be
+ * performed; TRUE - SETUP and FALSE - IN+STATUS
+ * Returns 0 if success
+ */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+	struct urb *urb, int is_setup)
+{
+	int slot_id;
+	unsigned int ep_index;
+	struct xhci_ring *ep_ring;
+	int ret;
+	struct usb_ctrlrequest *setup;
+	struct xhci_generic_trb *start_trb;
+	int start_cycle;
+	u32 field, length_field, remainder;
+	struct urb_priv *urb_priv;
+	struct xhci_td *td;
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	/* urb_priv will be free after transcation has completed */
+	urb_priv = kzalloc(sizeof(struct urb_priv) +
+			sizeof(struct xhci_td), GFP_KERNEL);
+	if (!urb_priv)
+		return -ENOMEM;
+
+	td = &urb_priv->td[0];
+	urb_priv->num_tds = 1;
+	urb_priv->num_tds_done = 0;
+	urb->hcpriv = urb_priv;
+
+	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+	if (!ep_ring) {
+		ret = -EINVAL;
+		goto free_priv;
+	}
+
+	slot_id = urb->dev->slot_id;
+	ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+
+	setup = (struct usb_ctrlrequest *) urb->setup_packet;
+	if (is_setup) {
+		ret = prepare_transfer(xhci, xhci->devs[slot_id],
+				ep_index, urb->stream_id,
+				1, urb, 0, GFP_KERNEL);
+		if (ret < 0)
+			goto free_priv;
+
+		start_trb = &ep_ring->enqueue->generic;
+		start_cycle = ep_ring->cycle_state;
+		/* Save the DMA address of the last TRB in the TD */
+		td->last_trb = ep_ring->enqueue;
+		field = TRB_IOC | TRB_IDT | TRB_TYPE(TRB_SETUP) | start_cycle;
+		/* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
+		if ((xhci->hci_version >= 0x100) ||
+				(xhci->quirks & XHCI_MTK_HOST))
+			field |= TRB_TX_TYPE(TRB_DATA_IN);
+
+		queue_trb(xhci, ep_ring, false,
+			  setup->bRequestType | setup->bRequest << 8 |
+			  le16_to_cpu(setup->wValue) << 16,
+			  le16_to_cpu(setup->wIndex) |
+			  le16_to_cpu(setup->wLength) << 16,
+			  TRB_LEN(8) | TRB_INTR_TARGET(0),
+			  /* Immediate data in pointer */
+			  field);
+		giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
+				start_cycle, start_trb);
+		return 0;
+	}
+
+	ret = prepare_transfer(xhci, xhci->devs[slot_id],
+			ep_index, urb->stream_id,
+			2, urb, 0, GFP_KERNEL);
+	if (ret < 0)
+		goto free_priv;
+
+	start_trb = &ep_ring->enqueue->generic;
+	start_cycle = ep_ring->cycle_state;
+	field = TRB_ISP | TRB_TYPE(TRB_DATA);
+
+	remainder = xhci_td_remainder(xhci, 0,
+				   urb->transfer_buffer_length,
+				   urb->transfer_buffer_length,
+				   urb, 1);
+
+	length_field = TRB_LEN(urb->transfer_buffer_length) |
+		TRB_TD_SIZE(remainder) |
+		TRB_INTR_TARGET(0);
+
+	if (urb->transfer_buffer_length > 0) {
+		field |= TRB_DIR_IN;
+		queue_trb(xhci, ep_ring, true,
+				lower_32_bits(urb->transfer_dma),
+				upper_32_bits(urb->transfer_dma),
+				length_field,
+				field | ep_ring->cycle_state);
+	}
+
+	td->last_trb = ep_ring->enqueue;
+	field = TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
+	queue_trb(xhci, ep_ring, false,
+			0,
+			0,
+			TRB_INTR_TARGET(0),
+			field);
+
+	giveback_first_trb(xhci, slot_id, ep_index, 0,
+			start_cycle, start_trb);
+
+	return 0;
+free_priv:
+	xhci_urb_free_priv(urb_priv);
+	return ret;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
 /*
  * The transfer burst count field of the isochronous TRB defines the

number of
* bursts that are required to move all packets in this TD. Only
SuperSpeed diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ca9385d22f68..a27616775845 100644

drivers/usb/host/xhci.c +1 -0
@@ -5426,6 +5426,7 @@ static const struct hc_driver xhci_hc_driver = {
 	.disable_usb3_lpm_timeout =	xhci_disable_usb3_lpm_timeout,
 	.find_raw_port_number =	xhci_find_raw_port_number,
 	.clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
+	.submit_single_step_set_feature	=
 xhci_submit_single_step_set_feature,
 };
 

void xhci_init_driver(struct hc_driver *drv, diff --git
a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2595a8f057c4..f93fc8f59af6 100644

drivers/usb/host/xhci.h +10 -0
@@ -2165,6 +2165,16 @@ int xhci_find_raw_port_number(struct usb_hcd
 *hcd, int port1);  struct xhci_hub *xhci_get_rhub(struct usb_hcd
 *hcd);
 
 void xhci_hc_died(struct xhci_hcd *xhci);
+#ifdef CONFIG_USB_HCD_TEST_MODE
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+	struct urb *urb, int is_setup);
+#else
+static inline int xhci_submit_single_step_set_feature(struct usb_hcd
 *hcd,
+	struct urb *urb, int is_setup)
+{
+	return 0;
+}
+#endif
 
Quoted 6 lines
Quoted 4 lines

#ifdef CONFIG_PM
int xhci_bus_suspend(struct usb_hcd *hcd);
--
2.25.1

A gentle ping.

Could you please take a look this patch?

Thanks

Quoted 1 line

Li Jun

#4 lore raw

Re: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Hi

Quoted 14 lines · Jun Li

Hi Mathias,

Quoted 12 lines

-----Original Message-----
From: Jun Li
Sent: Friday, June 11, 2021 5:19 PM
To: [email protected]
Cc: [email protected]; [email protected]; [email protected]; dl-linux-imx <[email protected]>; [email protected]; [email protected]
Subject: RE: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Quoted 3 lines
Quoted 1 line
Quoted 1 line

A gentle ping.

Could you please take a look this patch?

This somehow fell through the cracks, sorry.

I'll be away for two weeks so this will unfortunately be delayed even more. Sorry about this.

-Mathias

author
#5 lore raw

RE: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Hi Mathias,

Quoted 27 lines

-----Original Message-----
From: Mathias Nyman <[email protected]>
Sent: Friday, July 16, 2021 10:35 PM
To: Jun Li <[email protected]>; [email protected]
Cc: [email protected]; [email protected]; [email protected]; dl-linux-imx <[email protected]>; [email protected]; [email protected]
Subject: Re: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Hi

Quoted 14 lines · Jun Li

Hi Mathias,

Quoted 12 lines

-----Original Message-----
From: Jun Li
Sent: Friday, June 11, 2021 5:19 PM
To: [email protected]
Cc: [email protected]; [email protected]; [email protected]; dl-linux-imx <[email protected]>; [email protected]; [email protected]
Subject: RE: [PATCH v3 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2

Quoted 8 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line

A gentle ping.

Could you please take a look this patch?

This somehow fell through the cracks, sorry.

I'll be away for two weeks so this will unfortunately be delayed even more. Sorry about this.

Seems this patch is still missed, ping again.

Li Jun

Quoted 3 lines

-Mathias

author
#6 lore raw

PATCH v3 3/3 usb: core: hcd: use map_urb_for_dma for single step set feature urb

In reply to Li Jun

Use map_urb_for_dma() to improve the dma map code for single step set feature request urb in test mode.

---
Change for v3:
- Correct the error handling if map_urb_for_dma() fails.

change for v2:
- Add this new patch to use map_urb_for_dma API to replace both of dma_map_single() calls, suggested by Jack Pham.

 drivers/usb/core/hcd.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
drivers/usb/core/hcd.c +5 -10
index d7eb9f179ca6..fa72697f4829 100644
@@ -2159,16 +2159,11 @@ static struct urb *request_single_step_set_feature_urb(
 	usb_get_urb(urb);
 	atomic_inc(&urb->use_count);
 	atomic_inc(&urb->dev->urbnum);
-	urb->setup_dma = dma_map_single(
-			hcd->self.sysdev,
-			urb->setup_packet,
-			sizeof(struct usb_ctrlrequest),
-			DMA_TO_DEVICE);
-	urb->transfer_dma = dma_map_single(
-			hcd->self.sysdev,
-			urb->transfer_buffer,
-			urb->transfer_buffer_length,
-			DMA_FROM_DEVICE);
+	if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) {
+		usb_put_urb(urb);
+		return NULL;
+	}
+
 	urb->context = done;
 	return urb;
 }
Signature · 1 line
2.25.1
maintainer
#7 lore raw

Re: [PATCH v3 3/3] usb: core: hcd: use map_urb_for_dma for single step set feature urb

Quoted 26 lines · Li Jun

Use map_urb_for_dma() to improve the dma map code for single step set feature request urb in test mode.

---
Change for v3:
- Correct the error handling if map_urb_for_dma() fails.

change for v2:
- Add this new patch to use map_urb_for_dma API to replace both of dma_map_single() calls, suggested by Jack Pham.

 drivers/usb/core/hcd.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
drivers/usb/core/hcd.c +0 -2
index d7eb9f179ca6..fa72697f4829 100644
@@ -2159,16 +2159,11 @@ static struct urb *request_single_step_set_feature_urb(
 	usb_get_urb(urb);
 	atomic_inc(&urb->use_count);
 	atomic_inc(&urb->dev->urbnum);
-	urb->setup_dma = dma_map_single(
-			hcd->self.sysdev,

drivers/usb/core/hcd.c static struct urb *request_single_step_set_feature_urb( · line 2163

Quoted 10 lines
drivers/usb/core/hcd.c +2 -8
-			urb->setup_packet,
-			sizeof(struct usb_ctrlrequest),
-			DMA_TO_DEVICE);
-	urb->transfer_dma = dma_map_single(
-			hcd->self.sysdev,
-			urb->transfer_buffer,
-			urb->transfer_buffer_length,
-			DMA_FROM_DEVICE);
+	if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) {
+		usb_put_urb(urb);

You need to call usb_free_urb() here.

Alan Stern

Quoted 9 lines
drivers/usb/core/hcd.c +3 -0
+		return NULL;
+	}
+
 	urb->context = done;
 	return urb;
 }
Signature · 1 line
2.25.1
#8 lore raw

Re: [PATCH v3 3/3] usb: core: hcd: use map_urb_for_dma for single step set feature urb

Quoted 31 lines · Alan Stern
Quoted 30 lines · Li Jun

Use map_urb_for_dma() to improve the dma map code for single step set feature request urb in test mode.

---
Change for v3:
- Correct the error handling if map_urb_for_dma() fails.

change for v2:
- Add this new patch to use map_urb_for_dma API to replace both of dma_map_single() calls, suggested by Jack Pham.

 drivers/usb/core/hcd.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
drivers/usb/core/hcd.c +0 -6
index d7eb9f179ca6..fa72697f4829 100644
@@ -2159,16 +2159,11 @@ static struct urb *request_single_step_set_feature_urb(
 	usb_get_urb(urb);
 	atomic_inc(&urb->use_count);
 	atomic_inc(&urb->dev->urbnum);
-	urb->setup_dma = dma_map_single(
-			hcd->self.sysdev,
-			urb->setup_packet,
-			sizeof(struct usb_ctrlrequest),
-			DMA_TO_DEVICE);
-	urb->transfer_dma = dma_map_single(
Quoted 8 lines

drivers/usb/core/hcd.c static struct urb *request_single_step_set_feature_urb( · line 2163

Quoted 6 lines
drivers/usb/core/hcd.c +2 -4
-			hcd->self.sysdev,
-			urb->transfer_buffer,
-			urb->transfer_buffer_length,
-			DMA_FROM_DEVICE);
+	if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) {
+		usb_put_urb(urb);

You need to call usb_free_urb() here.

Hi Alan,

Aren't usb_put_urb() and usb_free_urb() identical? The former appears to just be a macro subsitution of the latter.

Jack

Quoted 9 lines
Quoted 9 lines
drivers/usb/core/hcd.c +3 -0
+		return NULL;
+	}
+
 	urb->context = done;
 	return urb;
 }
Signature · 1 line
2.25.1
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
maintainer
#9 lore raw

Re: [PATCH v3 3/3] usb: core: hcd: use map_urb_for_dma for single step set feature urb

Quoted 41 lines · Jack Pham
Quoted 31 lines · Alan Stern
Quoted 30 lines · Li Jun

Use map_urb_for_dma() to improve the dma map code for single step set feature request urb in test mode.

---
Change for v3:
- Correct the error handling if map_urb_for_dma() fails.

change for v2:
- Add this new patch to use map_urb_for_dma API to replace both of dma_map_single() calls, suggested by Jack Pham.

 drivers/usb/core/hcd.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
drivers/usb/core/hcd.c +0 -6
index d7eb9f179ca6..fa72697f4829 100644
@@ -2159,16 +2159,11 @@ static struct urb *request_single_step_set_feature_urb(
 	usb_get_urb(urb);
 	atomic_inc(&urb->use_count);
 	atomic_inc(&urb->dev->urbnum);
-	urb->setup_dma = dma_map_single(
-			hcd->self.sysdev,
-			urb->setup_packet,
-			sizeof(struct usb_ctrlrequest),
-			DMA_TO_DEVICE);
-	urb->transfer_dma = dma_map_single(
Quoted 8 lines

drivers/usb/core/hcd.c static struct urb *request_single_step_set_feature_urb( · line 2163

Quoted 6 lines
drivers/usb/core/hcd.c +2 -4
-			hcd->self.sysdev,
-			urb->transfer_buffer,
-			urb->transfer_buffer_length,
-			DMA_FROM_DEVICE);
+	if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) {
+		usb_put_urb(urb);

You need to call usb_free_urb() here.

Quoted 4 lines

Hi Alan,

Aren't usb_put_urb() and usb_free_urb() identical? The former appears to just be a macro subsitution of the latter.

Yes, they are identical, although that's more or less an historical accident. usb_free_urb was written before the refcount API came along.

The usb_put_urb() call here undoes the usb_get_urb() call at the top of the patch. You still need one more call to decrease the refcount to 0.

Alan Stern