From: Arnaud Mandy <ext-arnaud.2.mandy@xxxxxxxxx> rewriting of dma code for musb_g_rx function. Signed-off-by: Arnaud Mandy <ext-arnaud.2.mandy@xxxxxxxxx> Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxx> --- drivers/usb/musb/musb_core.c | 10 ++--- drivers/usb/musb/musb_core.h | 2 +- drivers/usb/musb/musb_gadget.c | 93 ++++++++++++++++++++++++++++++++++------ drivers/usb/musb/musb_gadget.h | 2 +- 4 files changed, 85 insertions(+), 22 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index c11d31f..90655df 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1556,7 +1556,7 @@ irqreturn_t musb_interrupt(struct musb *musb) musb_host_rx(musb, ep_num); } else { if (is_peripheral_capable()) - musb_g_rx(musb, ep_num); + musb_g_rx(musb, ep_num, false); } } @@ -1627,14 +1627,11 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) musb_host_rx(musb, epnum); } else { if (is_peripheral_capable()) - musb_g_rx(musb, epnum); + musb_g_rx(musb, epnum, true); } } } } - -#else -#define use_dma 0 #endif /*-------------------------------------------------------------------------*/ @@ -1923,6 +1920,7 @@ bad_config: musb->board_set_power = plat->set_power; musb->set_clock = plat->set_clock; musb->min_power = plat->min_power; + musb->use_dma = use_dma; /* Clock usage is chip-specific ... functional clock (DaVinci, * OMAP2430), or PHY ref (some TUSB6010 boards). All this core @@ -1972,7 +1970,7 @@ bad_config: } #endif /* ideally this would be abstracted in platform setup */ - if (!is_dma_capable() || !musb->dma_controller) + if (!musb->use_dma || !musb->dma_controller) dev->dma_mask = NULL; /* be sure interrupts are disabled before connecting ISR */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index e4a4202..5273a9b 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -116,7 +116,7 @@ struct musb_ep; extern irqreturn_t musb_g_ep0_irq(struct musb *); extern void musb_g_tx(struct musb *, u8); -extern void musb_g_rx(struct musb *, u8); +extern void musb_g_rx(struct musb *, u8, bool); extern void musb_g_reset(struct musb *); extern void musb_g_suspend(struct musb *); extern void musb_g_resume(struct musb *); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 45cd522..83d4ffc 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -584,28 +584,52 @@ static void do_pio_rx(struct musb *musb, struct musb_request *req) /* * Data ready for a request; called from IRQ */ -void musb_g_rx(struct musb *musb, u8 epnum) +void musb_g_rx(struct musb *musb, u8 epnum, bool is_dma) { u16 csr; + struct musb_request *req; struct usb_request *request; void __iomem *mbase = musb->mregs; struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; void __iomem *epio = musb->endpoints[epnum].regs; + struct dma_channel *dma; musb_ep_select(mbase, epnum); + csr = musb_readw(epio, MUSB_RXCSR); +restart: + + if (csr == 0) { + DBG(3, "spurious IRQ\n"); + return; + } + request = next_request(musb_ep); + if (!request) { + DBG(1, "waiting for request for %s (csr %04x)\n", + musb_ep->name, csr); + musb_ep->rx_pending = true; + return; + } - csr = musb_readw(epio, MUSB_RXCSR); + dma = musb_ep->dma; - DBG(4, "<== %s, rxcsr %04x %p\n", musb_ep->end_point.name, - csr, request); + DBG(4, "<== %s, rxcsr %04x %p (dma %s, %s)\n", musb_ep->name, + csr, request, dma ? "enabled" : "disabled", + is_dma ? "true" : "false"); if (csr & MUSB_RXCSR_P_SENTSTALL) { + DBG(5, "ep%d is halted, cannot transfer\n", epnum); csr |= MUSB_RXCSR_P_WZC_BITS; csr &= ~MUSB_RXCSR_P_SENTSTALL; musb_writew(epio, MUSB_RXCSR, csr); + if (dma != NULL && + dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { + dma->status = MUSB_DMA_STATUS_CORE_ABORT; + musb->dma_controller->channel_abort(dma); + } + if (request) musb_g_giveback(musb_ep, request, -EPIPE); return; @@ -625,21 +649,62 @@ void musb_g_rx(struct musb *musb, u8 epnum) DBG(4, "%s, incomprx\n", musb_ep->end_point.name); } - /* analyze request if the ep is hot */ - if (request) { - do_pio_rx(musb, to_musb_request(request)); - } else { - DBG(3, "packet waiting for %s%s request\n", - musb_ep->desc ? "" : "inactive ", - musb_ep->end_point.name); - musb_ep->rx_pending = true; + req = to_musb_request(request); + + BUG_ON(dma == NULL && (csr & MUSB_RXCSR_DMAENAB)); + + if (dma != NULL) { + u32 len; + + /* We do handle stalls yet. */ + BUG_ON(csr & MUSB_RXCSR_P_SENDSTALL); + + /* We abort() so dma->actual_len gets updated */ + musb->dma_controller->channel_abort(dma); + + /* We only expect full packets. */ + BUG_ON(dma->actual_len & (musb_ep->packet_sz - 1)); + + request->actual += dma->actual_len; + len = dma->actual_len; + + stop_dma(musb, musb_ep, req); + dma = NULL; + + DBG(4, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n", + epnum, csr, musb_readw(epio, MUSB_RXCSR), + len, request); + + if (!is_dma) { + /* Unload with pio */ + do_pio_rx(musb, req); + } else { + BUG_ON(request->actual != request->length); + musb_g_giveback(musb_ep, request, 0); + } + return; + } + + if (dma == NULL && musb->use_dma) { + if (start_dma(musb, req) == 0) + dma = musb_ep->dma; + } + + if (dma == NULL) { + do_pio_rx(musb, req); + csr = musb_readw(epio, MUSB_RXCSR); + if (csr & MUSB_RXCSR_RXPKTRDY) { + DBG(2, "new packet in FIFO, restarting RX " + "(CSR %04x)\n", csr); + goto restart; + } } } /* ------------------------------------------------------------ */ static int musb_gadget_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) + const struct usb_endpoint_descriptor *desc) { unsigned long flags; struct musb_ep *musb_ep; @@ -934,7 +999,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, if (!request->tx && musb_ep->rx_pending) { DBG(1, "processing pending RX\n"); musb_ep->rx_pending = false; - musb_g_rx(musb, musb_ep->current_epnum); + musb_g_rx(musb, musb_ep->current_epnum, false); } cleanup: diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index f9cb3a8..3e62716 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h @@ -98,7 +98,7 @@ static inline struct usb_request *next_request(struct musb_ep *ep) } extern void musb_g_tx(struct musb *musb, u8 epnum); -extern void musb_g_rx(struct musb *musb, u8 epnum); +extern void musb_g_rx(struct musb *musb, u8 epnum, bool); extern const struct usb_ep_ops musb_g_ep0_ops; -- 1.6.4.2.253.g0b1fac -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html