Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f849fcfc authored by Vamsi Krishna's avatar Vamsi Krishna
Browse files

dwc3: gadget: Check available trbs before processing req



if number of trbs not sufficient while processing request with
scatter/gather buffers some buffers may be dropped. To avoid
dropping packets check for available trbs before processing
number of trbs.

Change-Id: Ia85e2b57d20117d2319923b59c78b69c26385e42
Signed-off-by: default avatarVamsi Krishna <vskrishn@codeaurora.org>
parent bdac9783
Loading
Loading
Loading
Loading
+59 −6
Original line number Diff line number Diff line
@@ -964,6 +964,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
	u32			trbs_left;
	u32			max;
	unsigned int		last_one = 0;
	int			maxpkt_size;
	bool			isoc;

	maxpkt_size = usb_endpoint_maxp(dep->endpoint.desc);
	isoc = usb_endpoint_xfer_isoc(dep->endpoint.desc);

	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);

@@ -1006,17 +1011,31 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
		}
	}

	/* The last TRB is a link TRB, not used for xfer */
	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
		return;

	list_for_each_entry_safe(req, n, &dep->request_list, list) {
		unsigned	length;
		dma_addr_t	dma;
		bool		last_req = list_is_last(&req->list,
							&dep->request_list);
		int		num_trbs_required = 0;

		last_one = false;

		/* The last TRB is a link TRB, not used for xfer */
		if (isoc)
			num_trbs_required++;

		if (req->request.num_mapped_sgs)
			num_trbs_required += req->request.num_mapped_sgs;
		else
			num_trbs_required++;

		if (req->request.zero && req->request.length &&
				(req->request.length % maxpkt_size == 0))
			num_trbs_required++;

		if (trbs_left < num_trbs_required)
			break;

		if (req->request.num_mapped_sgs > 0) {
			struct usb_request *request = &req->request;
			struct scatterlist *sg = request->sg;
@@ -1031,11 +1050,45 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)

				if (i == (request->num_mapped_sgs - 1) ||
						sg_is_last(s)) {
					if (last_req)
						last_one = true;
					unsigned temp = 0;
					unsigned len;
					struct dwc3_request *nreq = n;
					struct usb_request *ureq;
					bool mpkt = false;

					chain = false;
					if (last_req) {
						last_one = true;
						goto start_trb_queuing;
					}

					/*
					 * check if trbs sufficient for next
					 * request to set the last bit
					 */
					ureq = &nreq->request;
					len  = ureq->length;

					if (len % maxpkt_size == 0)
						mpkt = true;

					if (ureq->zero && len && mpkt)
						temp++;

					if (ureq->num_mapped_sgs)
						temp +=
						ureq->num_mapped_sgs;
					else
						temp++;

					if (isoc)
						temp++;

					if (trbs_left <= temp)
						last_one = true;
				}

start_trb_queuing:
				trbs_left--;
				if (!trbs_left)
					last_one = true;