All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/11] usb: dwc3: gadget: Handle streams
@ 2020-05-06  2:46 Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 01/11] usb: gadget: Introduce usb_request->is_last Thinh Nguyen
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

Overview of stream transfer requirement:
 * A transfer will have a set of TRBs of the same stream ID.
 * A transfer is started with a stream ID in START_TRANSFER command.
 * A new stream will only start when the previous completes.

Overview of stream events:
 * A "prime" from host indicates that its endpoints are active
   (buffers prepared and ready to receive/transmit data). The controller
   automatically initiates stream if it sees this.
 * A "NoStream" rejection event indicates that the host isn't ready.
   Host will put the endpoint back to idle state. Device may need to
   reinitiate the stream to start transfer again.
 * A Stream Found event means host accepted device initiated stream.
   Nothing needs to be done from driver.

To initiate a stream, the driver will issue START_TRANSFER command with a
stream ID. To reinitiate the stream, the driver must issue END_TRANSFER and
restart the transfer with START_TRANSFER command with the same stream ID.

This implementation handles device-initated streams (e.g. UASP driver).  It
also handles some hosts' quirky behavior where they only prime each endpoint
once.

Prerequisite:
  This series requires DWC_usb32 patch series
  https://patchwork.kernel.org/project/linux-usb/list/?series=269641

  [PATCH 1/2] usb: dwc3: Add support for DWC_usb32 IP
  [PATCH 2/2] usb: dwc3: Get MDWIDTH for DWC_usb32


Changes in v2:
 - Update cover letter
 - Split handling of stream and of transfer completion into smaller patches
 - Reword usb_request->is_last to strictly use for streams
 - Enforce transfer completion handling to only for stream capable endpoints


Thinh Nguyen (11):
  usb: gadget: Introduce usb_request->is_last
  usb: gadget: f_tcm: Inform last stream request
  usb: dwc3: gadget: Continue to process pending requests
  usb: dwc3: gadget: Check for in-progress END_TRANSFER
  usb: dwc3: gadget: Refactor TRB completion handler
  usb: dwc3: gadget: Enable XferComplete event
  usb: dwc3: gadget: Handle XferComplete for streams
  usb: dwc3: gadget: Wait for transfer completion
  usb: dwc3: gadget: Don't prepare beyond a transfer
  usb: dwc3: gadget: Handle stream transfers
  usb: dwc3: gadget: Use SET_EP_PRIME for NoStream

 drivers/usb/dwc3/core.h             |  12 ++
 drivers/usb/dwc3/debug.h            |   2 +
 drivers/usb/dwc3/gadget.c           | 225 +++++++++++++++++++++++++++++++-----
 drivers/usb/gadget/function/f_tcm.c |   3 +
 include/linux/usb/gadget.h          |   3 +
 5 files changed, 215 insertions(+), 30 deletions(-)

-- 
2.11.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 01/11] usb: gadget: Introduce usb_request->is_last
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 02/11] usb: gadget: f_tcm: Inform last stream request Thinh Nguyen
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

To take advantage of DWC3 internal TRB prefetch and cache for
performance, inform the controller the last request with stream_id
before switching to a different stream transfer. This allows the
controller to maintain its transfer burst within the stream ID.

Introduce the usb-request is_last field to help inform the DWC3
controller of this.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 include/linux/usb/gadget.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index e959c09a97c9..281eabae7f33 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -42,6 +42,8 @@ struct usb_ep;
  * @num_mapped_sgs: number of SG entries mapped to DMA (internal)
  * @length: Length of that data
  * @stream_id: The stream id, when USB3.0 bulk streams are being used
+ * @is_last: Indicates if this is the last request of a stream_id before
+ *	switching to a different stream (required for DWC3 controllers).
  * @no_interrupt: If true, hints that no completion irq is needed.
  *	Helpful sometimes with deep request queues that are handled
  *	directly by DMA controllers.
@@ -104,6 +106,7 @@ struct usb_request {
 	unsigned		num_mapped_sgs;
 
 	unsigned		stream_id:16;
+	unsigned		is_last:1;
 	unsigned		no_interrupt:1;
 	unsigned		zero:1;
 	unsigned		short_not_ok:1;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 02/11] usb: gadget: f_tcm: Inform last stream request
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 01/11] usb: gadget: Introduce usb_request->is_last Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 03/11] usb: dwc3: gadget: Continue to process pending requests Thinh Nguyen
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

