From f9296fedb223d28aa281c45ab6cd7a1a3aea0fab Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 5 Mar 2020 13:24:20 -0800 Subject: [PATCH 1/4] usb: dwc3: gadget: Refactor dwc3_gadget_ep_dequeue The flow from function dwc3_gadget_ep_dequeue() is not easy to follow. Refactor it for easier read. No functional change in this commit. Change-Id: I254081abaf3ff7c6a7a598bf859804ecf3454a15 Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Git-commit: fcd2def6639293c2bde2dc4f5dab63641a60b5b3 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [mrana@codeaurora.org: resolve merge conflict related to debug log] Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index ec8eb40ae319..624fa98db9b2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1679,27 +1679,33 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, } trace_dwc3_ep_dequeue(req); + dbg_ep_dequeue(dep->number, req); spin_lock_irqsave(&dwc->lock, flags); list_for_each_entry(r, &dep->cancelled_list, list) { - if (r == req) - goto out0; + if (r == req) { + dbg_log_string("req:%pK found cancelled list", + &req->request); + goto out; + } } list_for_each_entry(r, &dep->pending_list, list) { - if (r == req) - break; + if (r == req) { + dbg_log_string("req:%pK found pending list", + &req->request); + dwc3_gadget_giveback(dep, req, -ECONNRESET); + goto out; + } } - if (r != req) { - list_for_each_entry(r, &dep->started_list, list) { - if (r == req) - break; - } + list_for_each_entry(r, &dep->started_list, list) { if (r == req) { struct dwc3_request *t; + dbg_log_string("req:%pK found started list", + &req->request); /* wait until it is processed */ dwc3_stop_active_transfer(dep, true, true); @@ -1710,18 +1716,14 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, list_for_each_entry_safe(r, t, &dep->started_list, list) dwc3_gadget_move_cancelled_request(r); - goto out0; + goto out; } - dev_err(dwc->dev, "request %pK was not queued to %s\n", - request, ep->name); - ret = -EINVAL; - goto out0; } - dbg_ep_dequeue(dep->number, req); - dwc3_gadget_giveback(dep, req, -ECONNRESET); - -out0: + dev_err(dwc->dev, "request %pK was not queued to %s\n", + request, ep->name); + ret = -EINVAL; +out: spin_unlock_irqrestore(&dwc->lock, flags); return ret; From d831e159b56dca0e0e77df01a669e117b5d5934e Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Tue, 31 Mar 2020 01:40:35 -0700 Subject: [PATCH 2/4] usb: dwc3: gadget: Fix request completion check A request may not be completed because not all the TRBs are prepared for it. This happens when we run out of available TRBs. When some TRBs are completed, the driver needs to prepare the rest of the TRBs for the request. The check dwc3_gadget_ep_request_completed() shouldn't be checking the amount of data received but rather the number of pending TRBs. Revise this request completion check. Change-Id: If806e69c32a84caa0c839286a33ee0b092cd372a Cc: stable@vger.kernel.org Fixes: e0c42ce590fe ("usb: dwc3: gadget: simplify IOC handling") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Git-commit: 49e0590e3a60e75b493e5df879e216e5073c7663 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 624fa98db9b2..42a8cb126b4e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2830,14 +2830,7 @@ static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep, static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req) { - /* - * For OUT direction, host may send less than the setup - * length. Return true for all OUT requests. - */ - if (!req->direction) - return true; - - return req->request.actual == req->request.length; + return req->num_pending_sgs == 0; } static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, @@ -2872,8 +2865,7 @@ 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) || - req->num_pending_sgs) { + if (!dwc3_gadget_ep_request_completed(req)) { __dwc3_gadget_kick_transfer(dep); goto out; } From f0b846ce9314570f593fbd5c8c7ec47b908aa889 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Sun, 29 Mar 2020 16:12:57 -0700 Subject: [PATCH 3/4] usb: dwc3: gadget: Properly handle failed kick_transfer If dwc3 fails to issue START_TRANSFER/UPDATE_TRANSFER command, then we should properly end an active transfer and give back all the started requests. However if it's for an isoc endpoint, the failure maybe due to bus-expiry status. In this case, don't give back the requests and wait for the next retry. Change-Id: I64ff69a663a9ad7701f877a0cf3bcd87b93c792a Fixes: 72246da40f37 ("usb: Introduce DesignWare USB3 DRD Driver") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Git-commit: 8d99087c2db863c5fa3a4a1f3cb82b3a493705ca Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 42a8cb126b4e..aa4517e9c1fe 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1339,6 +1339,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) } } +static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep); + static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; @@ -1380,14 +1382,20 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); if (ret < 0) { - /* - * 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. - */ - if (req->trb) - memset(req->trb, 0, sizeof(struct dwc3_trb)); - dwc3_gadget_del_and_unmap_request(dep, req, ret); + struct dwc3_request *tmp; + + if (ret == -EAGAIN) + return ret; + + dwc3_stop_active_transfer(dep, true, true); + + list_for_each_entry_safe(req, tmp, &dep->started_list, list) + dwc3_gadget_move_cancelled_request(req); + + /* If ep isn't started, then there's no end transfer pending */ + if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + dwc3_gadget_ep_cleanup_cancelled_requests(dep); + return ret; } From 3bd550d0581e284dc4e0705db3874dbbcc0d65ba Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 29 Jan 2020 09:20:19 +0200 Subject: [PATCH 4/4] usb: dwc3: trace: print enqueue/dequeue pointers too By printing enqueue/dequeue pointers, we can make sure that our TRB handling is correct. We've had a recent situation where we were not always dequeueing all TRBs in an SG list and this helped figure out what the problem was. Change-Id: Ied1c5d57b4f324c40dd219153b49a1e244b6773c Signed-off-by: Felipe Balbi Git-commit: 30ad6273adad76017ddad737d45f8931cac554ad Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Mayank Rana --- drivers/usb/dwc3/trace.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 9edff17111f7..3054b89512ff 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -227,6 +227,8 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, __field(u32, size) __field(u32, ctrl) __field(u32, type) + __field(u32, enqueue) + __field(u32, dequeue) ), TP_fast_assign( __assign_str(name, dep->name); @@ -236,9 +238,12 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, __entry->size = trb->size; __entry->ctrl = trb->ctrl; __entry->type = usb_endpoint_type(dep->endpoint.desc); + __entry->enqueue = dep->trb_enqueue; + __entry->dequeue = dep->trb_dequeue; ), - TP_printk("%s: trb %p buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)", - __get_str(name), __entry->trb, __entry->bph, __entry->bpl, + TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)", + __get_str(name), __entry->trb, __entry->enqueue, + __entry->dequeue, __entry->bph, __entry->bpl, ({char *s; int pcm = ((__entry->size >> 24) & 3) + 1; switch (__entry->type) {