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: c6267a5163
("usb: dwc3: gadget: align transfers to wMaxPacketSize")
Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
This commit is contained in:
parent
13111fcb0d
commit
490410b2e7
|
@ -1257,10 +1257,13 @@ out:
|
||||||
* The function goes through the requests list and sets up TRBs for the
|
* 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
|
* transfers. The function returns once there are no more TRBs available or
|
||||||
* it runs out of requests.
|
* 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;
|
struct dwc3_request *req, *n;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
|
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.
|
* break things.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(req, &dep->started_list, list) {
|
list_for_each_entry(req, &dep->started_list, list) {
|
||||||
if (req->num_pending_sgs > 0)
|
if (req->num_pending_sgs > 0) {
|
||||||
dwc3_prepare_one_trb_sg(dep, req);
|
ret = dwc3_prepare_one_trb_sg(dep, req);
|
||||||
|
if (!ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dwc3_calc_trbs_left(dep))
|
if (!dwc3_calc_trbs_left(dep))
|
||||||
return;
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't prepare beyond a transfer. In DWC_usb32, its transfer
|
* 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.
|
* active transfer instead of stopping.
|
||||||
*/
|
*/
|
||||||
if (dep->stream_capable && req->request.is_last)
|
if (dep->stream_capable && req->request.is_last)
|
||||||
return;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
|
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
|
||||||
struct dwc3 *dwc = dep->dwc;
|
struct dwc3 *dwc = dep->dwc;
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request,
|
ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request,
|
||||||
dep->direction);
|
dep->direction);
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
return ret;
|
||||||
|
|
||||||
req->sg = req->request.sg;
|
req->sg = req->request.sg;
|
||||||
req->start_sg = req->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;
|
req->num_pending_sgs = req->request.num_mapped_sgs;
|
||||||
|
|
||||||
if (req->num_pending_sgs > 0)
|
if (req->num_pending_sgs > 0)
|
||||||
dwc3_prepare_one_trb_sg(dep, req);
|
ret = dwc3_prepare_one_trb_sg(dep, req);
|
||||||
else
|
else
|
||||||
dwc3_prepare_one_trb_linear(dep, req);
|
ret = dwc3_prepare_one_trb_linear(dep, req);
|
||||||
|
|
||||||
if (!dwc3_calc_trbs_left(dep))
|
if (!ret || !dwc3_calc_trbs_left(dep))
|
||||||
return;
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't prepare beyond a transfer. In DWC_usb32, its transfer
|
* 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.
|
* active transfer instead of stopping.
|
||||||
*/
|
*/
|
||||||
if (dep->stream_capable && req->request.is_last)
|
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);
|
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;
|
int ret;
|
||||||
u32 cmd;
|
u32 cmd;
|
||||||
|
|
||||||
if (!dwc3_calc_trbs_left(dep))
|
ret = dwc3_prepare_trbs(dep);
|
||||||
return 0;
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
starting = !(dep->flags & DWC3_EP_TRANSFER_STARTED);
|
starting = !(dep->flags & DWC3_EP_TRANSFER_STARTED);
|
||||||
|
|
||||||
dwc3_prepare_trbs(dep);
|
|
||||||
req = next_request(&dep->started_list);
|
req = next_request(&dep->started_list);
|
||||||
if (!req) {
|
if (!req) {
|
||||||
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
||||||
|
|
Loading…
Reference in New Issue