Commit 75a41ce4 authored by Phil Elwell's avatar Phil Elwell Committed by Greg Kroah-Hartman
Browse files

usb: dwc2: Fix gadget DMA unmap direction



The dwc2 gadget support maps and unmaps DMA buffers as necessary. When
mapping and unmapping it uses the direction of the endpoint to select
the direction of the DMA transfer, but this fails for Control OUT
transfers because the unmap occurs after the endpoint direction has
been reversed for the status phase.

A possible solution would be to unmap the buffer before the direction
is changed, but a safer, less invasive fix is to remember the buffer
direction independently of the endpoint direction.

Fixes: fe0b94ab ("usb: dwc2: gadget: manage ep0 state in software")
Acked-by: default avatarMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarPhil Elwell <phil@raspberrypi.com>
Link: https://lore.kernel.org/r/20210506112200.2893922-1-phil@raspberrypi.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6f26ebb7
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -113,6 +113,7 @@ struct dwc2_hsotg_req;
 * @debugfs: File entry for debugfs file for this endpoint.
 * @debugfs: File entry for debugfs file for this endpoint.
 * @dir_in: Set to true if this endpoint is of the IN direction, which
 * @dir_in: Set to true if this endpoint is of the IN direction, which
 *          means that it is sending data to the Host.
 *          means that it is sending data to the Host.
 * @map_dir: Set to the value of dir_in when the DMA buffer is mapped.
 * @index: The index for the endpoint registers.
 * @index: The index for the endpoint registers.
 * @mc: Multi Count - number of transactions per microframe
 * @mc: Multi Count - number of transactions per microframe
 * @interval: Interval for periodic endpoints, in frames or microframes.
 * @interval: Interval for periodic endpoints, in frames or microframes.
@@ -162,6 +163,7 @@ struct dwc2_hsotg_ep {
	unsigned short		fifo_index;
	unsigned short		fifo_index;


	unsigned char           dir_in;
	unsigned char           dir_in;
	unsigned char           map_dir;
	unsigned char           index;
	unsigned char           index;
	unsigned char           mc;
	unsigned char           mc;
	u16                     interval;
	u16                     interval;
+2 −1
Original line number Original line Diff line number Diff line
@@ -422,7 +422,7 @@ static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg,
{
{
	struct usb_request *req = &hs_req->req;
	struct usb_request *req = &hs_req->req;


	usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in);
	usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->map_dir);
}
}


/*
/*
@@ -1242,6 +1242,7 @@ static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg,
{
{
	int ret;
	int ret;


	hs_ep->map_dir = hs_ep->dir_in;
	ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
	ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
	if (ret)
	if (ret)
		goto dma_error;
		goto dma_error;