USB: Let usb_sg_init to set transfer_buffer more often
authorPete Zaitcev <zaitcev@redhat.com>
Thu, 11 Jun 2009 14:40:39 +0000 (08:40 -0600)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 23 Sep 2009 13:46:19 +0000 (06:46 -0700)
This fix permits the "new" usbmon to access usb-storage's data buffer
without DMA remapping tricks. It should be compatible with PIO controllers
and not add any new crashes. Note that from now on PIO controllers and
usbmon are uniform in their access pattern and if one crashes then
the other will too. Hopefuly neither does.

As a side effect, we get rid for #ifdefs, which were a little ugly.

Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/message.c

index 9720e699f4729737cbdd90946f234e567fc0d874..da718e84d58d17fc0bc66d6f44472bea11484ea8 100644 (file)
@@ -459,35 +459,23 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
                        io->urbs[i]->context = io;
 
                        /*
-                        * Some systems need to revert to PIO when DMA is
-                        * temporarily unavailable.  For their sakes, both
-                        * transfer_buffer and transfer_dma are set when
-                        * possible.  However this can only work on systems
-                        * without:
+                        * Some systems need to revert to PIO when DMA is temporarily
+                        * unavailable.  For their sakes, both transfer_buffer and
+                        * transfer_dma are set when possible.
                         *
-                        *  - HIGHMEM, since DMA buffers located in high memory
-                        *    are not directly addressable by the CPU for PIO;
-                        *
-                        *  - IOMMU, since dma_map_sg() is allowed to use an
-                        *    IOMMU to make virtually discontiguous buffers be
-                        *    "dma-contiguous" so that PIO and DMA need diferent
-                        *    numbers of URBs.
-                        *
-                        * So when HIGHMEM or IOMMU are in use, transfer_buffer
-                        * is NULL to prevent stale pointers and to help spot
-                        * bugs.
+                        * Note that if IOMMU coalescing occurred, we cannot
+                        * trust sg_page anymore, so check if S/G list shrunk.
                         */
+                       if (io->nents == io->entries && !PageHighMem(sg_page(sg)))
+                               io->urbs[i]->transfer_buffer = sg_virt(sg);
+                       else
+                               io->urbs[i]->transfer_buffer = NULL;
+
                        if (dma) {
                                io->urbs[i]->transfer_dma = sg_dma_address(sg);
                                len = sg_dma_len(sg);
-#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
-                               io->urbs[i]->transfer_buffer = NULL;
-#else
-                               io->urbs[i]->transfer_buffer = sg_virt(sg);
-#endif
                        } else {
                                /* hc may use _only_ transfer_buffer */
-                               io->urbs[i]->transfer_buffer = sg_virt(sg);
                                len = sg->length;
                        }