usb: musb: gadget: fix ZLP sending in musb_g_tx(v1)
authorMing Lei <tom.leiming@gmail.com>
Fri, 24 Sep 2010 10:44:14 +0000 (13:44 +0300)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 22 Oct 2010 17:21:56 +0000 (10:21 -0700)
This patch fixes the problem reported by Sergei:

>how come? we need to send ZLP before giving back the request.
>Well, look at the code ionce again. We need to send ZLP *after*
>request->actual == request->length, but as the check is inserted
>after the ZLP send, ZLP *may* be sent once the first DMA completes,
>not the last.

The patch also has been discussed on the link below:

http://marc.info/?t=128454814900001&r=1&w=2

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Reported-by: Sergei Shtylyov <sshtylyov@mvista.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Anand Gadiyar <gadiyar@ti.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/musb/musb_gadget.c

index 6a8c061b66f1b07f92f89f912ef4962c8da41b2a..3f1cc5a8381f8e6e2a1152e655f3c73216bf3e9d 100644 (file)
@@ -477,40 +477,39 @@ void musb_g_tx(struct musb *musb, u8 epnum)
                                epnum, csr, musb_ep->dma->actual_len, request);
                }
 
-               if (is_dma || request->actual == request->length) {
-                       /*
-                        * First, maybe a terminating short packet. Some DMA
-                        * engines might handle this by themselves.
-                        */
-                       if ((request->zero && request->length
-                               && request->length % musb_ep->packet_sz == 0)
+               /*
+                * First, maybe a terminating short packet. Some DMA
+                * engines might handle this by themselves.
+                */
+               if ((request->zero && request->length
+                       && (request->length % musb_ep->packet_sz == 0)
+                       && (request->actual == request->length))
 #ifdef CONFIG_USB_INVENTRA_DMA
-                               || (is_dma && (!dma->desired_mode ||
-                                       (request->actual &
-                                               (musb_ep->packet_sz - 1))))
+                       || (is_dma && (!dma->desired_mode ||
+                               (request->actual &
+                                       (musb_ep->packet_sz - 1))))
 #endif
-                       ) {
-                               /*
-                                * On DMA completion, FIFO may not be
-                                * available yet...
-                                */
-                               if (csr & MUSB_TXCSR_TXPKTRDY)
-                                       return;
+               ) {
+                       /*
+                        * On DMA completion, FIFO may not be
+                        * available yet...
+                        */
+                       if (csr & MUSB_TXCSR_TXPKTRDY)
+                               return;
 
-                               DBG(4, "sending zero pkt\n");
-                               musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE
-                                               | MUSB_TXCSR_TXPKTRDY);
-                               request->zero = 0;
-                       }
+                       DBG(4, "sending zero pkt\n");
+                       musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE
+                                       | MUSB_TXCSR_TXPKTRDY);
+                       request->zero = 0;
+               }
 
-                       if (request->actual == request->length) {
-                               musb_g_giveback(musb_ep, request, 0);
-                               request = musb_ep->desc ? next_request(musb_ep) : NULL;
-                               if (!request) {
-                                       DBG(4, "%s idle now\n",
-                                               musb_ep->end_point.name);
-                                       return;
-                               }
+               if (request->actual == request->length) {
+                       musb_g_giveback(musb_ep, request, 0);
+                       request = musb_ep->desc ? next_request(musb_ep) : NULL;
+                       if (!request) {
+                               DBG(4, "%s idle now\n",
+                                       musb_ep->end_point.name);
+                               return;
                        }
                }