This patch implements separate flag bits to indicate which of transfer_dma
and setup_dma are already valid.  It provides greater flexibility to 
device drivers by allowing for control transfers in which only one of the 
two buffers has been mapped.

The new flag bits are URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP.  
The old symbol USB_NO_DMA_MAP is now defined to be the bitwise-or of 
these two, so existing drivers need no changes to work correctly.

Alterations to the core were minimal.  However, as a side effect of this
patch usb_buffer_map/sync/unmap() can now legally be used for control
transfers.  I also fixed a bug in usb_hcd_giveback_urb(), whereby the code
would attempt to unmap the buffers even for non-DMA host controllers.

Alan Stern


# This is a BitKeeper generated patch for the following project:
# Project Name: greg k-h's linux 2.5 USB kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#                  ChangeSet    1.1646  -> 1.1647 
#       drivers/usb/core/message.c      1.45    -> 1.46   
#       drivers/usb/core/usb.c  1.207   -> 1.208  
#       Documentation/usb/dma.txt       1.1     -> 1.2    
#        include/linux/usb.h    1.141   -> 1.142  
#       drivers/usb/core/hcd.c  1.104   -> 1.105  
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/09      [EMAIL PROTECTED]       1.1647
# Use separate transfer_flags bits for transfer_dma and setup_dma.
# --------------------------------------------
#
diff -Nru a/Documentation/usb/dma.txt b/Documentation/usb/dma.txt
--- a/Documentation/usb/dma.txt Mon Jun  9 16:26:29 2003
+++ b/Documentation/usb/dma.txt Mon Jun  9 16:26:29 2003
@@ -15,10 +15,14 @@
   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".) 
+  bit saying if it's valid.  (Control requests also have "setup_dma" and a
+  corresponding transfer_flags bit.)
 
