[RFC 5/6] usb/dwc3: Fix update transfer issue condition

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Update transfer is issued for the TRBs where HWO switches from 0 to 1.
Lets say we had issued START TRANSFER with 8 TRBs having HWO as 1. Now
we need to update 9th TRB, Then we need to call UPDATE TRANSFER with
parameter as 9th TRB.

Current code was issuing UPDATE transfer with 2nd TRB, which was already
cached correctly during START TRANSFER.

Two simplify the flow two functions dwc3_prepare_trbs &
__dwc3_gadget_kick_transfer have been merged.

Signed-off-by: Pratyush Anand <pratyush.anand@xxxxxx>
---
 drivers/usb/dwc3/gadget.c |  156 +++++++++++++++++++++------------------------
 1 files changed, 72 insertions(+), 84 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 783bc87..65b757e 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -842,24 +842,73 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 	trb->ctrl |= DWC3_TRB_CTRL_HWO;
 }
 
-/*
- * dwc3_prepare_trbs - setup TRBs from requests
- * @dep: endpoint for which requests are being prepared
- * @starting: true if the endpoint is idle and no requests are queued.
- *
- * The function goes through the requests list and sets up TRBs for the
- * transfers. The function returns once there are no more TRBs available or
- * it runs out of requests.
- */
-static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
+static int __dwc3_start_update_transfer(struct dwc3_ep *dep,
+		struct dwc3_request *req, bool start_new, u16 cmd_param)
+{
+	struct dwc3			*dwc = dep->dwc;
+	struct dwc3_gadget_ep_cmd_params params;
+	int				ret;
+	u32				cmd;
+
+	memset(&params, 0, sizeof(params));
+	params.param0 = upper_32_bits(req->trb_dma);
+	params.param1 = lower_32_bits(req->trb_dma);
+
+	if (start_new)
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+	else
+		cmd = DWC3_DEPCMD_UPDATETRANSFER;
+
+	cmd |= DWC3_DEPCMD_PARAM(cmd_param);
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	if (ret < 0) {
+		dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+
+		/*
+		 * FIXME we need to iterate over the list of requests
+		 * here and stop, unmap, free and del each of the linked
+		 * requests instead of what we do now.
+		 */
+		usb_gadget_unmap_request(&dwc->gadget, &req->request,
+				req->direction);
+		list_del(&req->list);
+		return ret;
+	}
+
+	dep->flags |= DWC3_EP_BUSY;
+
+	if (start_new) {
+		dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
+				dep->number);
+		WARN_ON_ONCE(!dep->resource_index);
+	}
+
+	return 0;
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+		int start_new)
 {
 	struct dwc3_request	*req, *n;
 	u32			trbs_left;
 	u32			max;
 	unsigned int		last_one = 0;
+	struct dwc3		*dwc = dep->dwc;
+
+	if (start_new && (dep->flags & DWC3_EP_BUSY)) {
+		dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+		return -EBUSY;
+	}
 
 	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
 
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "ep %s run out for requests.\n",
+			dep->name);
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		return 0;
+	}
+
 	/* the first request must not be queued */
 	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
 
@@ -876,8 +925,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 	 * full and don't do anything
 	 */
 	if (!trbs_left) {
-		if (!starting)
-			return;
+		if (!start_new)
+			return 0;
 		trbs_left = DWC3_TRB_NUM;
 		/*
 		 * In case we start from scratch, we queue the ISOC requests
@@ -899,10 +948,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 		}
 	}
 
-	/* The last TRB is a link TRB, not used for xfer */
-	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
-		return;
-
 	list_for_each_entry_safe(req, n, &dep->request_list, list) {
 		unsigned	length;
 		dma_addr_t	dma;
@@ -935,6 +980,9 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 				dwc3_prepare_one_trb(dep, req, dma, length,
 						last_one, chain);
 
+				if (!start_new)
+					__dwc3_start_update_transfer(dep, req,
+						start_new, cmd_param);
 				if (last_one)
 					break;
 			}
@@ -953,81 +1001,21 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 			dwc3_prepare_one_trb(dep, req, dma, length,
 					last_one, false);
 
+			if (!start_new)
+				__dwc3_start_update_transfer(dep, req,
+						start_new, cmd_param);
 			if (last_one)
 				break;
 		}
+		/* The last TRB is a link TRB, not used for xfer */
+		if ((trbs_left <= 1) &&
+				usb_endpoint_xfer_isoc(dep->endpoint.desc))
+			break;
 	}
-}
-
-static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
-		int start_new)
-{
-	struct dwc3_gadget_ep_cmd_params params;
-	struct dwc3_request		*req;
-	struct dwc3			*dwc = dep->dwc;
-	int				ret;
-	u32				cmd;
-
-	if (start_new && (dep->flags & DWC3_EP_BUSY)) {
-		dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
-		return -EBUSY;
-	}
-	dep->flags &= ~DWC3_EP_PENDING_REQUEST;
 
-	/*
-	 * If we are getting here after a short-out-packet we don't enqueue any
-	 * new requests as we try to set the IOC bit only on the last request.
-	 */
 	if (start_new) {
-		if (list_empty(&dep->req_queued))
-			dwc3_prepare_trbs(dep, start_new);
-
-		/* req points to the first request which will be sent */
 		req = next_request(&dep->req_queued);
-	} else {
-		dwc3_prepare_trbs(dep, start_new);
-
-		/*
-		 * req points to the first request where HWO changed from 0 to 1
-		 */
-		req = next_request(&dep->req_queued);
-	}
-	if (!req) {
-		dep->flags |= DWC3_EP_PENDING_REQUEST;
-		return 0;
-	}
-
-	memset(&params, 0, sizeof(params));
-	params.param0 = upper_32_bits(req->trb_dma);
-	params.param1 = lower_32_bits(req->trb_dma);
-
-	if (start_new)
-		cmd = DWC3_DEPCMD_STARTTRANSFER;
-	else
-		cmd = DWC3_DEPCMD_UPDATETRANSFER;
-
-	cmd |= DWC3_DEPCMD_PARAM(cmd_param);
-	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
-	if (ret < 0) {
-		dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
-
-		/*
-		 * FIXME we need to iterate over the list of requests
-		 * here and stop, unmap, free and del each of the linked
-		 * requests instead of what we do now.
-		 */
-		usb_gadget_unmap_request(&dwc->gadget, &req->request,
-				req->direction);
-		list_del(&req->list);
-		return ret;
-	}
-
-	dep->flags |= DWC3_EP_BUSY;
-
-	if (start_new) {
-		dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
-				dep->number);
-		WARN_ON_ONCE(!dep->resource_index);
+		__dwc3_start_update_transfer(dep, req, start_new, cmd_param);
 	}
 
 	return 0;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux