[PATCH V3] usb: dwc3: Handle pending control data out correctly

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

 



If transfer not ready is received before ep_queue is called for control
out transfer then pending flag is set. Handling of this case was not
correct.
TRB size must be multiple of maxpacket for all control out transfer.
dma sync function should also be called before start transfer.

A routine to delegate transfer for control data has been extracted out
from dwc3_ep0_do_control_data. Same routine has been called from
ep_queue too in case of pending flag is set.

Signed-off-by: Pratyush Anand <pratyush.anand@xxxxxx>
Signed-off-by: Felipe Balbi <balbi@xxxxxx>
---
 drivers/usb/dwc3/ep0.c |   90 +++++++++++++++++++++++++----------------------
 1 files changed, 48 insertions(+), 42 deletions(-)

diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 1f917d9..f0c5f85 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -119,6 +119,49 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
 	return 0;
 }
 
+static int dwc3_ep0_start_data_trans(struct dwc3 *dwc,
+		struct dwc3_request *req)
+{
+	u32 transfer_size = req->request.length;
+	struct dwc3_ep *dep = dwc->eps[0];
+	int ret;
+	dma_addr_t dma_addr;
+
+	if (transfer_size) {
+		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+				dep->direction);
+		if (ret) {
+			dev_dbg(dwc->dev, "failed to map request\n");
+			return ret;
+		}
+	} else {
+		dma_addr = dwc->ctrl_req_addr;
+	}
+
+	if (!req->direction && !IS_ALIGNED((u32)transfer_size,
+				dep->endpoint.maxpacket)) {
+		/*
+		 * REVISIT in case request length is bigger than EP0
+		 * wMaxPacketSize, we will need two chained TRBs to
+		 * handle the transfer.
+		 */
+		WARN_ON(transfer_size > dep->endpoint.maxpacket);
+
+		dwc->ep0_bounced = true;
+		transfer_size = roundup(transfer_size,
+				(u32)dep->endpoint.maxpacket);
+		dma_addr = dwc->ep0_bounce_addr;
+	} else {
+		dma_addr = req->request.dma;
+	}
+
+	ret = dwc3_ep0_start_trans(dwc, req->direction,
+			dma_addr, transfer_size,
+			DWC3_TRBCTL_CONTROL_DATA);
+
+	return ret;
+}
+
 static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
 		struct dwc3_request *req)
 {
@@ -150,9 +193,10 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
 			return 0;
 		}
 
-		ret = dwc3_ep0_start_trans(dwc, direction,
-				req->request.dma, req->request.length,
-				DWC3_TRBCTL_CONTROL_DATA);
+		req->direction = direction;
+
+		ret = dwc3_ep0_start_data_trans(dwc, req);
+
 		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
 				DWC3_EP0_DIR_IN);
 	} else if (dwc->delayed_status) {
@@ -675,45 +719,7 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
 	req = next_request(&dep->request_list);
 	req->direction = !!event->endpoint_number;
 
-	if (req->request.length == 0) {
-		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
-				dwc->ctrl_req_addr, 0,
-				DWC3_TRBCTL_CONTROL_DATA);
-	} else if ((req->request.length % dep->endpoint.maxpacket)
-			&& (event->endpoint_number == 0)) {
-
-		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
-			dep->direction);
-		if (ret) {
-			dev_dbg(dwc->dev, "failed to map request\n");
-			return;
-		}
-
-		WARN_ON(req->request.length > dep->endpoint.maxpacket);
-
-		dwc->ep0_bounced = true;
-
-		/*
-		 * REVISIT in case request length is bigger than EP0
-		 * wMaxPacketSize, we will need two chained TRBs to handle
-		 * the transfer.
-		 */
-		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
-				dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
-				DWC3_TRBCTL_CONTROL_DATA);
-	} else {
-
-		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
-			dep->direction);
-		if (ret) {
-			dev_dbg(dwc->dev, "failed to map request\n");
-			return;
-		}
-
-		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
-				req->request.dma, req->request.length,
-				DWC3_TRBCTL_CONTROL_DATA);
-	}
+	ret = dwc3_ep0_start_data_trans(dwc, req);
 
 	WARN_ON(ret < 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