Attached is a patch leveraging some of the new generic dma stuff:

- Replaces dma mapping calls in usbcore with generic equivalents.
  This is a minor code shrink (which we'd hoped could happen).

- Pass dma mask along, so net drivers can notice it'd be good to
  set NETIF_F_HIGHDMA; or scsi ones can set highmem_io.  (Some
  Intel EHCI setups are able to support this kind of DMA.)

- Updates one net driver (usbnet) to set NETIF_F_HIGHDMA when
  appropriate, mostly as an example (since I can't test this).

- Provides Documentation/usb/dma.txt, describing current APIs.
  (Unchanged by this patch, except dma mask visibility.)

- Converted another info() to dev_info(), and likewise a couple
  dbg() to dev_dbg() conversions in the modified routine.

The number of FIXMEs was conserved: the generic API doesn't yet
fix the error reporting bugs in the PCI-specific mapping API.

- Dave



--- ./include/linux-dist/usb.h  Tue Dec 24 09:59:08 2002
+++ ./include/linux/usb.h       Tue Dec 24 13:41:22 2002
@@ -28,14 +28,6 @@
                mdelay(ms);
 }
 
-/*
- * USB device number allocation bitmap. There's one bitmap
- * per USB tree.
- */
-struct usb_devmap {
-       unsigned long devicemap[128 / (8*sizeof(unsigned long))];
-};
-
 struct usb_device;
 
 /*-------------------------------------------------------------------------*/
@@ -159,10 +151,16 @@
 
 struct usb_operations;
 
+/* USB device number allocation bitmap */
+struct usb_devmap {
+       unsigned long devicemap[128 / (8*sizeof(unsigned long))];
+};
+
 /*
- * Allocated per bus we have
+ * Allocated per bus (tree of devices) we have:
  */
 struct usb_bus {
+       struct device *controller;      /* host/master side hardware */
        int busnum;                     /* Bus number (in order of reg) */
        char *bus_name;                 /* stable id (PCI slot_name etc) */
 
--- ./drivers/usb-dist/core/hcd.h       Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/hcd.h    Tue Dec 24 13:41:22 2002
@@ -145,26 +145,6 @@
                        dma_addr_t *dma);
        void (*buffer_free)(struct usb_bus *bus, size_t size,
                        void *addr, dma_addr_t dma);
-
-       int (*buffer_map) (struct usb_bus *bus,
-               void *addr, dma_addr_t *dma,
-               size_t size, int direction);
-       void (*buffer_dmasync) (struct usb_bus *bus,
-               dma_addr_t dma,
-               size_t size, int direction);
-       void (*buffer_unmap) (struct usb_bus *bus,
-               dma_addr_t dma,
-               size_t size, int direction);
-
-       int (*buffer_map_sg) (struct usb_bus *bus,
-               struct scatterlist *sg, int *n_hw_ents,
-               int nents, int direction);
-       void (*buffer_dmasync_sg) (struct usb_bus *bus,
-               struct scatterlist *sg,
-               int n_hw_ents, int direction);
-       void (*buffer_unmap_sg) (struct usb_bus *bus,
-               struct scatterlist *sg,
-               int n_hw_ents, int direction);
 };
 
 /* each driver provides one of these, and hardware init support */
@@ -248,23 +228,6 @@
 void hcd_buffer_free (struct usb_bus *bus, size_t size,
        void *addr, dma_addr_t dma);
 
-int hcd_buffer_map (struct usb_bus *bus,
-       void *addr, dma_addr_t *dma,
-       size_t size, int direction);
-void hcd_buffer_dmasync (struct usb_bus *bus,
-       dma_addr_t dma,
-       size_t size, int direction);
-void hcd_buffer_unmap (struct usb_bus *bus,
-       dma_addr_t dma,
-       size_t size, int direction);
-int hcd_buffer_map_sg (struct usb_bus *bus, struct scatterlist *sg,
-                      int *n_hw_ents, int nents, int direction);
-void hcd_buffer_sync_sg (struct usb_bus *bus, struct scatterlist *sg,
-                        int n_hw_ents, int direction);
-
-void hcd_buffer_unmap_sg (struct usb_bus *bus, struct scatterlist *sg,
-                         int n_hw_ents, int direction);
-
 /* generic bus glue, needed for host controllers that don't use PCI */
 extern struct usb_operations usb_hcd_operations;
 extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