Set the request->is_last to each stream request to indicate that the
request is the last stream request of a transfer. The DWC3 controller
needs to know this info to properly switch streams. The current
implementation of f_tcm uses a single request per transfer, so every
stream request is the last of its stream.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/gadget/function/f_tcm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 36504931b2d1..2979cbe4d95f 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -531,6 +531,7 @@ static int uasp_prepare_r_request(struct usbg_cmd *cmd)
 		stream->req_in->sg = se_cmd->t_data_sg;
 	}
 
+	stream->req_in->is_last = 1;
 	stream->req_in->complete = uasp_status_data_cmpl;
 	stream->req_in->length = se_cmd->data_length;
 	stream->req_in->context = cmd;
@@ -554,6 +555,7 @@ static void uasp_prepare_status(struct usbg_cmd *cmd)
 	 */
 	iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
 	iu->status = se_cmd->scsi_status;
+	stream->req_status->is_last = 1;
 	stream->req_status->context = cmd;
 	stream->req_status->length = se_cmd->scsi_sense_length + 16;
 	stream->req_status->buf = iu;
@@ -991,6 +993,7 @@ static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
 		req->sg = se_cmd->t_data_sg;
 	}
 
+	req->is_last = 1;
 	req->complete = usbg_data_write_cmpl;
 	req->length = se_cmd->data_length;
 	req->context = cmd;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 03/11] usb: dwc3: gadget: Continue to process pending requests
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 01/11] usb: gadget: Introduce usb_request->is_last Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 02/11] usb: gadget: f_tcm: Inform last stream request Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 04/11] usb: dwc3: gadget: Check for in-progress END_TRANSFER Thinh Nguyen
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

If there are still pending requests because no TRB was available,
prepare more when started requests are completed.

Introduce dwc3_gadget_ep_should_continue() to check for incomplete and
pending requests to resume updating new TRBs to the controller's TRB
cache.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/gadget.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 4ca3e197bee4..865e6fbb7360 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2605,10 +2605,8 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
 
 	req->request.actual = req->request.length - req->remaining;
 
-	if (!dwc3_gadget_ep_request_completed(req)) {
-		__dwc3_gadget_kick_transfer(dep);
+	if (!dwc3_gadget_ep_request_completed(req))
 		goto out;
-	}
 
 	dwc3_gadget_giveback(dep, req, status);
 
@@ -2632,6 +2630,24 @@ static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep,
 	}
 }
 
