[PATCH RFC] usb: musb: do not use dma for control transfers

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

 



The Inventra DMA engine in many instances of the MUSB controller
cannot use DMA for control transfers on EP0, but can use DMA for
all other transfers.

The USB core maps urbs for DMA if hcd->self.uses_dma is true.
(This is true for MUSB as well).

One way to solve this issue is to split the uses_dma flag into
two, one for control transfers and one for "ordinary" transfers.
The patch below implements this.

The original discussion thread for this issue was here [1].
A suggestion by Oliver Neukum to not use a flag describing
exceptions [2] was not tested, as it would mean touching all
the other HCD drivers.

An alternative approach Alan suggested is to have the MUSB HCD
driver unmap an urb if it cannot carry out any transfer using DMA.
We're yet to try this out, and I'll try and put this together in a bit.

[1] http://marc.info/?t=126477582800002&r=1&w=2
[2] http://marc.info/?l=linux-kernel&m=126639787526097&w=2

NYET-Signed-off-by: Anand Gadiyar <gadiyar@xxxxxx>
Cc: Oliver Neukum <oliver@xxxxxxxxxx>
Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Cc: Praveena NADAHALLY <praveen.nadahally@xxxxxxxxxxxxxx>
---
 drivers/usb/core/hcd.c         |    8 +++++---
 drivers/usb/musb/musb_core.c   |    3 +++
 drivers/usb/musb/musb_gadget.c |    4 ++++
 include/linux/usb.h            |    6 +++++-
 4 files changed, 17 insertions(+), 4 deletions(-)

Index: linux-2.6/drivers/usb/core/hcd.c
===================================================================
--- linux-2.6.orig/drivers/usb/core/hcd.c
+++ linux-2.6/drivers/usb/core/hcd.c
@@ -1321,7 +1321,9 @@ static int map_urb_for_dma(struct usb_hc
 	 */
 
 	if (usb_endpoint_xfer_control(&urb->ep->desc)) {
-		if (hcd->self.uses_dma) {
+		if (hcd->self.uses_pio_for_control_xfer)
+			urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		if (!hcd->self.uses_pio_for_control_xfer) {
 			urb->setup_dma = dma_map_single(
 					hcd->self.controller,
 					urb->setup_packet,
@@ -1347,7 +1349,7 @@ static int map_urb_for_dma(struct usb_hc
 	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
 	if (urb->transfer_buffer_length != 0
 	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
-		if (hcd->self.uses_dma) {
+		if (hcd->self.uses_dma_for_ordinary_xfer) {
 			if (urb->num_sgs) {
 				int n = dma_map_sg(
 						hcd->self.controller,
@@ -2147,7 +2149,7 @@ struct usb_hcd *usb_create_hcd (const st
 	usb_bus_init(&hcd->self);
 	hcd->self.controller = dev;
 	hcd->self.bus_name = bus_name;
-	hcd->self.uses_dma = (dev->dma_mask != NULL);
+	hcd->self.uses_dma_for_ordinary_xfer = (dev->dma_mask != NULL);
 
 	init_timer(&hcd->rh_timer);
 	hcd->rh_timer.function = rh_timer_func;
Index: linux-2.6/include/linux/usb.h
===================================================================
--- linux-2.6.orig/include/linux/usb.h
+++ linux-2.6/include/linux/usb.h
@@ -310,7 +310,11 @@ struct usb_bus {
 	struct device *controller;	/* host/master side hardware */
 	int busnum;			/* Bus number (in order of reg) */
 	const char *bus_name;		/* stable id (PCI slot_name etc) */
-	u8 uses_dma;			/* Does the host controller use DMA? */
+	u8 uses_dma_for_ordinary_xfer;	/* Does the host controller use DMA? */
+	u8 uses_pio_for_control_xfer;	/*
+					 * Does the host controller use PIO
+					 * for control transfers?
+					 */
 	u8 otg_port;			/* 0, or number of OTG/HNP port */
 	unsigned is_b_host:1;		/* true during some HNP roleswitches */
 	unsigned b_hnp_enable:1;	/* OTG: did A-Host enable HNP? */
Index: linux-2.6/drivers/usb/musb/musb_core.c
===================================================================
--- linux-2.6.orig/drivers/usb/musb/musb_core.c
+++ linux-2.6/drivers/usb/musb/musb_core.c
@@ -2107,12 +2107,15 @@ bad_config:
 	 * Otherwise, wait till the gadget driver hooks up.
 	 */
 	if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+		struct usb_hcd	*hcd = musb_to_hcd(musb);
+
 		MUSB_HST_MODE(musb);
 		musb->xceiv->default_a = 1;
 		musb->xceiv->state = OTG_STATE_A_IDLE;
 
 		status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
 
+		hcd->self.uses_pio_for_control_xfer = 1;
 		DBG(1, "%s mode, status %d, devctl %02x %c\n",
 			"HOST", status,
 			musb_readb(musb->mregs, MUSB_DEVCTL),
Index: linux-2.6/drivers/usb/musb/musb_gadget.c
===================================================================
--- linux-2.6.orig/drivers/usb/musb/musb_gadget.c
+++ linux-2.6/drivers/usb/musb/musb_gadget.c
@@ -1763,6 +1763,8 @@ int usb_gadget_register_driver(struct us
 		spin_unlock_irqrestore(&musb->lock, flags);
 
 		if (is_otg_enabled(musb)) {
+			struct usb_hcd	*hcd = musb_to_hcd(musb);
+
 			DBG(3, "OTG startup...\n");
 
 			/* REVISIT:  funcall to other code, which also
@@ -1777,6 +1779,8 @@ int usb_gadget_register_driver(struct us
 				musb->gadget_driver = NULL;
 				musb->g.dev.driver = NULL;
 				spin_unlock_irqrestore(&musb->lock, flags);
+			} else {
+				hcd->self.uses_pio_for_control_xfer = 1;
 			}
 		}
 	}
--
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