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)
committerFelipe Balbi <balbi@kernel.org>
Fri, 2 Oct 2020 06:57:44 +0000 (09:57 +0300)
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>
drivers/usb/dwc3/ep0.c

index b0363e3ba4d14a18f7c3012e3a2a62542f881d07..5580caed8b0cb087307612b18bd058e4acdba5eb 100644 (file)
@@ -947,12 +947,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)
@@ -999,9 +1003,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 {