aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2007-07-22 15:13:13 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-30 13:27:45 -0700
commita12b8db02035673153bbf19bb3641a08bed9e4b8 (patch)
treec168c7816fb9da3e3a1596f42c1def295addf77b
parente31c18804f584dd838a752f6628e8c15bd7a3372 (diff)
USB: fix scatterlist PIO case (IOMMU)
Update the scatterlist logic so that PIO options are also disabled when an IOMMU may have coalesced pages during dma_map_sg() ... it's not just HIGHMEM that can make trouble supporting both PIO and DMA based host controller drivers. There also seems to be a cross-arch issue here, with 64bit powerpc not using an IOMMU define ... and its IOMMU_VMERGE config can always be overridden on the kernel command line. So this is better, but still imperfect. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/message.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 25f63f1096b..ad4b956380d 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -411,15 +411,22 @@ int usb_sg_init (
* 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 HIGHMEM, since DMA buffers located
- * in high memory are not directly addressable by the CPU for
- * PIO ... so when HIGHMEM is in use, transfer_buffer is NULL
+ * work on systems without:
+ *
+ * - 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.
*/
if (dma) {
io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i);
-#ifdef CONFIG_HIGHMEM
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_IOMMU)
io->urbs[i]->transfer_buffer = NULL;
#else
io->urbs[i]->transfer_buffer =