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.
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);
/* 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;
/* 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
* 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 ... */
}
}
spin_unlock(&urb->lock);
+
+ /* already completed */
+ if (!qh) {
+ status = 0;
+ goto done;
+ }
+
+ /* still queued but not found on the list */
if (status)
goto done;