summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>2020-09-24 01:21:55 -0700
committerFelipe Balbi <balbi@kernel.org>2020-10-02 09:57:44 +0300
commit490410b2e73cd350ba91946913b017c8f6e1b612 (patch)
tree70e15326a361d353e5715649bcc9cf9b2a4104df /drivers/usb/dwc3
parent13111fcb0d64fb69bd7466d6e2ca6ed7b95a9d50 (diff)
downloadlinux-stable-490410b2e73cd350ba91946913b017c8f6e1b612.tar.gz
linux-stable-490410b2e73cd350ba91946913b017c8f6e1b612.tar.bz2
linux-stable-490410b2e73cd350ba91946913b017c8f6e1b612.zip
usb: dwc3: gadget: Check for number of TRBs prepared
By returning the number of TRBs prepared, we know whether to execute __dwc3_gadget_kick_transfer(). This allows us to check if we ran out of TRBs when extra TRBs are needed for OUT transfers. It also allows us to properly handle usb_gadget_map_request_by_dev() error. Fixes: c6267a51639b ("usb: dwc3: gadget: align transfers to wMaxPacketSize") Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/gadget.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 673a34b715e2..ec142724e85c 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1257,10 +1257,13 @@ out:
* 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.
+ *
+ * Returns the number of TRBs prepared or negative errno.
*/
-static void dwc3_prepare_trbs(struct dwc3_ep *dep)
+static int dwc3_prepare_trbs(struct dwc3_ep *dep)
{
struct dwc3_request *req, *n;
+ int ret = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
@@ -1275,11 +1278,14 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
* break things.
*/
list_for_each_entry(req, &dep->started_list, list) {
- if (req->num_pending_sgs > 0)
- dwc3_prepare_one_trb_sg(dep, req);
+ if (req->num_pending_sgs > 0) {
+ ret = dwc3_prepare_one_trb_sg(dep, req);
+ if (!ret)
+ return ret;
+ }
if (!dwc3_calc_trbs_left(dep))
- return;
+ return ret;
/*
* Don't prepare beyond a transfer. In DWC_usb32, its transfer
@@ -1287,17 +1293,16 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
* active transfer instead of stopping.
*/
if (dep->stream_capable && req->request.is_last)
- return;
+ return ret;
}
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
struct dwc3 *dwc = dep->dwc;
- int ret;
ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request,
dep->direction);
if (ret)
- return;
+ return ret;
req->sg = req->request.sg;
req->start_sg = req->sg;
@@ -1305,12 +1310,12 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
req->num_pending_sgs = req->request.num_mapped_sgs;
if (req->num_pending_sgs > 0)
- dwc3_prepare_one_trb_sg(dep, req);
+ ret = dwc3_prepare_one_trb_sg(dep, req);
else
- dwc3_prepare_one_trb_linear(dep, req);
+ ret = dwc3_prepare_one_trb_linear(dep, req);
- if (!dwc3_calc_trbs_left(dep))
- return;
+ if (!ret || !dwc3_calc_trbs_left(dep))
+ return ret;
/*
* Don't prepare beyond a transfer. In DWC_usb32, its transfer
@@ -1318,8 +1323,10 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
* active transfer instead of stopping.
*/
if (dep->stream_capable && req->request.is_last)
- return;
+ return ret;
}
+
+ return ret;
}
static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep);
@@ -1332,12 +1339,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
int ret;
u32 cmd;
- if (!dwc3_calc_trbs_left(dep))
- return 0;
+ ret = dwc3_prepare_trbs(dep);
+ if (ret <= 0)
+ return ret;
starting = !(dep->flags & DWC3_EP_TRANSFER_STARTED);
- dwc3_prepare_trbs(dep);
req = next_request(&dep->started_list);
if (!req) {
dep->flags |= DWC3_EP_PENDING_REQUEST;