This series resolves various issues with ZLP handling and refactor handling of TRBs. This series has too many changes comparing to the "[PATCH v3 0/4] usb: dwc3: gadget: Fix TRB preparation" series so I created different series instead.
Thinh Nguyen (10): usb: dwc3: gadget: Check MPS of the request length usb: dwc3: gadget: Reclaim extra TRBs after request completion usb: dwc3: gadget: Refactor preparing extra TRB usb: dwc3: gadget: Improve TRB ZLP setup usb: dwc3: ep0: Fix ZLP for OUT ep0 requests usb: dwc3: gadget: Return the number of prepared TRBs usb: dwc3: gadget: Check for number of TRBs prepared usb: dwc3: gadget: Set IOC if not enough for extra TRBs usb: dwc3: gadget: Refactor preparing last TRBs usb: dwc3: gadget: Rename misleading function names
drivers/usb/dwc3/ep0.c | 11 +- drivers/usb/dwc3/gadget.c | 262 +++++++++++++++++--------------------- 2 files changed, 124 insertions(+), 149 deletions(-)
base-commit: 2f45af92722ee6e78f12037af1870117bcae00d1
When preparing for SG, not all the entries are prepared at once. When resume, don't use the remaining request length to calculate for MPS alignment. Use the entire request->length to do that.
Cc: stable@vger.kernel.org Fixes: 5d187c0454ef ("usb: dwc3: gadget: Don't setup more than requested") Signed-off-by: Thinh Nguyen Thinh.Nguyen@synopsys.com --- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index cb19d682bbac..44351078f833 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1098,6 +1098,8 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, struct scatterlist *s; int i; unsigned int length = req->request.length; + unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); + unsigned int rem = length % maxp; unsigned int remaining = req->request.num_mapped_sgs - req->num_queued_sgs;
@@ -1109,8 +1111,6 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, length -= sg_dma_len(s);
for_each_sg(sg, s, remaining, i) { - unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); - unsigned int rem = length % maxp; unsigned int trb_length; unsigned int chain = true;
An SG request may be partially completed (due to no available TRBs). Don't reclaim extra TRBs and clear the needs_extra_trb flag until the request is fully completed. Otherwise, the driver will reclaim the wrong TRB.
Cc: stable@vger.kernel.org Fixes: 1f512119a08c ("usb: dwc3: gadget: add remaining sg entries to ring") Signed-off-by: Thinh Nguyen Thinh.Nguyen@synopsys.com --- drivers/usb/dwc3/gadget.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 44351078f833..6017263929f3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2738,6 +2738,11 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status);
+ req->request.actual = req->request.length - req->remaining; + + if (!dwc3_gadget_ep_request_completed(req)) + goto out; + if (req->needs_extra_trb) { unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
@@ -2753,11 +2758,6 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, req->needs_extra_trb = false; }
- req->request.actual = req->request.length - req->remaining; - - if (!dwc3_gadget_ep_request_completed(req)) - goto out; - dwc3_gadget_giveback(dep, req, status);
out:
The current ZLP handling for ep0 requests is only for control IN requests. For OUT direction, DWC3 needs to check and setup for MPS alignment.
Usually, control OUT requests can indicate its transfer size via the wLength field of the control message. So usb_request->zero is usually not needed for OUT direction. To handle ZLP OUT for control endpoint, make sure the TRB is MPS size.
Cc: stable@vger.kernel.org Fixes: c7fcdeb2627c ("usb: dwc3: ep0: simplify EP0 state machine") Fixes: d6e5a549cc4d ("usb: dwc3: simplify ZLP handling") Signed-off-by: Thinh Nguyen Thinh.Nguyen@synopsys.com --- drivers/usb/dwc3/ep0.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index b0363e3ba4d1..5580caed8b0c 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -947,12 +947,16 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req) { + unsigned int trb_length = 0; int ret;
req->direction = !!dep->number;
if (req->request.length == 0) { - dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0, + if (!req->direction) + trb_length = dep->endpoint.maxpacket; + + dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, trb_length, DWC3_TRBCTL_CONTROL_DATA, false); ret = dwc3_ep0_start_trans(dep); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) @@ -999,9 +1003,12 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1];
+ if (!req->direction) + trb_length = dep->endpoint.maxpacket; + /* Now prepare one extra TRB to align transfer size */ dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, - 0, DWC3_TRBCTL_CONTROL_DATA, + trb_length, DWC3_TRBCTL_CONTROL_DATA, false); ret = dwc3_ep0_start_trans(dep); } else {
linux-stable-mirror@lists.linaro.org