On 12/3/2015 7:18 AM, Felipe Balbi wrote:
> So far, dwc3 has always missed request->zero
> handling for every endpoint. Let's implement
> that so we can handle cases where transfer must
> be finished with a ZLP.
> 
> Note that dwc3 is a little special. Even though
> we're dealing with a ZLP, we still need a buffer
> of wMaxPacketSize bytes; to hide that detail from
> every gadget driver, we have a preallocated buffer
> of 1024 bytes (biggest bulk size) to use (and
> share) among all endpoints.
> 
> Reported-by: Ravi B <ravib...@ti.com>
> Signed-off-by: Felipe Balbi <ba...@ti.com>
> ---
> 
> since v1:
>       - remove unnecessary 'free_on_complete' flag
> 
> since v2:
>       - remove unnecessary 'out' label
> 
>  drivers/usb/dwc3/core.h   |  3 +++
>  drivers/usb/dwc3/gadget.c | 50 
> +++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 51 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 36f1cb74588c..29130682e547 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -37,6 +37,7 @@
>  #define DWC3_MSG_MAX 500
>  
>  /* Global constants */
> +#define DWC3_ZLP_BUF_SIZE    1024    /* size of a superspeed bulk */
>  #define DWC3_EP0_BOUNCE_SIZE 512
>  #define DWC3_ENDPOINTS_NUM   32
>  #define DWC3_XHCI_RESOURCES_NUM      2
> @@ -647,6 +648,7 @@ struct dwc3_scratchpad_array {
>   * @ctrl_req: usb control request which is used for ep0
>   * @ep0_trb: trb which is used for the ctrl_req
>   * @ep0_bounce: bounce buffer for ep0
> + * @zlp_buf: used when request->zero is set
>   * @setup_buf: used while precessing STD USB requests
>   * @ctrl_req_addr: dma address of ctrl_req
>   * @ep0_trb: dma address of ep0_trb
> @@ -734,6 +736,7 @@ struct dwc3 {
>       struct usb_ctrlrequest  *ctrl_req;
>       struct dwc3_trb         *ep0_trb;
>       void                    *ep0_bounce;
> +     void                    *zlp_buf;
>       void                    *scratchbuf;
>       u8                      *setup_buf;
>       dma_addr_t              ctrl_req_addr;
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index e341f034296f..e916c11ded59 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -1158,6 +1158,32 @@ out:
>       return ret;
>  }
>  
> +static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep,
> +             struct usb_request *request)
> +{
> +     dwc3_gadget_ep_free_request(ep, request);
> +}
> +
> +static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep)
> +{
> +     struct dwc3_request             *req;
> +     struct usb_request              *request;
> +     struct usb_ep                   *ep = &dep->endpoint;
> +
> +     dwc3_trace(trace_dwc3_gadget, "queueing ZLP\n");
> +     request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
> +     if (!request)
> +             return -ENOMEM;
> +
> +     request->length = 0;
> +     request->buf = dwc->zlp_buf;
> +     request->complete = __dwc3_gadget_ep_zlp_complete;
> +
> +     req = to_dwc3_request(request);
> +
> +     return __dwc3_gadget_ep_queue(dep, req);
> +}
> +
>  static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request 
> *request,
>       gfp_t gfp_flags)
>  {
> @@ -1171,6 +1197,16 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, 
> struct usb_request *request,
>  
>       spin_lock_irqsave(&dwc->lock, flags);
>       ret = __dwc3_gadget_ep_queue(dep, req);
> +
> +     /*
> +      * Okay, here's the thing, if gadget driver has requested for a ZLP by
> +      * setting request->zero, instead of doing magic, we will just queue an
> +      * extra usb_request ourselves so that it gets handled the same way as
> +      * any other request.
> +      */
> +     if (ret == 0 && request->zero && (request->length % ep->maxpacket == 0))
> +             ret = __dwc3_gadget_ep_queue_zlp(dwc, dep);

Hi Felipe,

This causes regression with at least mass storage + Windows host.

When the gadget queues a ZLP, we end up sending two ZLPs which leads
to violating the MSC protocol.

The following fixes it:

-       if (ret == 0 && request->zero && (request->length % ep->maxpacket == 0))
+       if (ret == 0 && request->zero && (request->length % ep->maxpacket == 0) 
&&
+           (request->length != 0))


Regards,
John
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to