Some platforms don't have DMA, but we should still be able to build
USB drivers for these platforms. They could still be used through
vhci_hcd, usbip_host, or maybe something like USB passthrough in UML
from a capable host.

This is admittedly ugly with all the #ifdefs, but it is necessary to
get around linker errors like these:

drivers/built-in.o: In function `dma_unmap_sg_attrs':
include/linux/dma-mapping.h:183: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_unmap_single_attrs':
include/linux/dma-mapping.h:148: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_map_sg_attrs':
include/linux/dma-mapping.h:168: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_map_page':
include/linux/dma-mapping.h:196: undefined reference to `bad_dma_ops'
drivers/built-in.o: In function `dma_mapping_error':
include/linux/dma-mapping.h:430: undefined reference to `bad_dma_ops'
drivers/built-in.o:include/linux/dma-mapping.h:131: more undefined references 
to `bad_dma_ops' follow

If any of the new warnings trigger, the correct solution is almost
certainly to add a CONFIG_HAS_DMA dependency in the Kconfig menu for
the responsible driver.

Signed-off-by: Vegard Nossum <vegard.nos...@oracle.com>
---
 drivers/usb/core/buffer.c | 17 +++++++++++++++++
 drivers/usb/core/hcd.c    | 45 +++++++++++++++++++++++++++++++++++++++------
 include/linux/usb/hcd.h   |  8 ++++++++
 3 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 89f2e77..427b131 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -59,13 +59,16 @@ void __init usb_init_pool_max(void)
  */
 int hcd_buffer_create(struct usb_hcd *hcd)
 {
+#ifdef CONFIG_HAS_DMA
        char            name[16];
        int             i, size;
+#endif
 
        if (!hcd->self.controller->dma_mask &&
            !(hcd->driver->flags & HCD_LOCAL_MEM))
                return 0;
 
+#ifdef CONFIG_HAS_DMA
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                size = pool_max[i];
                if (!size)
@@ -78,6 +81,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
                        return -ENOMEM;
                }
        }
+#endif
        return 0;
 }
 
@@ -91,6 +95,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
  */
 void hcd_buffer_destroy(struct usb_hcd *hcd)
 {
+#ifdef CONFIG_HAS_DMA
        int i;
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -101,6 +106,7 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
                        hcd->pool[i] = NULL;
                }
        }
+#endif
 }
 
 
@@ -116,7 +122,9 @@ void *hcd_buffer_alloc(
 )
 {
        struct usb_hcd          *hcd = bus_to_hcd(bus);
+#ifdef CONFIG_HAS_DMA
        int                     i;
+#endif
 
        /* some USB hosts just use PIO */
        if (!bus->controller->dma_mask &&
@@ -125,11 +133,16 @@ void *hcd_buffer_alloc(
                return kmalloc(size, mem_flags);
        }
 
+#ifdef CONFIG_HAS_DMA
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                if (size <= pool_max[i])
                        return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
        }
        return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
+#else
+       WARN_ON_NO_DMA();
+       return NULL;
+#endif
 }
 
 void hcd_buffer_free(
@@ -140,7 +153,9 @@ void hcd_buffer_free(
 )
 {
        struct usb_hcd          *hcd = bus_to_hcd(bus);
+#ifdef CONFIG_HAS_DMA
        int                     i;
+#endif
 
        if (!addr)
                return;
@@ -151,6 +166,7 @@ void hcd_buffer_free(
                return;
        }
 
+#ifdef CONFIG_HAS_DMA
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                if (size <= pool_max[i]) {
                        dma_pool_free(hcd->pool[i], addr, dma);
@@ -158,4 +174,5 @@ void hcd_buffer_free(
                }
        }
        dma_free_coherent(hcd->self.controller, size, addr, dma);
+#endif
 }
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index df0e3b9..1eb214d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1408,12 +1408,15 @@ static void hcd_free_coherent(struct usb_bus *bus, 
dma_addr_t *dma_handle,
 
 void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
 {
-       if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
+       if (urb->transfer_flags & URB_SETUP_MAP_SINGLE) {
+#ifdef CONFIG_HAS_DMA
                dma_unmap_single(hcd->self.controller,
                                urb->setup_dma,
                                sizeof(struct usb_ctrlrequest),
                                DMA_TO_DEVICE);
-       else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL)
+#endif
+               WARN_ON_NO_DMA();
+       } else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL)
                hcd_free_coherent(urb->dev->bus,
                                &urb->setup_dma,
                                (void **) &urb->setup_packet,
@@ -1440,27 +1443,37 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, 
struct urb *urb)
        usb_hcd_unmap_urb_setup_for_dma(hcd, urb);
 
        dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-       if (urb->transfer_flags & URB_DMA_MAP_SG)
+       if (urb->transfer_flags & URB_DMA_MAP_SG) {
+#ifdef CONFIG_HAS_DMA
                dma_unmap_sg(hcd->self.controller,
                                urb->sg,
                                urb->num_sgs,
                                dir);
-       else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
+#endif
+               WARN_ON_NO_DMA();
+       } else if (urb->transfer_flags & URB_DMA_MAP_PAGE) {
+#ifdef CONFIG_HAS_DMA
                dma_unmap_page(hcd->self.controller,
                                urb->transfer_dma,
                                urb->transfer_buffer_length,
                                dir);
-       else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
+#endif
+               WARN_ON_NO_DMA();
+       } else if (urb->transfer_flags & URB_DMA_MAP_SINGLE) {
+#ifdef CONFIG_HAS_DMA
                dma_unmap_single(hcd->self.controller,
                                urb->transfer_dma,
                                urb->transfer_buffer_length,
                                dir);
-       else if (urb->transfer_flags & URB_MAP_LOCAL)
+#endif
+               WARN_ON_NO_DMA();
+       } else if (urb->transfer_flags & URB_MAP_LOCAL) {
                hcd_free_coherent(urb->dev->bus,
                                &urb->transfer_dma,
                                &urb->transfer_buffer,
                                urb->transfer_buffer_length,
                                dir);
+       }
 
        /* Make it safe to call this routine more than once */
        urb->transfer_flags &= ~(URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
@@ -1493,6 +1506,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                if (hcd->self.uses_pio_for_control)
                        return ret;
                if (hcd->self.uses_dma) {
+#ifdef CONFIG_HAS_DMA
                        urb->setup_dma = dma_map_single(
                                        hcd->self.controller,
                                        urb->setup_packet,
@@ -1502,6 +1516,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                                                urb->setup_dma))
                                return -EAGAIN;
                        urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
+#else
+                       WARN_ON_NO_DMA();
+                       return -EINVAL;
+#endif
                } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
                        ret = hcd_alloc_coherent(
                                        urb->dev->bus, mem_flags,
@@ -1520,6 +1538,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
            && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
                if (hcd->self.uses_dma) {
                        if (urb->num_sgs) {
+#ifdef CONFIG_HAS_DMA
                                int n;
 
                                /* We don't support sg for isoc transfers ! */
@@ -1541,7 +1560,12 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                                if (n != urb->num_sgs)
                                        urb->transfer_flags |=
                                                        URB_DMA_SG_COMBINED;
+#else
+                               WARN_ON_NO_DMA();
+                               ret = -EINVAL;
+#endif
                        } else if (urb->sg) {
+#ifdef CONFIG_HAS_DMA
                                struct scatterlist *sg = urb->sg;
                                urb->transfer_dma = dma_map_page(
                                                hcd->self.controller,
@@ -1554,10 +1578,15 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                                        ret = -EAGAIN;
                                else
                                        urb->transfer_flags |= URB_DMA_MAP_PAGE;
+#else
+                               WARN_ON_NO_DMA();
+                               ret = -EINVAL;
+#endif
                        } else if (is_vmalloc_addr(urb->transfer_buffer)) {
                                WARN_ONCE(1, "transfer buffer not dma 
capable\n");
                                ret = -EAGAIN;
                        } else {
+#ifdef CONFIG_HAS_DMA
                                urb->transfer_dma = dma_map_single(
                                                hcd->self.controller,
                                                urb->transfer_buffer,
@@ -1568,6 +1597,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                                        ret = -EAGAIN;
                                else
                                        urb->transfer_flags |= 
URB_DMA_MAP_SINGLE;
+#else
+                               WARN_ON_NO_DMA();
+                               ret = -EINVAL;
+#endif
                        }
                } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
                        ret = hcd_alloc_coherent(
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 4dcf844..51b816a 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -409,6 +409,14 @@ static inline bool 
hcd_periodic_completion_in_progress(struct usb_hcd *hcd,
        return hcd->high_prio_bh.completing_ep == ep;
 }
 
+#ifdef CONFIG_HAS_DMA
+#define WARN_ON_NO_DMA() do { } while (0)
+#else
+/* If this ever triggers, the correct fix is almost certainly
+ * to add a CONFIG_HAS_DMA dependency in the Kconfig for that driver. */
+#define WARN_ON_NO_DMA() WARN_ONCE(1, "HCD driver tried to use DMA memory")
+#endif
+
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
 extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
                int status);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to