--- ./drivers/usb-dist/core/hcd-pci.c   Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/hcd-pci.c        Tue Dec 24 13:41:22 2002
@@ -138,7 +138,8 @@
        hcd->pdev = dev;
        hcd->self.bus_name = dev->slot_name;
        hcd->product_desc = dev->dev.name;
-       hcd->controller = &dev->dev;
+       hcd->self.controller = &dev->dev;
+       hcd->controller = hcd->self.controller;
 
        if ((retval = hcd_buffer_create (hcd)) != 0) {
 clean_3:
--- ./drivers/usb-dist/core/usb.c       Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/usb.c    Tue Dec 24 13:41:22 2002
@@ -41,6 +41,11 @@
 #endif
 #include <linux/usb.h>
 
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
 #include "hcd.h"
 #include "usb.h"
 
@@ -803,7 +808,7 @@
 
        *pdev = NULL;
 
-       info("USB disconnect on device %d", dev->devnum);
+       dev_info (dev->dev, "USB disconnect, address %d\n", dev->devnum);
 
        /* Free up all the children before we remove this device */
        for (i = 0; i < USB_MAXCHILDREN; i++) {
@@ -812,7 +817,7 @@
                        usb_disconnect(child);
        }
 
-       dbg ("unregistering interfaces on device %d", dev->devnum);
+       dev_dbg (dev->dev, "unregistering interfaces\n");
        if (dev->actconfig) {
                for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
                        struct usb_interface *interface = 
&dev->actconfig->interface[i];
@@ -822,7 +827,7 @@
                }
        }
 
-       dbg ("unregistering the device %d", dev->devnum);
+       dev_dbg (dev->dev, "unregistering device\n");
        /* Free the device number and remove the /proc/bus/usb entry */
        if (dev->devnum > 0) {
                clear_bit(dev->devnum, dev->bus->devmap.devicemap);
@@ -980,6 +985,9 @@
                sprintf (&dev->dev.bus_id[0], "%d-%s",
                         dev->bus->busnum, dev->devpath);
 
+       /* dma masks come from the controller; readonly, except to hcd */
+       dev->dev.dma_mask = parent->dma_mask;
+
        /* USB device state == default ... it's not usable yet */
 
        /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
@@ -1104,6 +1112,7 @@
                interface->dev.parent = &dev->dev;
                interface->dev.driver = NULL;
                interface->dev.bus = &usb_bus_type;
+               interface->dev.dma_mask = parent->dma_mask;
                sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
                         dev->bus->busnum, dev->devpath,
                         desc->bInterfaceNumber);
@@ -1206,24 +1215,21 @@
 struct urb *usb_buffer_map (struct urb *urb)
 {
        struct usb_bus          *bus;
-       struct usb_operations   *op;
+       struct device           *controller;
 
        if (!urb
                        || usb_pipecontrol (urb->pipe)
                        || !urb->dev
                        || !(bus = urb->dev->bus)
-                       || !(op = bus->op)
-                       || !op->buffer_map)
+                       || !(controller = bus->controller))
                return 0;
 
-       if (op->buffer_map (bus,
-                       urb->transfer_buffer,
-                       &urb->transfer_dma,
-                       urb->transfer_buffer_length,
+       urb->transfer_dma = dma_map_single (controller,
+                       urb->transfer_buffer, urb->transfer_buffer_length,
                        usb_pipein (urb->pipe)
-                               ? USB_DIR_IN
-                               : USB_DIR_OUT))
-               return 0;
+                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       // FIXME generic api broken like pci, can't report errors
+       // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
        urb->transfer_flags |= URB_NO_DMA_MAP;
        return urb;
 }
@@ -1235,22 +1241,19 @@
 void usb_buffer_dmasync (struct urb *urb)
 {
        struct usb_bus          *bus;
-       struct usb_operations   *op;
+       struct device           *controller;
 
        if (!urb
                        || !(urb->transfer_flags & URB_NO_DMA_MAP)
                        || !urb->dev
                        || !(bus = urb->dev->bus)
-                       || !(op = bus->op)
-                       || !op->buffer_dmasync)
+                       || !(controller = bus->controller))
                return;
 