+static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep)
+{
+	struct dwc3_request	*req;
+
+	if (!list_empty(&dep->pending_list))
+		return true;
+
+	/*
+	 * We only need to check the first entry of the started list. We can
+	 * assume the completed requests are removed from the started list.
+	 */
+	req = next_request(&dep->started_list);
+	if (!req)
+		return false;
+
+	return !dwc3_gadget_ep_request_completed(req);
+}
+
 static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep,
 		const struct dwc3_event_depevt *event)
 {
@@ -2661,6 +2677,8 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
 
 	if (stop)
 		dwc3_stop_active_transfer(dep, true, true);
+	else if (dwc3_gadget_ep_should_continue(dep))
+		__dwc3_gadget_kick_transfer(dep);
 
 	/*
 	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 04/11] usb: dwc3: gadget: Check for in-progress END_TRANSFER
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (2 preceding siblings ...)
  2020-05-06  2:46 ` [PATCH v2 03/11] usb: dwc3: gadget: Continue to process pending requests Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 05/11] usb: dwc3: gadget: Refactor TRB completion handler Thinh Nguyen
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

While handling TRBs completion, if a END_TRANSFER command isn't
completed, don't kick new transfer or issue END_TRANSFER command.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/gadget.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 865e6fbb7360..3bb6f847a865 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2675,11 +2675,15 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
 
 	dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
 
+	if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
+		goto out;
+
 	if (stop)
 		dwc3_stop_active_transfer(dep, true, true);
 	else if (dwc3_gadget_ep_should_continue(dep))
 		__dwc3_gadget_kick_transfer(dep);
 
+out:
 	/*
 	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
 	 * See dwc3_gadget_linksts_change_interrupt() for 1st half.
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 05/11] usb: dwc3: gadget: Refactor TRB completion handler
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (3 preceding siblings ...)
  2020-05-06  2:46 ` [PATCH v2 04/11] usb: dwc3: gadget: Check for in-progress END_TRANSFER Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 06/11] usb: dwc3: gadget: Enable XferComplete event Thinh Nguyen
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

To prepare for handling of XferComplete event, let's refactor and split
up dwc3_gadget_endpoint_transfer_in_progress() to handle TRBs completion
for different events. The handling of TRBs completion will be the same,
but the status of XferComplete event is different than XferInProgress.
No functional change in this commit.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/gadget.c | 45 ++++++++++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3bb6f847a865..5f98b424f20b 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2654,34 +2654,22 @@ static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep,
 	dep->frame_number = event->parameters;
 }
 
-static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
-		const struct dwc3_event_depevt *event)
+static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event, int status)
 {
 	struct dwc3		*dwc = dep->dwc;
-	unsigned		status = 0;
-	bool			stop = false;
-
-	dwc3_gadget_endpoint_frame_from_event(dep, event);
-
-	if (event->status & DEPEVT_STATUS_BUSERR)
-		status = -ECONNRESET;
-
-	if (event->status & DEPEVT_STATUS_MISSED_ISOC) {
-		status = -EXDEV;
-
-		if (list_empty(&dep->started_list))
-			stop = true;
-	}
+	bool			no_started_trb = true;
 
 	dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
 
 	if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
 		goto out;
 
-	if (stop)
+	if (status == -EXDEV && list_empty(&dep->started_list))
 		dwc3_stop_active_transfer(dep, true, true);
 	else if (dwc3_gadget_ep_should_continue(dep))
-		__dwc3_gadget_kick_transfer(dep);
+		if (__dwc3_gadget_kick_transfer(dep) == 0)
+			no_started_trb = false;
 
 out:
 	/*
@@ -2699,7 +2687,7 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
 				continue;
 
 			if (!list_empty(&dep->started_list))
-				return;
+				return no_started_trb;
 		}
 
 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
@@ -2708,6 +2696,25 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
 
 		dwc->u1u2 = 0;
 	}
+
+	return no_started_trb;
+}
+
+static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	int status = 0;
+
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		dwc3_gadget_endpoint_frame_from_event(dep, event);
+
+	if (event->status & DEPEVT_STATUS_BUSERR)
+		status = -ECONNRESET;
+
+	if (event->status & DEPEVT_STATUS_MISSED_ISOC)
+		status = -EXDEV;
+
+	dwc3_gadget_endpoint_trbs_complete(dep, event, status);
 }
 
 static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 06/11] usb: dwc3: gadget: Enable XferComplete event
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (4 preceding siblings ...)
  2020-05-06  2:46 ` [PATCH v2 05/11] usb: dwc3: gadget: Refactor TRB completion handler Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 07/11] usb: dwc3: gadget: Handle XferComplete for streams Thinh Nguyen
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

To switch from one stream to another, this requires the driver to start
a new transfer with a specific stream ID. For a transfer to complete,
the driver needs to indicate the last TRB of a transfer, and it needs to
enable XferComplete event to handle completed TRBs of a transfer. Let's
enable this event only for stream capable endpoints.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/gadget.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5f98b424f20b..81aa7de4cb17 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -579,6 +579,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
 
 	if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
 		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
+			| DWC3_DEPCFG_XFER_COMPLETE_EN
 			| DWC3_DEPCFG_STREAM_EVENT_EN;
 		dep->stream_capable = true;
 	}
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 07/11] usb: dwc3: gadget: Handle XferComplete for streams
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (5 preceding siblings ...)
  2020-05-06  2:46 ` [PATCH v2 06/11] usb: dwc3: gadget: Enable XferComplete event Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:46 ` [PATCH v2 08/11] usb: dwc3: gadget: Wait for transfer completion Thinh Nguyen
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

In DWC3, to prepare TRBs for streams, all the TRBs of a transfer will
use the same stream ID. To start a new stream, the driver needs to wait
for the current transfer to complete or ended (by END_TRANFER command).
As a result, inform the controller of the last TRB of a transfer so that
it knows when a transfer completes and start a new transfer of a new
stream.

Even though the transfer completion handling can be applied for other
non-isoc endpoints, only do it for streams due to its requirement.
It's better to keep the controller's TRB cache full than waiting for
transfer completion and starting a new transfer.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/gadget.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 81aa7de4cb17..052f6dc52a51 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -919,7 +919,8 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
 
 static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
 		dma_addr_t dma, unsigned length, unsigned chain, unsigned node,
-		unsigned stream_id, unsigned short_not_ok, unsigned no_interrupt)
+		unsigned stream_id, unsigned short_not_ok,
+		unsigned no_interrupt, unsigned is_last)
 {
 	struct dwc3		*dwc = dep->dwc;
 	struct usb_gadget	*gadget = &dwc->gadget;
@@ -1012,6 +1013,8 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
 
 	if (chain)
 		trb->ctrl |= DWC3_TRB_CTRL_CHN;
+	else if (dep->stream_capable && is_last)
+		trb->ctrl |= DWC3_TRB_CTRL_LST;
 
 	if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
 		trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id);
@@ -1039,6 +1042,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 	unsigned		stream_id = req->request.stream_id;
 	unsigned		short_not_ok = req->request.short_not_ok;
 	unsigned		no_interrupt = req->request.no_interrupt;
+	unsigned		is_last = req->request.is_last;
 
 	if (req->request.num_sgs > 0) {
 		length = sg_dma_len(req->start_sg);
@@ -1059,7 +1063,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 	req->num_trbs++;
 
 	__dwc3_prepare_one_trb(dep, trb, dma, length, chain, node,
-			stream_id, short_not_ok, no_interrupt);
+			stream_id, short_not_ok, no_interrupt, is_last);
 }
 
 static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
@@ -1104,7 +1108,8 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
 					maxp - rem, false, 1,
 					req->request.stream_id,
 					req->request.short_not_ok,
-					req->request.no_interrupt);
+					req->request.no_interrupt,
+					req->request.is_last);
 		} else {
 			dwc3_prepare_one_trb(dep, req, chain, i);
 		}
@@ -1148,7 +1153,8 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
 		__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem,
 				false, 1, req->request.stream_id,
 				req->request.short_not_ok,
-				req->request.no_interrupt);
+				req->request.no_interrupt,
+				req->request.is_last);
 	} else if (req->request.zero && req->request.length &&
 		   (IS_ALIGNED(req->request.length, maxp))) {
 		struct dwc3	*dwc = dep->dwc;
@@ -1165,7 +1171,8 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
 		__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
 				false, 1, req->request.stream_id,
 				req->request.short_not_ok,
-				req->request.no_interrupt);
+				req->request.no_interrupt,
+				req->request.is_last);
 	} else {
 		dwc3_prepare_one_trb(dep, req, false, 0);
 	}
@@ -2718,6 +2725,19 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
 	dwc3_gadget_endpoint_trbs_complete(dep, event, status);
 }
 
+static void dwc3_gadget_endpoint_transfer_complete(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	int status = 0;
+
+	dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
+
+	if (event->status & DEPEVT_STATUS_BUSERR)
+		status = -ECONNRESET;
+
+	dwc3_gadget_endpoint_trbs_complete(dep, event, status);
+}
+
 static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
 		const struct dwc3_event_depevt *event)
 {
@@ -2781,8 +2801,10 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 			dep->flags &= ~DWC3_EP_DELAY_START;
 		}
 		break;
-	case DWC3_DEPEVT_STREAMEVT:
 	case DWC3_DEPEVT_XFERCOMPLETE:
+		dwc3_gadget_endpoint_transfer_complete(dep, event);
+		break;
+	case DWC3_DEPEVT_STREAMEVT:
 	case DWC3_DEPEVT_RXTXFIFOEVT:
 		break;
 	}
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 08/11] usb: dwc3: gadget: Wait for transfer completion
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (6 preceding siblings ...)
  2020-05-06  2:46 ` [PATCH v2 07/11] usb: dwc3: gadget: Handle XferComplete for streams Thinh Nguyen
@ 2020-05-06  2:46 ` Thinh Nguyen
  2020-05-06  2:47 ` [PATCH v2 09/11] usb: dwc3: gadget: Don't prepare beyond a transfer Thinh Nguyen
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:46 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

If a transfer is in-progress, any new request should not kick off
another transfer. The driver needs to wait for the current transfer to
complete before starting off the next transfer. Introduce a new flag
DWC3_EP_WAIT_TRANSFER_COMPLETE for this.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/core.h   | 1 +
 drivers/usb/dwc3/gadget.c | 9 ++++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7204a838ec06..b11183a715a7 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -701,6 +701,7 @@ struct dwc3_ep {
 #define DWC3_EP_END_TRANSFER_PENDING BIT(4)
 #define DWC3_EP_PENDING_REQUEST	BIT(5)
 #define DWC3_EP_DELAY_START	BIT(6)
+#define DWC3_EP_WAIT_TRANSFER_COMPLETE	BIT(7)
 
 	/* This last one is specific to EP0 */
 #define DWC3_EP0_DIR_IN		BIT(31)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 052f6dc52a51..97c6a5785725 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1292,6 +1292,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
 		return ret;
 	}
 
