[18/28] usb: dwc3: ep0: fix Data Phase for transfer sizes aligned to wMaxPacketSize

Message ID 20141023145641.GG13573@saruman
State Accepted
Commit 36f84ffb45c75ff10442a9f8f2fd91dcf6c6f5dd
Headers show

Commit Message

Felipe Balbi Oct. 23, 2014, 2:56 p.m.
Hi,

On Thu, Oct 23, 2014 at 10:18:27AM -0400, Alan Stern wrote:
> On Thu, 23 Oct 2014, Felipe Balbi wrote:
> 
> > here's v2:
> > 
> > 8<--------------------------------------------------------------
> > 
> > From 1080b54d66e3e77410b41732e76746ed8e2c01c7 Mon Sep 17 00:00:00 2001
> > From: Felipe Balbi <balbi@ti.com>
> > Date: Tue, 30 Sep 2014 10:39:14 -0500
> > Subject: [PATCH] usb: dwc3: ep0: fix Data Phase for transfer sizes aligned to
> >  wMaxPacketSize
> > 
> > According to Section 8.5.3.2 of the USB 2.0 specification,
> > a USB device must terminate a Data Phase with either a
> > short packet or a ZLP (if the previous transfer was
> > a multiple of wMaxPacketSize).
> > 
> > For reference, here's what the USB 2.0 specification, section
> > 8.5.3.2 says:
> > 
> > "
> > 8.5.3.2 Variable-length Data Stage
> > 
> > A control pipe may have a variable-length data phase
> > in which the host requests more data than is contained
> > in the specified data structure. When all of the data
> > structure is returned to the host, the function should
> > indicate that the Data stage is ended by returning a
> > packet that is shorter than the MaxPacketSize for the
> > pipe. If the data structure is an exact multiple of
> > wMaxPacketSize for the pipe, the function will return
> > a zero-length packet to indicate the end of the Data
> > stage.
> > "
> > 
> > Signed-off-by: Felipe Balbi <balbi@ti.com>
> > ---
> >  drivers/usb/dwc3/ep0.c | 19 +++++++++++++------
> >  1 file changed, 13 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
> > index a47cc1e..ce6b0c7 100644
> > --- a/drivers/usb/dwc3/ep0.c
> > +++ b/drivers/usb/dwc3/ep0.c
> > @@ -828,12 +828,19 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
> >  
> >  		dwc3_ep0_stall_and_restart(dwc);
> >  	} else {
> > -		/*
> > -		 * handle the case where we have to send a zero packet. This
> > -		 * seems to be case when req.length > maxpacket. Could it be?
> > -		 */
> > -		if (r)
> > -			dwc3_gadget_giveback(ep0, r, 0);
> > +		dwc3_gadget_giveback(ep0, r, 0);
> 
> Don't you want to wait until the ZLP has completed before doing the 
> giveback?
> 
> In fact, shouldn't all this ZLP code run when the transfer is 
> submitted, rather than when it completes?  The idea is that you get a 
> request, you queue up all the necessary TRBs or whatever, and if an 
> extra ZLP is needed then you queue up an extra TRB.

yeah, this is desirable but it would require a bigger rework of how we
handle TRBs in dwc3. Currently, for ep0, we have a single TRB and adding
another wouldn't fit into an -rc release. I'll see what I can do to make
this better but as of now we need this bug fix.

> > +
> > +		if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
> > +				ur->zero) {
> 
> Is this correct in the case where ur->length is 0?  When that happens,
> there should be only one ZLP, not two.

and here I was assuming IS_ALIGNED() would handle that case. Here's v3.

8<------------------------------------------------------------------

From 36f84ffb45c75ff10442a9f8f2fd91dcf6c6f5dd Mon Sep 17 00:00:00 2001
From: Felipe Balbi <balbi@ti.com>
Date: Tue, 30 Sep 2014 10:39:14 -0500
Subject: [PATCH] usb: dwc3: ep0: fix Data Phase for transfer sizes aligned to
 wMaxPacketSize

According to Section 8.5.3.2 of the USB 2.0 specification,
a USB device must terminate a Data Phase with either a
short packet or a ZLP (if the previous transfer was
a multiple of wMaxPacketSize).

For reference, here's what the USB 2.0 specification, section
8.5.3.2 says:

"
8.5.3.2 Variable-length Data Stage

A control pipe may have a variable-length data phase
in which the host requests more data than is contained
in the specified data structure. When all of the data
structure is returned to the host, the function should
indicate that the Data stage is ended by returning a
packet that is shorter than the MaxPacketSize for the
pipe. If the data structure is an exact multiple of
wMaxPacketSize for the pipe, the function will return
a zero-length packet to indicate the end of the Data
stage.
"

Signed-off-by: Felipe Balbi <balbi@ti.com>
---
 drivers/usb/dwc3/ep0.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

Patch

diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index a47cc1e..711b230 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -828,12 +828,19 @@  static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 
 		dwc3_ep0_stall_and_restart(dwc);
 	} else {
-		/*
-		 * handle the case where we have to send a zero packet. This
-		 * seems to be case when req.length > maxpacket. Could it be?
-		 */
-		if (r)
-			dwc3_gadget_giveback(ep0, r, 0);
+		dwc3_gadget_giveback(ep0, r, 0);
+
+		if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
+				ur->length && ur->zero) {
+			int ret;
+
+			dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+			ret = dwc3_ep0_start_trans(dwc, epnum,
+					dwc->ctrl_req_addr, 0,
+					DWC3_TRBCTL_CONTROL_DATA);
+			WARN_ON(ret < 0);
+		}
 	}
 }