-       op->buffer_dmasync (bus,
-                       urb->transfer_dma,
-                       urb->transfer_buffer_length,
+       dma_sync_single (controller,
+                       urb->transfer_dma, urb->transfer_buffer_length,
                        usb_pipein (urb->pipe)
-                               ? USB_DIR_IN
-                               : USB_DIR_OUT);
+                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /**
@@ -1262,23 +1265,21 @@
 void usb_buffer_unmap (struct urb *urb)
 {
        struct usb_bus          *bus;
-       struct usb_operations   *op;
+       struct device           *controller;
 
        if (!urb
                        || !(urb->transfer_flags & URB_NO_DMA_MAP)
                        || !urb->dev
                        || !(bus = urb->dev->bus)
-                       || !(op = bus->op)
-                       || !op->buffer_unmap)
+                       || !(controller = bus->controller))
                return;
 
-       op->buffer_unmap (bus,
-                       urb->transfer_dma,
-                       urb->transfer_buffer_length,
+       dma_unmap_single (controller,
+                       urb->transfer_dma, urb->transfer_buffer_length,
                        usb_pipein (urb->pipe)
-                               ? USB_DIR_IN
-                               : USB_DIR_OUT);
+                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
+
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
@@ -1297,6 +1298,7 @@
  * to complete before starting the next I/O.   This is particularly easy
  * to do with scatterlists.  Just allocate and submit one URB for each DMA
  * mapping entry returned, stopping on the first error or when all succeed.
+ * Better yet, use the usb_sg_*() calls, which do that (and more) for you.
  *
  * This call would normally be used when translating scatterlist requests,
  * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it
@@ -1308,26 +1310,17 @@
                struct scatterlist *sg, int nents)
 {
        struct usb_bus          *bus;
-       struct usb_operations   *op;
-       int n_hw_ents;
+       struct device           *controller;
 
        if (!dev
                        || usb_pipecontrol (pipe)
                        || !(bus = dev->bus)
-                       || !(op = bus->op)
-                       || !op->buffer_map_sg)
-               return -1;
-
-       if (op->buffer_map_sg (bus,
-                              sg,
-                              &n_hw_ents,
-                              nents,
-                              usb_pipein (pipe)
-                                      ? USB_DIR_IN
-                                      : USB_DIR_OUT))
+                       || !(controller = bus->controller))
                return -1;
 
-       return n_hw_ents;
+       // FIXME generic api broken like pci, can't report errors
+       return dma_map_sg (controller, sg, nents,
+                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /**
@@ -1344,20 +1337,15 @@
                struct scatterlist *sg, int n_hw_ents)
 {
        struct usb_bus          *bus;
-       struct usb_operations   *op;
+       struct device           *controller;
 
        if (!dev
                        || !(bus = dev->bus)
-                       || !(op = bus->op)
-                       || !op->buffer_dmasync_sg)
+                       || !(controller = bus->controller))
                return;
 
-       op->buffer_dmasync_sg (bus,
-                              sg,
-                              n_hw_ents,
-                              usb_pipein (pipe)
-                                      ? USB_DIR_IN
-                                      : USB_DIR_OUT);
+       dma_sync_sg (controller, sg, n_hw_ents,
+                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /**
@@ -1373,20 +1361,15 @@
                struct scatterlist *sg, int n_hw_ents)
 {
        struct usb_bus          *bus;
-       struct usb_operations   *op;
+       struct device           *controller;
 
        if (!dev
                        || !(bus = dev->bus)
-                       || !(op = bus->op)
-                       || !op->buffer_unmap_sg)
+                       || !(controller = bus->controller))
                return;
 
-       op->buffer_unmap_sg (bus,
-                            sg,
-                            n_hw_ents,
-                            usb_pipein (pipe)
-                                    ? USB_DIR_IN
-                                    : USB_DIR_OUT);
+       dma_unmap_sg (controller, sg, n_hw_ents,
+                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 
--- ./drivers/usb-dist/core/buffer.c    Tue Dec 24 10:01:02 2002
+++ ./drivers/usb/core/buffer.c Tue Dec 24 13:41:22 2002
@@ -24,11 +24,14 @@
 
 
 /*
- * DMA-Consistent Buffers
+ * DMA-Coherent Buffers
  */
 
 /* FIXME tune these based on pool statistics ... */
 static const size_t    pool_max [HCD_BUFFER_POOLS] = {
+       /* platforms without dma-friendly caches might need to
+        * prevent cacheline sharing...
+        */
        32,
        128,
        512,
@@ -133,98 +136,3 @@
        }
        pci_free_consistent (hcd->pdev, size, addr, dma);
 }
