aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormokopatches <mokopatches@openmoko.org>2008-11-19 17:03:14 +0000
committerLars-Peter Clausen <lars@metafoo.de>2010-05-17 19:49:29 +0200
commit200ef71c3f94b4c152bdb02954297cd0672bc07e (patch)
treea34798f01328984f3f53eb4eaa8bfdfe93b3689f
parent8dd3b11c092dff5aa3892c1e12cbda799fd37891 (diff)
s3c2410_udc-2440_dual_packet-workaround.patch
This is a patch that seems to make the USB hangs on the S3C2440 go away. At least a good amount of ping torture didn't make them come back so far. The issue is that, if there are several back-to-back packets, sometimes no interrupt is generated for one of them. This seems to be caused by the mysterious dual packet mode, which the USB hardware enters automatically if the endpoint size is half that of the FIFO. (On the 2440, this is the normal situation for bulk data endpoints.) There is also a timing factor in this. I think what happens is that the USB hardware automatically sends an acknowledgement if there is only one packet in the FIFO (the FIFO has space for two). If another packet arrives before the host has retrieved and acknowledged the previous one, no interrupt is generated for that second one. However, there may be an indication. There is one undocumented bit (none of the 244x manuals document it), OUT_CRS1_REG[1], that seems to be set suspiciously often when this condition occurs. There is also CLR_DATA_TOGGLE, OUT_CRS1_REG[7], which may have a function related to this. (The Samsung manual is rather terse on that, as usual.) This needs to be examined further. For now, the patch seems to do the trick. Note that this is not a clean solution by any means, because we might potentially get stuck in that interrupt for quite a while.
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index d5f4c1d45c9..e6b76d812c3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -842,6 +842,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
u32 ep_csr1;
u32 idx;
+handle_ep_again:
if (likely (!list_empty(&ep->queue)))
req = list_entry(ep->queue.next,
struct s3c2410_request, queue);
@@ -881,6 +882,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
s3c2410_udc_read_fifo(ep,req);
+ if (s3c2410_udc_fifo_count_out())
+ goto handle_ep_again;
}
}
}