This series contains miscellaneous fixes and cleanup including the clearing of the ep0 flags and handling of SG for dwc3.
Thinh Nguyen (5): usb: dwc3: ep0: Don't clear ep0 DWC3_EP_TRANSFER_STARTED usb: dwc3: gadget: Fix checking for number of TRBs left usb: dwc3: gadget: Fix looping of queued SG entries usb: dwc3: gadget: Cleanup SG handling usb: dwc3: gadget: Remove dwc3_request->needs_extra_trb
drivers/usb/dwc3/core.h | 6 ---- drivers/usb/dwc3/ep0.c | 2 +- drivers/usb/dwc3/gadget.c | 65 ++++++++++++--------------------------- 3 files changed, 21 insertions(+), 52 deletions(-)
base-commit: 528ea1aca24fba5616f397d43ccb2de99d2a41d7
The driver cannot issue the End Transfer command to the SETUP transfer. Don't clear DWC3_EP_TRANSFER_STARTED flag to make sure that the driver won't send Start Transfer command again, which can cause no-resource error. For example this can occur if the host issues a reset to the device.
Cc: stable@vger.kernel.org Fixes: 76cb323f80ac ("usb: dwc3: ep0: clear all EP0 flags") Signed-off-by: Thinh Nguyen Thinh.Nguyen@synopsys.com --- drivers/usb/dwc3/ep0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index f3d97ad5156e..666ac432f52d 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -232,7 +232,7 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) /* stall is always issued on EP0 */ dep = dwc->eps[0]; __dwc3_gadget_ep_set_halt(dep, 1, false); - dep->flags &= DWC3_EP_RESOURCE_ALLOCATED; + dep->flags &= DWC3_EP_RESOURCE_ALLOCATED | DWC3_EP_TRANSFER_STARTED; dep->flags |= DWC3_EP_ENABLED; dwc->delayed_status = false;
The check whether the TRB ring is full or empty in dwc3_calc_trbs_left() is insufficient. It assumes there are active TRBs if there's any request in the started_list. However, that's not the case for requests with a large SG list.
That is, if we have a single usb request that requires more TRBs than the total TRBs in the TRB ring, the queued TRBs will be available when all the TRBs in the ring are completed. But the request is only partially completed and remains in the started_list. With the current logic, the TRB ring is empty, but dwc3_calc_trbs_left() returns 0.
Fix this by additionally checking for the request->num_trbs for active TRB count.
Cc: stable@vger.kernel.org Fixes: 51f1954ad853 ("usb: dwc3: gadget: Fix dwc3_calc_trbs_left()") Signed-off-by: Thinh Nguyen Thinh.Nguyen@synopsys.com --- drivers/usb/dwc3/gadget.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6101e5467b08..38c3769a6c48 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1230,11 +1230,14 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) * pending to be processed by the driver. */ if (dep->trb_enqueue == dep->trb_dequeue) { + struct dwc3_request *req; + /* - * If there is any request remained in the started_list at - * this point, that means there is no TRB available. + * If there is any request remained in the started_list with + * active TRBs at this point, then there is no TRB available. */ - if (!list_empty(&dep->started_list)) + req = next_request(&dep->started_list); + if (req && req->num_trbs) return 0;
return DWC3_TRB_NUM - 1;
The dwc3_request->num_queued_sgs is decremented on completion. If a partially completed request is handled, then the dwc3_request->num_queued_sgs no longer reflects the total number of num_queued_sgs (it would be cleared).
Correctly check the number of request SG entries remained to be prepare and queued. Failure to do this may cause null pointer dereference when accessing non-existent SG entry.
Cc: stable@vger.kernel.org Fixes: c96e6725db9d ("usb: dwc3: gadget: Correct the logic for queuing sgs") Signed-off-by: Thinh Nguyen Thinh.Nguyen@synopsys.com --- drivers/usb/dwc3/gadget.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 38c3769a6c48..3a5a0d8be33c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1470,8 +1470,8 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep, struct scatterlist *s; int i; unsigned int length = req->request.length; - unsigned int remaining = req->request.num_mapped_sgs - - req->num_queued_sgs; + unsigned int remaining = req->num_pending_sgs; + unsigned int num_queued_sgs = req->request.num_mapped_sgs - remaining; unsigned int num_trbs = req->num_trbs; bool needs_extra_trb = dwc3_needs_extra_trb(dep, req);
@@ -1479,7 +1479,7 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep, * If we resume preparing the request, then get the remaining length of * the request and resume where we left off. */ - for_each_sg(req->request.sg, s, req->num_queued_sgs, i) + for_each_sg(req->request.sg, s, num_queued_sgs, i) length -= sg_dma_len(s);
for_each_sg(sg, s, remaining, i) {
linux-stable-mirror@lists.linaro.org