-
-
-/*
- * DMA-Mappings for arbitrary memory buffers
- */
-
-int hcd_buffer_map (
-       struct usb_bus  *bus,
-       void            *addr,
-       dma_addr_t      *dma,
-       size_t          size,
-       int             direction
-) {
-       struct usb_hcd  *hcd = bus->hcpriv;
-
-       // FIXME pci_map_single() has no standard failure mode!
-       *dma = pci_map_single (hcd->pdev, addr, size,
-                       (direction == USB_DIR_IN)
-                               ? PCI_DMA_FROMDEVICE
-                               : PCI_DMA_TODEVICE);
-       return 0;
-}
-
-void hcd_buffer_dmasync (
-       struct usb_bus  *bus,
-       dma_addr_t      dma,
-       size_t          size,
-       int             direction
-) {
-       struct usb_hcd *hcd = bus->hcpriv;
-
-       pci_dma_sync_single (hcd->pdev, dma, size,
-                       (direction == USB_DIR_IN)
-                               ? PCI_DMA_FROMDEVICE
-                               : PCI_DMA_TODEVICE);
-}
-
-void hcd_buffer_unmap (
-       struct usb_bus  *bus,
-       dma_addr_t      dma,
-       size_t          size,
-       int             direction
-) {
-       struct usb_hcd *hcd = bus->hcpriv;
-
-       pci_unmap_single (hcd->pdev, dma, size,
-                       (direction == USB_DIR_IN)
-                               ? PCI_DMA_FROMDEVICE
-                               : PCI_DMA_TODEVICE);
-}
-
-int hcd_buffer_map_sg (
-       struct usb_bus          *bus,
-       struct scatterlist      *sg,
-       int                     *n_hw_ents,
-       int                     nents,
-       int                     direction
-) {
-       struct usb_hcd *hcd = bus->hcpriv;
-
-       // FIXME pci_map_sg() has no standard failure mode!
-       *n_hw_ents = pci_map_sg(hcd->pdev, sg, nents,
-                               (direction == USB_DIR_IN)
-                               ? PCI_DMA_FROMDEVICE
-                               : PCI_DMA_TODEVICE);
-       return 0;
-}
-
-void hcd_buffer_sync_sg (
-       struct usb_bus          *bus,
-       struct scatterlist      *sg,
-       int                     n_hw_ents,
-       int                     direction
-) {
-       struct usb_hcd *hcd = bus->hcpriv;
-
-       pci_dma_sync_sg(hcd->pdev, sg, n_hw_ents,
-                       (direction == USB_DIR_IN)
-                       ? PCI_DMA_FROMDEVICE
-                       : PCI_DMA_TODEVICE);
-}
-
-void hcd_buffer_unmap_sg (
-       struct usb_bus          *bus,
-       struct scatterlist      *sg,
-       int                     n_hw_ents,
-       int                     direction
-) {
-       struct usb_hcd *hcd = bus->hcpriv;
-
-       pci_unmap_sg(hcd->pdev, sg, n_hw_ents,
-                    (direction == USB_DIR_IN)
-                    ? PCI_DMA_FROMDEVICE
-                    : PCI_DMA_TODEVICE);
-}
--- ./drivers/usb-dist/core/hcd.c       Tue Dec 24 10:01:01 2002
+++ ./drivers/usb/core/hcd.c    Tue Dec 24 13:41:22 2002
@@ -1031,19 +1031,19 @@
        /* lower level hcd code should use *_dma exclusively */
        if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
                if (usb_pipecontrol (urb->pipe))
-                       urb->setup_dma = pci_map_single (
-                                       hcd->pdev,
+                       urb->setup_dma = dma_map_single (
+                                       hcd->controller,
                                        urb->setup_packet,
                                        sizeof (struct usb_ctrlrequest),
-                                       PCI_DMA_TODEVICE);
+                                       DMA_TO_DEVICE);
                if (urb->transfer_buffer_length != 0)
