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

Commit 4199c5f8 authored by Felipe Balbi's avatar Felipe Balbi
Browse files

usb: dwc3: ep0: improve handling of unaligned OUT requests



Just like we did for all other endpoint types, let's rely on a chained
TRB pointing to ep0_bounce_addr in order to align transfer size. This
will make the code simpler.

Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent d686a5ff
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@
#define DWC3_PULL_UP_TIMEOUT	500	/* ms */
#define DWC3_ZLP_BUF_SIZE	1024	/* size of a superspeed bulk */
#define DWC3_BOUNCE_SIZE	1024	/* size of a superspeed bulk */
#define DWC3_EP0_BOUNCE_SIZE	512
#define DWC3_EP0_SETUP_SIZE	512
#define DWC3_ENDPOINTS_NUM	32
#define DWC3_XHCI_RESOURCES_NUM	2

@@ -761,12 +761,10 @@ struct dwc3_scratchpad_array {
/**
 * struct dwc3 - representation of our controller
 * @ep0_trb: trb which is used for the ctrl_req
 * @ep0_bounce: bounce buffer for ep0
 * @zlp_buf: used when request->zero is set
 * @setup_buf: used while precessing STD USB requests
 * @ep0_trb: dma address of ep0_trb
 * @ep0_usb_req: dummy req used while handling STD USB requests
 * @ep0_bounce_addr: dma address of ep0_bounce
 * @scratch_addr: dma address of scratchbuf
 * @ep0_in_setup: one control transfer is completed and enter setup phase
 * @lock: for synchronizing
@@ -859,13 +857,11 @@ struct dwc3_scratchpad_array {
struct dwc3 {
	struct dwc3_trb		*ep0_trb;
	void			*bounce;
	void			*ep0_bounce;
	void			*zlp_buf;
	void			*scratchbuf;
	u8			*setup_buf;
	dma_addr_t		ep0_trb_addr;
	dma_addr_t		bounce_addr;
	dma_addr_t		ep0_bounce_addr;
	dma_addr_t		scratch_addr;
	struct dwc3_request	ep0_usb_req;
	struct completion	ep0_in_setup;
+18 −47
Original line number Diff line number Diff line
@@ -836,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
	struct usb_request	*ur;
	struct dwc3_trb		*trb;
	struct dwc3_ep		*ep0;
	unsigned		transfer_size = 0;
	unsigned		maxp;
	unsigned		remaining_ur_length;
	void			*buf;
@@ -849,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
	ep0 = dwc->eps[0];

	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;

	trb = dwc->ep0_trb;

	trace_dwc3_complete_trb(ep0, trb);

	r = next_request(&ep0->pending_list);
@@ -872,39 +869,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
	remaining_ur_length = ur->length;

	length = trb->size & DWC3_TRB_SIZE_MASK;

	maxp = ep0->endpoint.maxpacket;

	if (dwc->ep0_bounced) {
		/*
		 * Handle the first TRB before handling the bounce buffer if
		 * the request length is greater than the bounce buffer size
		 */
		if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
			transfer_size = ALIGN(ur->length - maxp, maxp);
			transferred = transfer_size - length;
			buf = (u8 *)buf + transferred;
	transferred = ur->length - length;
	ur->actual += transferred;
			remaining_ur_length -= transferred;

	if (dwc->ep0_bounced) {
		trb++;
			length = trb->size & DWC3_TRB_SIZE_MASK;

		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
		ep0->trb_enqueue = 0;
		dwc->ep0_bounced = false;
	}

		transfer_size = roundup((ur->length - transfer_size),
					maxp);

		transferred = min_t(u32, remaining_ur_length,
				    transfer_size - length);
		memcpy(buf, dwc->ep0_bounce, transferred);
	} else {
		transferred = ur->length - length;
	}

	ur->actual += transferred;

	if ((epnum & 1) && ur->actual < ur->length) {
		/* for some reason we did not get everything out */

@@ -1006,8 +981,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
		ret = dwc3_ep0_start_trans(dep);
	} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
			&& (dep->number == 0)) {
		u32	transfer_size = 0;
		u32	maxpacket;
		u32	rem;

		ret = usb_gadget_map_request_by_dev(dwc->sysdev,
				&req->request, dep->number);
@@ -1015,23 +990,19 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
			return;

		maxpacket = dep->endpoint.maxpacket;
		rem = req->request.length % maxpacket;
		dwc->ep0_bounced = true;

		if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
			transfer_size = ALIGN(req->request.length - maxpacket,
					      maxpacket);
		/* prepare normal TRB */
		dwc3_ep0_prepare_one_trb(dep, req->request.dma,
						   transfer_size,
					 req->request.length,
					 DWC3_TRBCTL_CONTROL_DATA,
					 true);
		}

		transfer_size = roundup((req->request.length - transfer_size),
					maxpacket);

		dwc->ep0_bounced = true;

		dwc3_ep0_prepare_one_trb(dep, dwc->ep0_bounce_addr,
					 transfer_size, DWC3_TRBCTL_CONTROL_DATA,
		/* Now prepare one extra TRB to align transfer size */
		dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
					 maxpacket - rem,
					 DWC3_TRBCTL_CONTROL_DATA,
					 false);
		ret = dwc3_ep0_start_trans(dep);
	} else {
+10 −40
Original line number Diff line number Diff line
@@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
		int status)
{
	struct dwc3			*dwc = dep->dwc;
	unsigned int			unmap_after_complete = false;

	req->started = false;
	list_del(&req->list);
@@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
	if (req->request.status == -EINPROGRESS)
		req->request.status = status;

	/*
	 * NOTICE we don't want to unmap before calling ->complete() if we're
	 * dealing with a bounced ep0 request. If we unmap it here, we would end
	 * up overwritting the contents of req->buf and this could confuse the
	 * gadget driver.
	 */
	if (dwc->ep0_bounced && dep->number <= 1) {
		dwc->ep0_bounced = false;
		unmap_after_complete = true;
	} else {
	usb_gadget_unmap_request_by_dev(dwc->sysdev,
					&req->request, req->direction);
	}

	trace_dwc3_gadget_giveback(req);

@@ -201,10 +189,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
	usb_gadget_giveback_request(&dep->endpoint, &req->request);
	spin_lock(&dwc->lock);

	if (unmap_after_complete)
		usb_gadget_unmap_request_by_dev(dwc->sysdev,
				&req->request, req->direction);

	if (dep->number > 1)
		pm_runtime_put(dwc->dev);
}
@@ -3153,32 +3137,23 @@ int dwc3_gadget_init(struct dwc3 *dwc)
		goto err0;
	}

	dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
	dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
	if (!dwc->setup_buf) {
		ret = -ENOMEM;
		goto err1;
	}

	dwc->ep0_bounce = dma_alloc_coherent(dwc->sysdev,
			DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
			GFP_KERNEL);
	if (!dwc->ep0_bounce) {
		dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
		ret = -ENOMEM;
		goto err2;
	}

	dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL);
	if (!dwc->zlp_buf) {
		ret = -ENOMEM;
		goto err3;
		goto err2;
	}

	dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
			&dwc->bounce_addr, GFP_KERNEL);
	if (!dwc->bounce) {
		ret = -ENOMEM;
		goto err4;
		goto err3;
	}

	init_completion(&dwc->ep0_in_setup);
@@ -3218,7 +3193,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)

	ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
	if (ret)
		goto err5;
		goto err4;

	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
	if (ret) {
@@ -3228,16 +3203,14 @@ int dwc3_gadget_init(struct dwc3 *dwc)

	return 0;
err5:
	dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
			dwc->bounce_addr);
	dwc3_gadget_free_endpoints(dwc);

err4:
	kfree(dwc->zlp_buf);
	dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
			dwc->bounce_addr);

err3:
	dwc3_gadget_free_endpoints(dwc);
	dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
			dwc->ep0_bounce, dwc->ep0_bounce_addr);
	kfree(dwc->zlp_buf);

err2:
	kfree(dwc->setup_buf);
@@ -3260,9 +3233,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)

	dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
			dwc->bounce_addr);
	dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
			dwc->ep0_bounce, dwc->ep0_bounce_addr);

	kfree(dwc->setup_buf);
	kfree(dwc->zlp_buf);