summaryrefslogtreecommitdiff
path: root/drivers/usb/musb/musb_gadget.c
diff options
context:
space:
mode:
authorSergei Shtylyov <sshtylyov@ru.mvista.com>2009-03-26 18:27:47 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-04-17 10:50:25 -0700
commitb6e434a5404b9ce8c285ea081b6ea5c523b29db4 (patch)
tree8a1d0aac0692859aeb97931b86bf60314b663567 /drivers/usb/musb/musb_gadget.c
parentc7bbc056a92476b3b3d70a8df7cc746ac5d56de7 (diff)
USB: musb: sanitize clearing TXCSR DMA bits (take 2)
The MUSB code clears TXCSR_DMAMODE incorrectly in several places, either asserting that TXCSR_DMAENAB is clear (when sometimes it isn't) or clearing both bits together. Recent versions of the programmer's guide require DMAENAB to be cleared first, although some older ones didn't. Fix this and while at it: - In musb_gadget::txstate(), stop clearing the AUTOSET and DMAMODE bits for the CPPI case since they never get set anyway (the former bit is reserved on DaVinci); but do clear the DMAENAB bit on the DMA error path. - In musb_host::musb_ep_program(), remove the duplicate DMA controller specific code code clearing the TXCSR previous state, add the code to clear TXCSR DMA bits on the Inventra DMA error path, to replace such code (executed late) on the PIO path. - In musbhsdma::dma_channel_abort()/dma_controller_irq(), add/use the 'offset' variable to avoid MUSB_EP_OFFSET() invocations on every RXCSR/TXCSR access. [dbrownell@users.sourceforge.net: don't introduce CamelCase, shrink diff] Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/musb/musb_gadget.c')
-rw-r--r--drivers/usb/musb/musb_gadget.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index c7ebd0867fcc..f79440cdfe7e 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -165,9 +165,15 @@ static void nuke(struct musb_ep *ep, const int status)
if (is_dma_capable() && ep->dma) {
struct dma_controller *c = ep->musb->dma_controller;
int value;
+
if (ep->is_in) {
+ /*
+ * The programming guide says that we must not clear
+ * the DMAMODE bit before DMAENAB, so we only
+ * clear it in the second write...
+ */
musb_writew(epio, MUSB_TXCSR,
- 0 | MUSB_TXCSR_FLUSHFIFO);
+ MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO);
musb_writew(epio, MUSB_TXCSR,
0 | MUSB_TXCSR_FLUSHFIFO);
} else {
@@ -230,7 +236,7 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
| IN token(s) are recd from Host.
| -> DMA interrupt on completion
| calls TxAvail.
- | -> stop DMA, ~DmaEenab,
+ | -> stop DMA, ~DMAENAB,
| -> set TxPktRdy for last short pkt or zlp
| -> Complete Request
| -> Continue next request (call txstate)
@@ -315,9 +321,17 @@ static void txstate(struct musb *musb, struct musb_request *req)
request->dma, request_size);
if (use_dma) {
if (musb_ep->dma->desired_mode == 0) {
- /* ASSERT: DMAENAB is clear */
- csr &= ~(MUSB_TXCSR_AUTOSET |
- MUSB_TXCSR_DMAMODE);
+ /*
+ * We must not clear the DMAMODE bit
+ * before the DMAENAB bit -- and the
+ * latter doesn't always get cleared
+ * before we get here...
+ */
+ csr &= ~(MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_DMAENAB);
+ musb_writew(epio, MUSB_TXCSR, csr
+ | MUSB_TXCSR_P_WZC_BITS);
+ csr &= ~MUSB_TXCSR_DMAMODE;
csr |= (MUSB_TXCSR_DMAENAB |
MUSB_TXCSR_MODE);
/* against programming guide */
@@ -334,10 +348,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
#elif defined(CONFIG_USB_TI_CPPI_DMA)
/* program endpoint CSR first, then setup DMA */
- csr &= ~(MUSB_TXCSR_AUTOSET
- | MUSB_TXCSR_DMAMODE
- | MUSB_TXCSR_P_UNDERRUN
- | MUSB_TXCSR_TXPKTRDY);
+ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
musb_writew(epio, MUSB_TXCSR,
(MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
@@ -364,8 +375,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
if (!use_dma) {
c->channel_release(musb_ep->dma);
musb_ep->dma = NULL;
- /* ASSERT: DMAENAB clear */
- csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE);
+ csr &= ~MUSB_TXCSR_DMAENAB;
+ musb_writew(epio, MUSB_TXCSR, csr);
/* invariant: prequest->buf is non-null */
}
#elif defined(CONFIG_USB_TUSB_OMAP_DMA)