Commit 490410b2 authored by Thinh Nguyen's avatar Thinh Nguyen Committed by Felipe Balbi
Browse files

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: c6267a51 ("usb: dwc3: gadget: align transfers to wMaxPacketSize")
Signed-off-by: default avatarThinh Nguyen <Thinh.Nguyen@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
parent 13111fcb
Loading
Loading
Loading
Loading
+22 −15
Original line number Diff line number Diff line
@@ -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;