[rfc/rft/patch 09/19] usb: musb: gadget: dma enabling for musb_gadget rx

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 58e19c1..ee2d127 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1554,7 +1554,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);
 			}
 		}
 
@@ -1625,14 +1625,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
 
 /*-------------------------------------------------------------------------*/
@@ -1921,6 +1918,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
@@ -1970,7 +1968,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

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux