| From 66706077dc89c66a4777a4c6298273816afb848c Mon Sep 17 00:00:00 2001 |
| From: Thinh Nguyen <Thinh.Nguyen@synopsys.com> |
| Date: Thu, 24 Sep 2020 01:21:43 -0700 |
| Subject: usb: dwc3: ep0: Fix ZLP for OUT ep0 requests |
| |
| From: Thinh Nguyen <Thinh.Nguyen@synopsys.com> |
| |
| 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 | 11 +++++++++-- |
| 1 file changed, 9 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/usb/dwc3/ep0.c |
| +++ b/drivers/usb/dwc3/ep0.c |
| @@ -942,12 +942,16 @@ static void dwc3_ep0_xfer_complete(struc |
| 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(s |
| |
| 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 { |