+	if (dep->stream_capable && req->request.is_last)
+		dep->flags |= DWC3_EP_WAIT_TRANSFER_COMPLETE;
+
 	return 0;
 }
 
@@ -1498,6 +1501,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 	list_add_tail(&req->list, &dep->pending_list);
 	req->status = DWC3_REQUEST_STATUS_QUEUED;
 
+	if (dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE)
+		return 0;
+
 	/* Start the transfer only after the END_TRANSFER is completed */
 	if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) {
 		dep->flags |= DWC3_EP_DELAY_START;
@@ -2735,7 +2741,8 @@ static void dwc3_gadget_endpoint_transfer_complete(struct dwc3_ep *dep,
 	if (event->status & DEPEVT_STATUS_BUSERR)
 		status = -ECONNRESET;
 
-	dwc3_gadget_endpoint_trbs_complete(dep, event, status);
+	if (dwc3_gadget_endpoint_trbs_complete(dep, event, status))
+		dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE;
 }
 
 static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 09/11] usb: dwc3: gadget: Don't prepare beyond a transfer
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (7 preceding siblings ...)
  2020-05-06  2:46 ` [PATCH v2 08/11] usb: dwc3: gadget: Wait for transfer completion Thinh Nguyen
@ 2020-05-06  2:47 ` Thinh Nguyen
  2020-05-06  2:47 ` [PATCH v2 10/11] usb: dwc3: gadget: Handle stream transfers Thinh Nguyen
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:47 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

Don't prepare TRBs beyond a transfer. In DWC_usb32, its transfer burst
capability may try to read and use TRBs beyond the active transfer. For
other controllers, they don't process the next transfer TRBs until the
current transfer is completed. Explicitly prevent preparing TRBs ahead
for all controllers.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/gadget.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 97c6a5785725..07824b670440 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1231,6 +1231,14 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
 
 		if (!dwc3_calc_trbs_left(dep))
 			return;
+
+		/*
+		 * Don't prepare beyond a transfer. In DWC_usb32, its transfer
+		 * burst capability may try to read and use TRBs beyond the
+		 * active transfer instead of stopping.
+		 */
+		if (dep->stream_capable && req->request.is_last)
+			return;
 	}
 }
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 10/11] usb: dwc3: gadget: Handle stream transfers
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (8 preceding siblings ...)
  2020-05-06  2:47 ` [PATCH v2 09/11] usb: dwc3: gadget: Don't prepare beyond a transfer Thinh Nguyen