-                       urb->transfer_dma = pci_map_single (
-                                       hcd->pdev,
+                       urb->transfer_dma = dma_map_single (
+                                       hcd->controller,
                                        urb->transfer_buffer,
                                        urb->transfer_buffer_length,
                                        usb_pipein (urb->pipe)
-                                           ? PCI_DMA_FROMDEVICE
-                                           : PCI_DMA_TODEVICE);
+                                           ? DMA_FROM_DEVICE
+                                           : DMA_TO_DEVICE);
        }
 
        status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
@@ -1265,12 +1265,6 @@
        .deallocate =           hcd_free_dev,
        .buffer_alloc =         hcd_buffer_alloc,
        .buffer_free =          hcd_buffer_free,
-       .buffer_map =           hcd_buffer_map,
-       .buffer_dmasync =       hcd_buffer_dmasync,
-       .buffer_unmap =         hcd_buffer_unmap,
-       .buffer_map_sg =        hcd_buffer_map_sg,
-       .buffer_dmasync_sg =    hcd_buffer_sync_sg,
-       .buffer_unmap_sg =      hcd_buffer_unmap_sg,
 };
 EXPORT_SYMBOL (usb_hcd_operations);
 
--- ./drivers/usb-dist/host/ohci-sa1111.c       Tue Dec 24 10:01:02 2002
+++ ./drivers/usb/host/ohci-sa1111.c    Tue Dec 24 13:41:22 2002
@@ -176,7 +176,8 @@
        hcd->irq = dev->irq[1];
        hcd->regs = dev->mapbase;
        hcd->pdev = SA1111_FAKE_PCIDEV;