-- "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.
+- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do
+  it first and set URB_NO_TRANSFER_DMA_MAP or URB_NO_SETUP_DMA_MAP.  (For
+  compatibility with earlier versions of usbcore, URB_NO_DMA_MAP sets
+  both URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_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
@@ -33,7 +37,7 @@
 - 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
+  while guaranteeing that no hidden copies through DMA "bounce" buffers will
   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,
@@ -42,10 +46,19 @@
        void usb_buffer_free (struct usb_device *dev, size_t size,
                void *addr, dma_addr_t dma);
 
+  For control transfers you can use the buffer primitives or not for each
+  of the transfer buffer and setup buffer independently.  Set the bit flags
+  URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which
+  buffers you have prepared.  For non-control transfers URB_NO_SETUP_DMA_MAP
+  is ignored, so you can often just use URB_NO_DMA_MAP (which sets both
+  bits).
+
   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.
+  systems where the I/O would otherwise tie up an IOMMU mapping.  (See
+  Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming"
+  DMA mappings.)
 
   Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
   space-efficient.
@@ -99,6 +112,5 @@
 
        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.
-
+  The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP
+  so that usbcore won't map or unmap the buffer.
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c    Mon Jun  9 16:26:29 2003
+++ b/drivers/usb/core/hcd.c    Mon Jun  9 16:26:29 2003
@@ -1035,15 +1035,16 @@
        /* lower level hcd code should use *_dma exclusively,
         * unless it uses pio or talks to another transport.
         */
-       if (!(urb->transfer_flags & URB_NO_DMA_MAP)
-                       && hcd->controller->dma_mask) {
-               if (usb_pipecontrol (urb->pipe))
+       if (hcd->controller->dma_mask) {
+               if (usb_pipecontrol (urb->pipe)
+                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
                        urb->setup_dma = dma_map_single (
                                        hcd->controller,
                                        urb->setup_packet,
                                        sizeof (struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
-               if (urb->transfer_buffer_length != 0)
+               if (urb->transfer_buffer_length != 0
+                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
                        urb->transfer_dma = dma_map_single (
                                        hcd->controller,
                                        urb->transfer_buffer,
@@ -1410,12 +1411,14 @@
        // It would catch exit/unlink paths for all urbs.
 
        /* lower level hcd code should use *_dma exclusively */
-       if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
-               if (usb_pipecontrol (urb->pipe))
+       if (hcd->controller->dma_mask) {
+               if (usb_pipecontrol (urb->pipe)
+                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
                        pci_unmap_single (hcd->pdev, urb->setup_dma,
                                        sizeof (struct usb_ctrlrequest),
                                        PCI_DMA_TODEVICE);
-               if (urb->transfer_buffer_length != 0)
+               if (urb->transfer_buffer_length != 0
+                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
                        pci_unmap_single (hcd->pdev, urb->transfer_dma,
                                        urb->transfer_buffer_length,
                                        usb_pipein (urb->pipe)
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c        Mon Jun  9 16:26:29 2003
+++ b/drivers/usb/core/message.c        Mon Jun  9 16:26:29 2003
@@ -344,7 +344,8 @@
        if (!io->urbs)
                goto nomem;
 
-       urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT;
+       urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP
+                       | URB_NO_INTERRUPT;
        if (usb_pipein (pipe))
                urb_flags |= URB_SHORT_NOT_OK;
 
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c    Mon Jun  9 16:26:29 2003
+++ b/drivers/usb/core/usb.c    Mon Jun  9 16:26:29 2003
@@ -1234,7 +1234,7 @@
 }
 
 /**
- * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP
+ * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
  * @dev: device the buffer will be used with
  * @size: requested buffer size
  * @mem_flags: affect whether allocation may block
@@ -1245,9 +1245,9 @@
  * specified device.  Such cpu-space buffers are returned along with the DMA
  * address (through the pointer provided).
  *
- * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to
- * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping
- * hardware for long idle periods.  The implementation varies between
+ * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
+ * to avoid behaviors like using "DMA bounce buffers", or tying down I/O
+ * mapping hardware for long idle periods.  The implementation varies between
  * platforms, depending on details of how DMA will work to this device.
  * Using these buffers also helps prevent cacheline sharing problems on
  * architectures where CPU caches are not DMA-coherent.
@@ -1294,14 +1294,13 @@
  * @urb: urb whose transfer_buffer will be mapped
  *
  * Return value is either null (indicating no buffer could be mapped), or
- * the parameter.  URB_NO_DMA_MAP is added to urb->transfer_flags if the
- * operation succeeds.  If the device is connected to this system through
- * a non-DMA controller, this operation always succeeds.
+ * the parameter.  URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags
+ * if the operation succeeds.  If the device is connected to this system
+ * through a non-DMA controller, this operation always succeeds.
  *
  * This call would normally be used for an urb which is reused, perhaps
  * as the target of a large periodic transfer, with usb_buffer_dmasync()
- * calls to synchronize memory and dma state.  It may not be used for
- * control requests.
+ * calls to synchronize memory and dma state.
  *
  * Reverse the effect of this call with usb_buffer_unmap().
  */
@@ -1311,7 +1310,6 @@
        struct device           *controller;
 
        if (!urb
-                       || usb_pipecontrol (urb->pipe)
                        || !urb->dev
                        || !(bus = urb->dev->bus)
                        || !(controller = bus->controller))
@@ -1326,7 +1324,7 @@
        // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
        } else
                urb->transfer_dma = ~0;
-       urb->transfer_flags |= URB_NO_DMA_MAP;
+       urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        return urb;
 }
 
@@ -1340,7 +1338,7 @@
        struct device           *controller;
 
        if (!urb
-                       || !(urb->transfer_flags & URB_NO_DMA_MAP)
+                       || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
                        || !urb->dev
                        || !(bus = urb->dev->bus)
                        || !(controller = bus->controller))
@@ -1365,7 +1363,7 @@
        struct device           *controller;
 
        if (!urb
-                       || !(urb->transfer_flags & URB_NO_DMA_MAP)
+                       || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
                        || !urb->dev
                        || !(bus = urb->dev->bus)
                        || !(controller = bus->controller))
@@ -1391,7 +1389,7 @@
  *
  * The caller is responsible for placing the resulting DMA addresses from
  * the scatterlist into URB transfer buffer pointers, and for setting the
- * URB_NO_DMA_MAP transfer flag in each of those URBs.
+ * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs.
  *
  * Top I/O rates come from queuing URBs, instead of waiting for each one
  * to complete before starting the next I/O.   This is particularly easy
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h       Mon Jun  9 16:26:29 2003
+++ b/include/linux/usb.h       Mon Jun  9 16:26:29 2003
@@ -492,8 +492,10 @@
  */
 #define URB_SHORT_NOT_OK       0x0001  /* report short reads as errors */
 #define URB_ISO_ASAP           0x0002  /* iso-only, urb->start_frame ignored */
-#define URB_NO_DMA_MAP         0x0004  /* urb->*_dma are valid on submit */
-#define URB_ASYNC_UNLINK       0x0008  /* usb_unlink_urb() returns asap */
+#define URB_NO_TRANSFER_DMA_MAP        0x0004  /* urb->transfer_dma valid on submit */
+#define URB_NO_SETUP_DMA_MAP   0x0008  /* urb->setup_dma valid on submit */
+#define URB_NO_DMA_MAP         (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP)
+#define URB_ASYNC_UNLINK       0x0010  /* usb_unlink_urb() returns asap */
 #define URB_NO_FSBR            0x0020  /* UHCI-specific */
 #define URB_ZERO_PACKET                0x0040  /* Finish bulk OUTs with short packet 
*/
 #define URB_NO_INTERRUPT       0x0080  /* HINT: no non-error interrupt needed */
@@ -531,14 +533,15 @@
  *     submission, unlinking, or operation are handled.  Different
  *     kinds of URB can use different flags.
  * @transfer_buffer:  This identifies the buffer to (or from) which
- *     the I/O request will be performed (unless URB_NO_DMA_MAP is set).
- *     This buffer must be suitable for DMA; allocate it with kmalloc()
- *     or equivalent.  For transfers to "in" endpoints, contents of
- *     this buffer will be modified.  This buffer is used for data
+ *     the I/O request will be performed (unless URB_NO_TRANSFER_DMA_MAP
+ *     is set).  This buffer must be suitable for DMA; allocate it with
+ *     kmalloc() or equivalent.  For transfers to "in" endpoints, contents
+ *     of this buffer will be modified.  This buffer is used for data
  *     phases of control transfers.
- * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device
- *     driver is saying that it provided this DMA address, which the host
- *     controller driver should use instead of the transfer_buffer.
+ * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP,
+ *     the device driver is saying that it provided this DMA address,
+ *     which the host controller driver should use instead of the
+ *     transfer_buffer.
  * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
  *     be broken up into chunks according to the current maximum packet
  *     size for the endpoint, which is a function of the configuration
@@ -553,11 +556,10 @@
  * @setup_packet: Only used for control transfers, this points to eight bytes
  *     of setup data.  Control transfers always start by sending this data
  *     to the device.  Then transfer_buffer is read or written, if needed.
- *     (Not used when URB_NO_DMA_MAP is set.)
- * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device
- *     driver has provided this DMA address for the setup packet.  The
- *     host controller driver should use this instead of setup_buffer.
- *     If there is a data phase, its buffer is identified by transfer_dma.
+ *     (Not used when URB_NO_SETUP_DMA_MAP is set.)
+ * @setup_dma: For control transfers with URB_NO_SETUP_DMA_MAP set, the
+ *     device driver has provided this DMA address for the setup packet.
+ *     The host controller driver should use this instead of setup_packet.
  * @start_frame: Returns the initial frame for interrupt or isochronous
  *     transfers.
  * @number_of_packets: Lists the number of ISO transfer buffers.
@@ -589,13 +591,13 @@
  * bounce buffer or talking to an IOMMU),
  * although they're cheap on commodity x86 and ppc hardware.
  *
- * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which
- * tells the host controller driver that no such mapping is needed since
- * the device driver is DMA-aware.  For example, they might allocate a DMA
- * buffer with usb_buffer_alloc(), or call usb_buffer_map().
- * When this transfer flag is provided, host controller drivers will use the
- * dma addresses found in the transfer_dma and/or setup_dma fields rather than
- * determing a dma address themselves.
+ * Alternatively, drivers may pass the URB_NO_xxx_DMA_MAP transfer flags,
+ * which tell the host controller driver that no such mapping is needed since
+ * the device driver is DMA-aware.  For example, a device driver might
+ * allocate a DMA buffer with usb_buffer_alloc() or call usb_buffer_map().
+ * When these transfer flags are provided, host controller drivers will use
+ * the dma addresses found in the transfer_dma and/or setup_dma fields rather
+ * than determining a dma address themselves.
  *
  * Initialization:
  *
@@ -614,7 +616,11 @@
  * should always terminate with a short packet, even if it means adding an
  * extra zero length packet.
  *
- * Control URBs must provide a setup_packet.
+ * Control URBs must provide a setup_packet.  The setup_packet and
+ * transfer_buffer may each be mapped for DMA or not, independently of
+ * the other.  The transfer_flags bits URB_NO_TRANSFER_DMA_MAP and
+ * URB_NO_SETUP_DMA_MAP indicate which buffers have already been mapped.
+ * URB_NO_SETUP_DMA_MAP is ignored for non-control URBs.
  *
  * Interrupt UBS must provide an interval, saying how often (in milliseconds
  * or, for highspeed devices, 125 microsecond units)



-------------------------------------------------------
This SF.net email is sponsored by:  Etnus, makers of TotalView, The best
thread debugger on the planet. Designed with thread debugging features
you've never dreamed of, try TotalView 6 free at www.etnus.com.
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to