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

Commit c6267a51 authored by Felipe Balbi's avatar Felipe Balbi
Browse files

usb: dwc3: gadget: align transfers to wMaxPacketSize



Instead of passing quirk_ep_out_aligned_size, we can use one extra TRB
to align transfer to wMaxPacketSize.

Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 905dc04e
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -725,6 +725,7 @@ struct dwc3_hwparams {
 * @epnum: endpoint number to which this request refers
 * @epnum: endpoint number to which this request refers
 * @trb: pointer to struct dwc3_trb
 * @trb: pointer to struct dwc3_trb
 * @trb_dma: DMA address of @trb
 * @trb_dma: DMA address of @trb
 * @unaligned: true for OUT endpoints with length not divisible by maxp
 * @direction: IN or OUT direction flag
 * @direction: IN or OUT direction flag
 * @mapped: true when request has been dma-mapped
 * @mapped: true when request has been dma-mapped
 * @queued: true when request has been queued to HW
 * @queued: true when request has been queued to HW
@@ -741,6 +742,7 @@ struct dwc3_request {
	struct dwc3_trb		*trb;
	struct dwc3_trb		*trb;
	dma_addr_t		trb_dma;
	dma_addr_t		trb_dma;


	unsigned		unaligned:1;
	unsigned		direction:1;
	unsigned		direction:1;
	unsigned		mapped:1;
	unsigned		mapped:1;
	unsigned		started:1;
	unsigned		started:1;
+61 −8
Original line number Original line Diff line number Diff line
@@ -992,12 +992,33 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
	int		i;
	int		i;


	for_each_sg(sg, s, req->num_pending_sgs, i) {
	for_each_sg(sg, s, req->num_pending_sgs, i) {
		unsigned int length = req->request.length;
		unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
		unsigned int rem = length % maxp;
		unsigned chain = true;
		unsigned chain = true;


		if (sg_is_last(s))
		if (sg_is_last(s))
			chain = false;
			chain = false;


		if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
			struct dwc3	*dwc = dep->dwc;
			struct dwc3_trb	*trb;

			req->unaligned = true;

			/* prepare normal TRB */
			dwc3_prepare_one_trb(dep, req, true, i);

			/* Now prepare one extra TRB to align transfer size */
			trb = &dep->trb_pool[dep->trb_enqueue];
			__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr,
					maxp - rem, false, 0,
					req->request.stream_id,
					req->request.short_not_ok,
					req->request.no_interrupt);
		} else {
			dwc3_prepare_one_trb(dep, req, chain, i);
			dwc3_prepare_one_trb(dep, req, chain, i);
		}


		if (!dwc3_calc_trbs_left(dep))
		if (!dwc3_calc_trbs_left(dep))
			break;
			break;
@@ -1007,8 +1028,29 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
		struct dwc3_request *req)
		struct dwc3_request *req)
{
{
	unsigned int length = req->request.length;
	unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
	unsigned int rem = length % maxp;

	if (rem && usb_endpoint_dir_out(dep->endpoint.desc)) {
		struct dwc3	*dwc = dep->dwc;
		struct dwc3_trb	*trb;

		req->unaligned = true;

		/* prepare normal TRB */
		dwc3_prepare_one_trb(dep, req, true, 0);

		/* Now prepare one extra TRB to align transfer size */
		trb = &dep->trb_pool[dep->trb_enqueue];
		__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem,
				false, 0, req->request.stream_id,
				req->request.short_not_ok,
				req->request.no_interrupt);
	} else {
		dwc3_prepare_one_trb(dep, req, false, 0);
		dwc3_prepare_one_trb(dep, req, false, 0);
	}
	}
}


/*
/*
 * dwc3_prepare_trbs - setup TRBs from requests
 * dwc3_prepare_trbs - setup TRBs from requests
@@ -2031,6 +2073,16 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
	if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
	if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;


	/*
	 * If we're dealing with unaligned size OUT transfer, we will be left
	 * with one TRB pending in the ring. We need to manually clear HWO bit
	 * from that TRB.
	 */
	if (req->unaligned && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
		return 1;
	}

	if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
	if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
		return 1;
		return 1;


@@ -2120,6 +2172,13 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
					event, status, chain);
					event, status, chain);
		}
		}


		if (req->unaligned) {
			trb = &dep->trb_pool[dep->trb_dequeue];
			ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
					event, status, false);
			req->unaligned = false;
		}

		req->request.actual = length - req->remaining;
		req->request.actual = length - req->remaining;


		if ((req->request.actual < length) && req->num_pending_sgs)
		if ((req->request.actual < length) && req->num_pending_sgs)
@@ -3058,12 +3117,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)


	dwc->gadget.max_speed		= dwc->maximum_speed;
	dwc->gadget.max_speed		= dwc->maximum_speed;


	/*
	 * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
	 * on ep out.
	 */
	dwc->gadget.quirk_ep_out_aligned_size = true;

	/*
	/*
	 * REVISIT: Here we should clear all pending IRQs to be
	 * REVISIT: Here we should clear all pending IRQs to be
	 * sure we're starting from a well known location.
	 * sure we're starting from a well known location.