@ 2020-05-06  2:47 ` Thinh Nguyen
  2020-05-06  2:47 ` [PATCH v2 11/11] usb: dwc3: gadget: Use SET_EP_PRIME for NoStream Thinh Nguyen
  2020-05-14 10:43 ` [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Felipe Balbi
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:47 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

Overview of stream transfer requirement:
 * A transfer will have a set of TRBs of the same stream ID.
 * A transfer is started with a stream ID in START_TRANSFER command.
 * A new stream will only start when the previous completes.

Overview of stream events:
 * A "prime" from host indicates that its endpoints are active
   (buffers prepared and ready to receive/transmit data). The controller
   automatically initiates stream if it sees this.
 * A "NoStream" rejection event indicates that the host isn't ready.
   Host will put the endpoint back to idle state. Device may need to
   reinitiate the stream to start transfer again.
 * A Stream Found event means host accepted device initiated stream.
   Nothing needs to be done from driver.

To initiate a stream, the driver will issue START_TRANSFER command with
a stream ID. To reinitiate the stream, the driver must issue
END_TRANSFER and restart the transfer with START_TRANSFER command with
the same stream ID.

This implementation handles device-initated streams (e.g. UASP driver).
It also handles some hosts' quirky behavior where they only prime each
endpoint once.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/core.h   |  8 ++++
 drivers/usb/dwc3/debug.h  |  2 +
 drivers/usb/dwc3/gadget.c | 97 +++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b11183a715a7..4def088329c7 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -495,6 +495,7 @@
 #define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
 #define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
 #define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
+#define DWC3_DGCMD_SET_ENDPOINT_PRIME	0x0d
 #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
 
 #define DWC3_DGCMD_STATUS(n)		(((n) >> 12) & 0x0F)
@@ -702,6 +703,9 @@ struct dwc3_ep {
 #define DWC3_EP_PENDING_REQUEST	BIT(5)
 #define DWC3_EP_DELAY_START	BIT(6)
 #define DWC3_EP_WAIT_TRANSFER_COMPLETE	BIT(7)
+#define DWC3_EP_IGNORE_NEXT_NOSTREAM	BIT(8)
+#define DWC3_EP_FORCE_RESTART_STREAM	BIT(9)
+#define DWC3_EP_FIRST_STREAM_PRIMED	BIT(10)
 
 	/* This last one is specific to EP0 */
 #define DWC3_EP0_DIR_IN		BIT(31)
@@ -1301,6 +1305,10 @@ struct dwc3_event_depevt {
 #define DEPEVT_STREAMEVT_FOUND		1
 #define DEPEVT_STREAMEVT_NOTFOUND	2
 
+/* Stream event parameter */
+#define DEPEVT_STREAM_PRIME		0xfffe
+#define DEPEVT_STREAM_NOSTREAM		0x0
+
 /* Control-only Status */
 #define DEPEVT_STATUS_CONTROL_DATA	1
 #define DEPEVT_STATUS_CONTROL_STATUS	2
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 0f95656c9622..d8f600e0e88f 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -68,6 +68,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd)
 		return "All FIFO Flush";
 	case DWC3_DGCMD_SET_ENDPOINT_NRDY:
 		return "Set Endpoint NRDY";
+	case DWC3_DGCMD_SET_ENDPOINT_PRIME:
+		return "Set Endpoint Prime";
 	case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
 		return "Run SoC Bus Loopback Test";
 	default:
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 07824b670440..0380f76151a1 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -610,6 +610,9 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
 	return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
 }
 
+static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
+		bool interrupt);
+
 /**
  * __dwc3_gadget_ep_enable - initializes a hw endpoint
  * @dep: endpoint to be initialized
@@ -670,7 +673,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
 	 * Issue StartTransfer here with no-op TRB so we can always rely on No
 	 * Response Update Transfer command.
 	 */
-	if ((usb_endpoint_xfer_bulk(desc) && !dep->stream_capable) ||
+	if (usb_endpoint_xfer_bulk(desc) ||
 			usb_endpoint_xfer_int(desc)) {
 		struct dwc3_gadget_ep_cmd_params params;
 		struct dwc3_trb	*trb;
@@ -689,6 +692,29 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
 		ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
 		if (ret < 0)
 			return ret;
+
+		if (dep->stream_capable) {
+			/*
+			 * For streams, at start, there maybe a race where the
+			 * host primes the endpoint before the function driver
+			 * queues a request to initiate a stream. In that case,
+			 * the controller will not see the prime to generate the
+			 * ERDY and start stream. To workaround this, issue a
+			 * no-op TRB as normal, but end it immediately. As a
+			 * result, when the function driver queues the request,
+			 * the next START_TRANSFER command will cause the
+			 * controller to generate an ERDY to initiate the
+			 * stream.
+			 */
+			dwc3_stop_active_transfer(dep, true, true);
+
+			/*
+			 * All stream eps will reinitiate stream on NoStream
+			 * rejection until we can determine that the host can
+			 * prime after the first transfer.
+			 */
+			dep->flags |= DWC3_EP_FORCE_RESTART_STREAM;
+		}
 	}
 
 out:
@@ -697,8 +723,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
 	return 0;
 }
 
-static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
-		bool interrupt);
 static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
 	struct dwc3_request		*req;
@@ -2772,6 +2796,63 @@ static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
 	(void) __dwc3_gadget_start_isoc(dep);
 }
 
+static void dwc3_gadget_endpoint_stream_event(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3 *dwc = dep->dwc;
+
+	if (event->status == DEPEVT_STREAMEVT_FOUND) {
+		dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED;
+		goto out;
+	}
+
+	/* Note: NoStream rejection event param value is 0 and not 0xFFFF */
+	switch (event->parameters) {
+	case DEPEVT_STREAM_PRIME:
+		/*
+		 * If the host can properly transition the endpoint state from
+		 * idle to prime after a NoStream rejection, there's no need to
+		 * force restarting the endpoint to reinitiate the stream. To
+		 * simplify the check, assume the host follows the USB spec if
+		 * it primed the endpoint more than once.
+		 */
+		if (dep->flags & DWC3_EP_FORCE_RESTART_STREAM) {
+			if (dep->flags & DWC3_EP_FIRST_STREAM_PRIMED)
+				dep->flags &= ~DWC3_EP_FORCE_RESTART_STREAM;
+			else
+				dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED;
+		}
+
+		break;
+	case DEPEVT_STREAM_NOSTREAM:
+		if ((dep->flags & DWC3_EP_IGNORE_NEXT_NOSTREAM) ||
+		    !(dep->flags & DWC3_EP_FORCE_RESTART_STREAM) ||
+		    !(dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE))
+			break;
+
+		/*
+		 * If the host rejects a stream due to no active stream, by the
+		 * USB and xHCI spec, the endpoint will be put back to idle
+		 * state. When the host is ready (buffer added/updated), it will
+		 * prime the endpoint to inform the usb device controller. This
+		 * triggers the device controller to issue ERDY to restart the
+		 * stream. However, some hosts don't follow this and keep the
+		 * endpoint in the idle state. No prime will come despite host
+		 * streams are updated, and the device controller will not be
+		 * triggered to generate ERDY to move the next stream data. To
+		 * workaround this and maintain compatibility with various
+		 * hosts, force to reinitate the stream until the host is ready
+		 * instead of waiting for the host to prime the endpoint.
+		 */
+		dep->flags |= DWC3_EP_DELAY_START;
+		dwc3_stop_active_transfer(dep, true, true);
+		return;
+	}
+
+out:
+	dep->flags &= ~DWC3_EP_IGNORE_NEXT_NOSTREAM;
+}
+
 static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 {
@@ -2820,6 +2901,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 		dwc3_gadget_endpoint_transfer_complete(dep, event);
 		break;
 	case DWC3_DEPEVT_STREAMEVT:
+		dwc3_gadget_endpoint_stream_event(dep, event);
+		break;
 	case DWC3_DEPEVT_RXTXFIFOEVT:
 		break;
 	}
@@ -2911,6 +2994,14 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
 	WARN_ON_ONCE(ret);
 	dep->resource_index = 0;
 
+	/*
+	 * The END_TRANSFER command will cause the controller to generate a
+	 * NoStream Event, and it's not due to the host DP NoStream rejection.
+	 * Ignore the next NoStream event.
+	 */
+	if (dep->stream_capable)
+		dep->flags |= DWC3_EP_IGNORE_NEXT_NOSTREAM;
+
 	if (!interrupt)
 		dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
 	else
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 11/11] usb: dwc3: gadget: Use SET_EP_PRIME for NoStream
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (9 preceding siblings ...)
  2020-05-06  2:47 ` [PATCH v2 10/11] usb: dwc3: gadget: Handle stream transfers Thinh Nguyen
