aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/musb_gadget.c
diff options
context:
space:
mode:
authorMing Lei <tom.leiming@gmail.com>2010-09-25 05:50:43 -0500
committerFelipe Balbi <balbi@ti.com>2010-11-05 13:42:31 +0200
commit9001d80df9b1db946ef5d0fb52c974d74c567b86 (patch)
treed0e0487e8617782a1740a68b0af392354c5231bd /drivers/usb/musb/musb_gadget.c
parentc8ddb2713c624f432fa5fe3c7ecffcdda46ea0d4 (diff)
downloadkernel_samsung_smdk4412-9001d80df9b1db946ef5d0fb52c974d74c567b86.zip
kernel_samsung_smdk4412-9001d80df9b1db946ef5d0fb52c974d74c567b86.tar.gz
kernel_samsung_smdk4412-9001d80df9b1db946ef5d0fb52c974d74c567b86.tar.bz2
usb: musb: gadget: fix dma mode 0 in double buffer Rx case
1, In Rx double buffer case, FIFO may have two packets, so rxstate should be called to unload fifo if RXPKTRDY is set even the current request has not been completed. 2, Commit 633ba7876b96ec339ef685357e2f7c60b5a8ce85 introduces autoclear to support double buffer in dma mode 0, so remove clearing RXPKTRDY manually for dma mode 0. 3, Commit c7af6b29ffeffbeb28caf39e5b2ce29b11807c7d may break dma mode 1 for non-doublebuffer endpoint, fix it. With this patch, either usbtest #5 or g_file_storage(writing file to device in usb host) or g_ether have been tested OK in double buffer case(using fifo mode 3). Also, this patch has been verified that single buffer case can't be broken. Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: Anand Gadiyar <gadiyar@ti.com> Cc: Mike Frysinger <vapier@gentoo.org> Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com> Signed-off-by: Ming Lei <tom.leiming@gmail.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb/musb_gadget.c')
-rw-r--r--drivers/usb/musb/musb_gadget.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 5d81504..ce31f07 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -644,10 +644,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
*/
csr |= MUSB_RXCSR_DMAENAB;
- if (!musb_ep->hb_mult &&
- musb_ep->hw_ep->rx_double_buffered)
- csr |= MUSB_RXCSR_AUTOCLEAR;
#ifdef USE_MODE1
+ csr |= MUSB_RXCSR_AUTOCLEAR;
/* csr |= MUSB_RXCSR_DMAMODE; */
/* this special sequence (enabling and then
@@ -656,6 +654,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
*/
musb_writew(epio, MUSB_RXCSR,
csr | MUSB_RXCSR_DMAMODE);
+#else
+ if (!musb_ep->hb_mult &&
+ musb_ep->hw_ep->rx_double_buffered)
+ csr |= MUSB_RXCSR_AUTOCLEAR;
#endif
musb_writew(epio, MUSB_RXCSR, csr);
@@ -807,7 +809,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
/* Autoclear doesn't clear RxPktRdy for short packets */
- if ((dma->desired_mode == 0)
+ if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
|| (dma->actual_len
& (musb_ep->packet_sz - 1))) {
/* ack the read! */
@@ -818,8 +820,16 @@ void musb_g_rx(struct musb *musb, u8 epnum)
/* incomplete, and not short? wait for next IN packet */
if ((request->actual < request->length)
&& (musb_ep->dma->actual_len
- == musb_ep->packet_sz))
+ == musb_ep->packet_sz)) {
+ /* In double buffer case, continue to unload fifo if
+ * there is Rx packet in FIFO.
+ **/
+ csr = musb_readw(epio, MUSB_RXCSR);
+ if ((csr & MUSB_RXCSR_RXPKTRDY) &&
+ hw_ep->rx_double_buffered)
+ goto exit;
return;
+ }
#endif
musb_g_giveback(musb_ep, request, 0);
@@ -827,7 +837,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
if (!request)
return;
}
-
+exit:
/* Analyze request */
rxstate(musb, to_musb_request(request));
}