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