From: Tony Lindgren Date: Thu, 3 May 2007 00:39:18 +0000 (+0000) Subject: musb_hdrc: Avoid host babble by checking tx fifo X-Git-Tag: v2.6.21-omap1~7 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=3f625d7f99e04f0a21fd504cccf930774dbc1562;p=linux-2.6-omap-h63xx.git musb_hdrc: Avoid host babble by checking tx fifo Running a tusb6010 system in host mode would fail with testusb -a -t12 -c1 most of the time with BABBLE errors. Turns out this was caused by incorrect handling of TX FIFONOTEMPTY, where the code did not wait for it to clear. This patch introduces musb_h_tx_flush_fifo(), and makes musb_host.c to use it. Signed-off-by: Tony Lindgren --- diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 440df48c91d..82ece3b20c8 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -107,6 +107,29 @@ static void musb_ep_program(struct musb *pThis, u8 bEnd, struct urb *pUrb, unsigned int nOut, u8 * pBuffer, u32 dwLength); +/* + * Clear TX fifo. Needed to avoid BABBLE errors. + */ +static inline void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) +{ + void __iomem *epio = ep->regs; + u16 csr; + int retries = 1000; + + csr = musb_readw(epio, MGC_O_HDRC_TXCSR); + while (csr & MGC_M_TXCSR_FIFONOTEMPTY) { + DBG(5, "Host TX FIFONOTEMPTY csr: %02x\n", csr); + csr |= MGC_M_TXCSR_FLUSHFIFO; + musb_writew(epio, MGC_O_HDRC_TXCSR, csr); + csr = musb_readw(epio, MGC_O_HDRC_TXCSR); + if (retries-- < 1) { + ERR("Could not flush host TX fifo: csr: %04x\n", csr); + return; + } + mdelay(1); + } +} + /* * Start transmit. Caller is responsible for locking shared resources. * pThis must be locked. @@ -570,14 +593,9 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) if (ep->bIsSharedFifo) { csr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR); if (csr & MGC_M_TXCSR_MODE) { - if (csr & MGC_M_TXCSR_FIFONOTEMPTY) { - /* this shouldn't happen; irq?? */ - ERR("shared fifo not empty?\n"); - musb_writew(ep->regs, MGC_O_HDRC_TXCSR, - MGC_M_TXCSR_FLUSHFIFO); - musb_writew(ep->regs, MGC_O_HDRC_TXCSR, - MGC_M_TXCSR_FRCDATATOG); - } + musb_h_tx_flush_fifo(ep); + musb_writew(ep->regs, MGC_O_HDRC_TXCSR, + MGC_M_TXCSR_FRCDATATOG); } /* clear mode (and everything else) to enable Rx */ musb_writew(ep->regs, MGC_O_HDRC_TXCSR, 0); @@ -683,14 +701,12 @@ static void musb_ep_program(struct musb *pThis, u8 bEnd, /* ASSERT: TXCSR_DMAENAB was already cleared */ /* flush all old state, set default */ - if (csr & MGC_M_TXCSR_FIFONOTEMPTY) - csr |= MGC_M_TXCSR_FLUSHFIFO; + musb_h_tx_flush_fifo(pEnd); csr &= ~(MGC_M_TXCSR_H_NAKTIMEOUT | MGC_M_TXCSR_DMAMODE | MGC_M_TXCSR_FRCDATATOG | MGC_M_TXCSR_H_RXSTALL | MGC_M_TXCSR_H_ERROR - | MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY ); csr |= MGC_M_TXCSR_MODE; @@ -1229,11 +1245,8 @@ void musb_host_tx(struct musb *pThis, u8 bEnd) /* do the proper sequence to abort the transfer in the * usb core; the dma engine should already be stopped. */ -// SCRUB (TX) - if (wTxCsrVal & MGC_M_TXCSR_FIFONOTEMPTY) - wTxCsrVal |= MGC_M_TXCSR_FLUSHFIFO; - wTxCsrVal &= ~(MGC_M_TXCSR_FIFONOTEMPTY - | MGC_M_TXCSR_AUTOSET + musb_h_tx_flush_fifo(pEnd); + wTxCsrVal &= ~(MGC_M_TXCSR_AUTOSET | MGC_M_TXCSR_DMAENAB | MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL @@ -1949,16 +1962,13 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in) * clearing that status is platform-specific... */ } else { -// SCRUB (TX) + musb_h_tx_flush_fifo(ep); csr = musb_readw(epio, MGC_O_HDRC_TXCSR); - if (csr & MGC_M_TXCSR_FIFONOTEMPTY) - csr |= MGC_M_TXCSR_FLUSHFIFO; csr &= ~( MGC_M_TXCSR_AUTOSET | MGC_M_TXCSR_DMAENAB | MGC_M_TXCSR_H_RXSTALL | MGC_M_TXCSR_H_NAKTIMEOUT | MGC_M_TXCSR_H_ERROR - | MGC_M_TXCSR_FIFONOTEMPTY ); musb_writew(epio, MGC_O_HDRC_TXCSR, csr); /* REVISIT may need to clear FLUSHFIFO ... */ @@ -2002,6 +2012,14 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) } } spin_unlock(&urb->lock); + + /* already completed */ + if (!qh) { + status = 0; + goto done; + } + + /* still queued but not found on the list */ if (status) goto done;