-       hcd->controller = &dev->dev;
+       hcd->self.controller = &dev->dev;
+       hcd->controller = hcd->self.controller;
 
        retval = hcd_buffer_create (hcd);
        if (retval != 0) {
--- ./drivers/usb-dist/host/ehci-hcd.c  Tue Dec 24 10:01:02 2002
+++ ./drivers/usb/host/ehci-hcd.c       Tue Dec 24 13:41:22 2002
@@ -405,9 +405,10 @@
         * streaming mappings for I/O buffers, like pci_map_single(),
         * can return segments above 4GB, if the device allows.
         *
-        * NOTE:  layered drivers can't yet tell when we enable that,
-        * so they can't pass this info along (like NETIF_F_HIGHDMA)
-        * (or like Scsi_Host.highmem_io) ... usb_bus.flags?
+        * NOTE:  the dma mask is visible through dma_supported(), so
+        * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+        * Scsi_Host.highmem_io, and so forth.  It's readonly to all
+        * host side drivers though.
         */
        if (HCC_64BIT_ADDR (hcc_params)) {
                writel (0, &ehci->regs->segment);
--- ./drivers/usb-dist/net/usbnet.c     Tue Dec 24 10:00:59 2002
+++ ./drivers/usb/net/usbnet.c  Tue Dec 24 13:41:22 2002
@@ -146,6 +146,11 @@
 #endif
 #include <linux/usb.h>
 
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
 
 /* minidrivers _could_ be individually configured */
 #define        CONFIG_USB_AN2720
@@ -2169,9 +2174,13 @@
        memcpy (net->dev_addr, node_id, sizeof node_id);
 
        // point-to-point link ... we always use Ethernet headers 
-       // supports win32 interop and the bridge driver.
+       // supports win32 interop (some devices) and the bridge driver.
        ether_setup (net);
 
+       // possible with some EHCI controllers
+       if (dma_supported (&udev->dev, 0xffffffffffffffffULL))
+               net->features |= NETIF_F_HIGHDMA;
+
        net->change_mtu = usbnet_change_mtu;
        net->get_stats = usbnet_get_stats;
        net->hard_start_xmit = usbnet_start_xmit;
--- ./Documentation-dist/usb/dma.txt    Wed Dec 31 16:00:00 1969
+++ ./Documentation/usb/dma.txt Tue Dec 24 13:41:22 2002
@@ -0,0 +1,104 @@
+In Linux 2.5 kernels (and later), USB device drivers have additional control
+over how DMA may be used to perform I/O operations.  The APIs are detailed
+in the kernel usb programming guide (kerneldoc, from the source code).
+
+
+API OVERVIEW
+
+The big picture is that USB drivers can continue to ignore most DMA issues,
+though they still must provide DMA-ready buffers (see DMA-mapping.txt).
+That's how they've worked through the 2.4 (and earlier) kernels.
+
+OR:  they can now be DMA-aware.
+
+- New calls enable DMA-aware drivers, letting them allocate dma buffers and
+  manage dma mappings for existing dma-ready buffers (see below).
+
+- URBs have an additional "transfer_dma" field, as well as a transfer_flags
+  bit saying if it's valid.  (Control requests also needed "setup_dma".) 
+
+- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do it
+  first and set URB_NO_DMA_MAP.  HCDs don't manage dma mappings for urbs.
+
+- There's a new "generic DMA API", parts of which are usable by USB device
+  drivers.  Never use dma_set_mask() on any USB interface or device; that
+  would potentially break all devices sharing that bus.
+
+
+ELIMINATING COPIES
+
+It's good to avoid making CPUs copy data needlessly.  The costs can add up,
+and effects like cache-trashing can impose subtle penalties.
+
+- When you're allocating a buffer for DMA purposes anyway, use the buffer
+  primitives.  Think of them as kmalloc and kfree that give you the right
+  kind of addresses to store in urb->transfer_buffer and urb->transfer_dma,
+  while guaranteeing that hidden copies through DMA "bounce" buffers won't
+  slow things down.  You'd also set URB_NO_DMA_MAP in urb->transfer_flags:
+
+       void *usb_buffer_alloc (struct usb_device *dev, size_t size,
+               int mem_flags, dma_addr_t *dma);
+
+       void usb_buffer_free (struct usb_device *dev, size_t size,
+               void *addr, dma_addr_t dma);
+
+  The memory buffer returned is "dma-coherent"; sometimes you might need to
+  force a consistent memory access ordering by using memory barriers.  It's
+  not using a streaming DMA mapping, so it's good for small transfers on
+  systems where the I/O would otherwise tie up an IOMMU mapping.
+
+  Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
+  space-efficient.
+
+- Devices on some EHCI controllers could handle DMA to/from high memory.
+  Driver probe() routines can notice this using a generic DMA call, then
+  tell higher level code (network, scsi, etc) about it like this:
+
+       if (dma_supported (&intf->dev, 0xffffffffffffffffULL))
+               net->features |= NETIF_F_HIGHDMA;
+
+  That can eliminate dma bounce buffering of requests that originate (or
+  terminate) in high memory, in cases where the buffers aren't allocated
+  with usb_buffer_alloc() but instead are dma-mapped.
+
+
+WORKING WITH EXISTING BUFFERS
+
+Existing buffers aren't usable for DMA without first being mapped into the
+DMA address space of the device.
+
+- When you're using scatterlists, you can map everything at once.  On some
+  systems, this kicks in an IOMMU and turns the scatterlists into single
+  DMA transactions:
+
+       int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int nents);
+
+       void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int n_hw_ents);
+
+       void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int n_hw_ents);
+
+  It's probably easier to use the new usb_sg_*() calls, which do the DMA
+  mapping and apply other tweaks to make scatterlist i/o be fast.
+
+- Some drivers may prefer to work with the model that they're mapping large
+  buffers, synchronizing their safe re-use.  (If there's no re-use, then let
+  usbcore do the map/unmap.)  Large periodic transfers make good examples
+  here, since it's cheaper to just synchronize the buffer than to unmap it
+  each time an urb completes and then re-map it on during resubmission.
+
+  These calls all work with initialized urbs:  urb->dev, urb->pipe,
+  urb->transfer_buffer, and urb->transfer_buffer_length must all be
+  valid when these calls are used:
+
+       struct urb *usb_buffer_map (struct urb *urb);
+
+       void usb_buffer_dmasync (struct urb *urb);
+
+       void usb_buffer_unmap (struct urb *urb);
+
+  The calls manage urb->transfer_dma for you, and set URB_NO_DMA_MAP so that
+  usbcore won't map or unmap the buffer.
+

Reply via email to