@ 2020-05-06  2:47 ` Thinh Nguyen
  2020-05-14 10:43 ` [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Felipe Balbi
  11 siblings, 0 replies; 13+ messages in thread
From: Thinh Nguyen @ 2020-05-06  2:47 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

DWC_usb32 v1.00a and later can use SET_EP_PRIME command to reinitiate a
stream. Use the command to handle NoStream rejection instead of ending
and restarting the endpoint.

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
---
 drivers/usb/dwc3/core.h   |  3 +++
 drivers/usb/dwc3/gadget.c | 13 ++++++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4def088329c7..013f42a2b5dc 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1161,6 +1161,9 @@ struct dwc3 {
 #define DWC31_REVISION_180A	0x3138302a
 #define DWC31_REVISION_190A	0x3139302a
 
+#define DWC32_REVISION_ANY	0x0
+#define DWC32_REVISION_100A	0x3130302a
+
 	u32			version_type;
 
 #define DWC31_VERSIONTYPE_ANY		0x0
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 0380f76151a1..fea4fde1b5e3 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2844,9 +2844,16 @@ static void dwc3_gadget_endpoint_stream_event(struct dwc3_ep *dep,
 		 * hosts, force to reinitate the stream until the host is ready
 		 * instead of waiting for the host to prime the endpoint.
 		 */
-		dep->flags |= DWC3_EP_DELAY_START;
-		dwc3_stop_active_transfer(dep, true, true);
-		return;
+		if (DWC3_VER_IS_WITHIN(DWC32, 100A, ANY)) {
+			unsigned int cmd = DWC3_DGCMD_SET_ENDPOINT_PRIME;
+
+			dwc3_send_gadget_generic_command(dwc, cmd, dep->number);
+		} else {
+			dep->flags |= DWC3_EP_DELAY_START;
+			dwc3_stop_active_transfer(dep, true, true);
+			return;
+		}
+		break;
 	}
 
 out:
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 00/11] usb: dwc3: gadget: Handle streams
  2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
                   ` (10 preceding siblings ...)
  2020-05-06  2:47 ` [PATCH v2 11/11] usb: dwc3: gadget: Use SET_EP_PRIME for NoStream Thinh Nguyen
@ 2020-05-14 10:43 ` Felipe Balbi
  11 siblings, 0 replies; 13+ messages in thread
From: Felipe Balbi @ 2020-05-14 10:43 UTC (permalink / raw)
  To: Thinh Nguyen, Greg Kroah-Hartman, Thinh Nguyen, linux-usb; +Cc: John Youn

[-- Attachment #1: Type: text/plain, Size: 2538 bytes --]


Hi,

Thinh Nguyen <Thinh.Nguyen@synopsys.com> writes:
> Overview of stream transfer requirement:
>  * A transfer will have a set of TRBs of the same stream ID.
>  * A transfer is started with a stream ID in START_TRANSFER command.
>  * A new stream will only start when the previous completes.
>
> Overview of stream events:
>  * A "prime" from host indicates that its endpoints are active
>    (buffers prepared and ready to receive/transmit data). The controller
>    automatically initiates stream if it sees this.
>  * A "NoStream" rejection event indicates that the host isn't ready.
>    Host will put the endpoint back to idle state. Device may need to
>    reinitiate the stream to start transfer again.
>  * A Stream Found event means host accepted device initiated stream.
>    Nothing needs to be done from driver.
>
> To initiate a stream, the driver will issue START_TRANSFER command with a
> stream ID. To reinitiate the stream, the driver must issue END_TRANSFER and
> restart the transfer with START_TRANSFER command with the same stream ID.
>
> This implementation handles device-initated streams (e.g. UASP driver).  It
> also handles some hosts' quirky behavior where they only prime each endpoint
> once.
>
> Prerequisite:
>   This series requires DWC_usb32 patch series
>   https://patchwork.kernel.org/project/linux-usb/list/?series=269641
>
>   [PATCH 1/2] usb: dwc3: Add support for DWC_usb32 IP
>   [PATCH 2/2] usb: dwc3: Get MDWIDTH for DWC_usb32
>
>
> Changes in v2:
>  - Update cover letter
>  - Split handling of stream and of transfer completion into smaller patches
>  - Reword usb_request->is_last to strictly use for streams
>  - Enforce transfer completion handling to only for stream capable endpoints
>
>
> Thinh Nguyen (11):
>   usb: gadget: Introduce usb_request->is_last
>   usb: gadget: f_tcm: Inform last stream request
>   usb: dwc3: gadget: Continue to process pending requests
>   usb: dwc3: gadget: Check for in-progress END_TRANSFER
>   usb: dwc3: gadget: Refactor TRB completion handler
>   usb: dwc3: gadget: Enable XferComplete event
>   usb: dwc3: gadget: Handle XferComplete for streams
>   usb: dwc3: gadget: Wait for transfer completion
>   usb: dwc3: gadget: Don't prepare beyond a transfer
>   usb: dwc3: gadget: Handle stream transfers
>   usb: dwc3: gadget: Use SET_EP_PRIME for NoStream

This seris is now in testing/next. Can you check that everything looks
fine for you? I had to manually apply one patch.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-05-14 10:43 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-06  2:46 [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 01/11] usb: gadget: Introduce usb_request->is_last Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 02/11] usb: gadget: f_tcm: Inform last stream request Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 03/11] usb: dwc3: gadget: Continue to process pending requests Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 04/11] usb: dwc3: gadget: Check for in-progress END_TRANSFER Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 05/11] usb: dwc3: gadget: Refactor TRB completion handler Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 06/11] usb: dwc3: gadget: Enable XferComplete event Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 07/11] usb: dwc3: gadget: Handle XferComplete for streams Thinh Nguyen
2020-05-06  2:46 ` [PATCH v2 08/11] usb: dwc3: gadget: Wait for transfer completion Thinh Nguyen
2020-05-06  2:47 ` [PATCH v2 09/11] usb: dwc3: gadget: Don't prepare beyond a transfer Thinh Nguyen
2020-05-06  2:47 ` [PATCH v2 10/11] usb: dwc3: gadget: Handle stream transfers Thinh Nguyen
2020-05-06  2:47 ` [PATCH v2 11/11] usb: dwc3: gadget: Use SET_EP_PRIME for NoStream Thinh Nguyen
2020-05-14 10:43 ` [PATCH v2 00/11] usb: dwc3: gadget: Handle streams Felipe Balbi

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.