usb: dwc2: Fix gadget DMA unmap direction
authorPhil Elwell <phil@raspberrypi.com>
Thu, 6 May 2021 11:22:00 +0000 (12:22 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 22 May 2021 08:40:32 +0000 (10:40 +0200)
commit 75a41ce46bae6cbe7d3bb2584eb844291d642874 upstream.

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: fe0b94abcdf6 ("usb: dwc2: gadget: manage ep0 state in software")
Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
Link: https://lore.kernel.org/r/20210506112200.2893922-1-phil@raspberrypi.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c

index 0f45a2f165e5d8bdcc5694332b755c89d007d798..1bb8b1e22ed359aad283b3b99ceaddb364a37c2c 100644 (file)
@@ -164,6 +164,7 @@ struct dwc2_hsotg_req;
  * @lock: State lock to protect contents of endpoint.
  * @dir_in: Set to true if this endpoint is of the IN direction, which
  *          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.
  * @mc: Multi Count - number of transactions per microframe
  * @interval - Interval for periodic endpoints, in frames or microframes.
@@ -207,6 +208,7 @@ struct dwc2_hsotg_ep {
        unsigned short          fifo_index;
 
        unsigned char           dir_in;
+       unsigned char           map_dir;
        unsigned char           index;
        unsigned char           mc;
        u16                     interval;
index 6bde5db1490a191d83eeab953f6a0f4486c52481..e7ad3ae4ea6bd398ada4a54d73460e7f825d30e1 100644 (file)
@@ -308,7 +308,7 @@ static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg,
        if (hs_req->req.length == 0)
                return;
 
-       usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in);
+       usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->map_dir);
 }
 
 /**
@@ -745,6 +745,7 @@ static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg,
        if (hs_req->req.length == 0)
                return 0;
 
+       hs_ep->map_dir = hs_ep->dir_in;
        ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
        if (ret)
                goto dma_error;