struct musb_hw_ep *hw_ep = chdat->hw_ep;
void __iomem *ep_conf = hw_ep->conf;
void __iomem *musb_base = musb->pRegs;
- unsigned long remaining, flags;
+ unsigned long remaining, flags, pio;
int ch;
spin_lock_irqsave(&musb->Lock, flags);
remaining = TUSB_EP_CONFIG_XFR_SIZE(remaining);
channel->dwActualLength = chdat->transfer_len - remaining;
+ pio = chdat->len - channel->dwActualLength;
DBG(2, "DMA remaining %lu/%u\n", remaining, chdat->transfer_len);
- /* Transfer remaining 1 - 31 bytes if DMA worked */
- if (remaining == 0) {
- u32 pio;
+ /* Transfer remaining 1 - 31 bytes */
+ if (pio > 0 && pio < 32) {
u8 *buf;
- pio = chdat->len - channel->dwActualLength;
- buf = phys_to_virt((u32)chdat->dma_addr)
- + chdat->transfer_len;
- if (chdat->tx)
+ DBG(2, "Using PIO for remaining %i bytes\n", pio);
+ buf = phys_to_virt((u32)chdat->dma_addr) + chdat->transfer_len;
+ if (chdat->tx) {
+ consistent_sync(phys_to_virt((u32)chdat->dma_addr),
+ chdat->transfer_len, DMA_TO_DEVICE);
musb_write_fifo(hw_ep, pio, buf);
- else
+ } else {
musb_read_fifo(hw_ep, pio, buf);
+ consistent_sync(phys_to_virt((u32)chdat->dma_addr),
+ chdat->transfer_len, DMA_FROM_DEVICE);
+ }
channel->dwActualLength += pio;
}
if (!chdat->tx)
musb_dma_completion(musb, chdat->epnum, chdat->tx);
- /* We musb terminate short tx transfers manually by setting TXPKTRDY.
+ /* We must terminate short tx transfers manually by setting TXPKTRDY.
* REVISIT: This same problem may occur with other MUSB dma as well.
* Easy to test with g_ether by pinging the MUSB board with ping -s54.
*/
s8 dmareq;
s8 sync_dev;
- if (unlikely(dma_addr & 0x1) || len < 32)
+ if (unlikely(dma_addr & 0x1) || (len < 32) || (len > packet_sz))
return FALSE;
chdat->transfer_len = len & ~0x1f;