From 490410b2e73cd350ba91946913b017c8f6e1b612 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Thu, 24 Sep 2020 01:21:55 -0700 Subject: [PATCH] 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 Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 673a34b..ec14272 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; -- 2.7.4