]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
usb: dwc3: ep0: Fix ZLP for OUT ep0 requests
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Thu, 24 Sep 2020 08:21:43 +0000 (01:21 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Nov 2020 10:51:38 +0000 (11:51 +0100)
commit 66706077dc89c66a4777a4c6298273816afb848c upstream.

The current ZLP handling for ep0 requests is only for control IN
requests. For OUT direction, DWC3 needs to check and setup for MPS
alignment.

Usually, control OUT requests can indicate its transfer size via the
wLength field of the control message. So usb_request->zero is usually
not needed for OUT direction. To handle ZLP OUT for control endpoint,
make sure the TRB is MPS size.

Cc: stable@vger.kernel.org
Fixes: c7fcdeb2627c ("usb: dwc3: ep0: simplify EP0 state machine")
Fixes: d6e5a549cc4d ("usb: dwc3: simplify ZLP handling")
Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc3/ep0.c

index 59f2e8c31bd1bf94c0b483979ee39b01a45acb84..90f92bf9451b1e4e79062832a4796c057fdf80f6 100644 (file)
@@ -942,12 +942,16 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
 static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
                struct dwc3_ep *dep, struct dwc3_request *req)
 {
+       unsigned int            trb_length = 0;
        int                     ret;
 
        req->direction = !!dep->number;
 
        if (req->request.length == 0) {
-               dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0,
+               if (!req->direction)
+                       trb_length = dep->endpoint.maxpacket;
+
+               dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, trb_length,
                                DWC3_TRBCTL_CONTROL_DATA, false);
                ret = dwc3_ep0_start_trans(dep);
        } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
@@ -994,9 +998,12 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
 
                req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1];
 
+               if (!req->direction)
+                       trb_length = dep->endpoint.maxpacket;
+
                /* Now prepare one extra TRB to align transfer size */
                dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
-                                        0, DWC3_TRBCTL_CONTROL_DATA,
+                                        trb_length, DWC3_TRBCTL_CONTROL_DATA,
                                         false);
                ret = dwc3_ep0_start_trans(dep);
        } else {