Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / x86_64 / kernel / pci-dma.c
index cab471c..a9275c9 100644 (file)
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <asm/io.h>
+#include <asm/proto.h>
 
-/* Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scatter-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
+int iommu_merge __read_mostly = 0;
+EXPORT_SYMBOL(iommu_merge);
+
+dma_addr_t bad_dma_address __read_mostly;
+EXPORT_SYMBOL(bad_dma_address);
+
+/* This tells the BIO block layer to assume merging. Default to off
+   because we cannot guarantee merging later. */
+int iommu_bio_merge __read_mostly = 0;
+EXPORT_SYMBOL(iommu_bio_merge);
+
+int iommu_sac_force __read_mostly = 0;
+EXPORT_SYMBOL(iommu_sac_force);
+
+int no_iommu __read_mostly;
+#ifdef CONFIG_IOMMU_DEBUG
+int panic_on_overflow __read_mostly = 1;
+int force_iommu __read_mostly = 1;
+#else
+int panic_on_overflow __read_mostly = 0;
+int force_iommu __read_mostly= 0;
+#endif
+
+/* Dummy device used for NULL arguments (normally ISA). Better would
+   be probably a smaller DMA mask, but this is bug-to-bug compatible
+   to i386. */
+struct device fallback_dev = {
+       .bus_id = "fallback device",
+       .coherent_dma_mask = 0xffffffff,
+       .dma_mask = &fallback_dev.coherent_dma_mask,
+};
+
+/* Allocate DMA memory on node near device */
+noinline static void *
+dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
+{
+       struct page *page;
+       int node;
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               node = pcibus_to_node(to_pci_dev(dev)->bus);
+       else
+#endif
+               node = numa_node_id();
+
+       if (node < first_node(node_online_map))
+               node = first_node(node_online_map);
+
+       page = alloc_pages_node(node, gfp, order);
+       return page ? page_address(page) : NULL;
+}
+
+/*
+ * Allocate memory for a coherent mapping.
  */
-int dma_map_sg(struct device *hwdev, struct scatterlist *sg,
-              int nents, int direction)
+void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+                  gfp_t gfp)
 {
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-       for (i = 0; i < nents; i++ ) {
-               struct scatterlist *s = &sg[i];
-               BUG_ON(!s->page); 
-               s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
-               s->dma_length = s->length;
+       void *memory;
+       unsigned long dma_mask = 0;
+       u64 bus;
+
+       if (!dev)
+               dev = &fallback_dev;
+       dma_mask = dev->coherent_dma_mask;
+       if (dma_mask == 0)
+               dma_mask = 0xffffffff;
+
+       /* Don't invoke OOM killer */
+       gfp |= __GFP_NORETRY;
+
+       /* Kludge to make it bug-to-bug compatible with i386. i386
+          uses the normal dma_mask for alloc_coherent. */
+       dma_mask &= *dev->dma_mask;
+
+       /* Why <=? Even when the mask is smaller than 4GB it is often
+          larger than 16MB and in this case we have a chance of
+          finding fitting memory in the next higher zone first. If
+          not retry with true GFP_DMA. -AK */
+       if (dma_mask <= 0xffffffff)
+               gfp |= GFP_DMA32;
+
+ again:
+       memory = dma_alloc_pages(dev, gfp, get_order(size));
+       if (memory == NULL)
+               return NULL;
+
+       {
+               int high, mmu;
+               bus = virt_to_bus(memory);
+               high = (bus + size) >= dma_mask;
+               mmu = high;
+               if (force_iommu && !(gfp & GFP_DMA))
+                       mmu = 1;
+               else if (high) {
+                       free_pages((unsigned long)memory,
+                                  get_order(size));
+
+                       /* Don't use the 16MB ZONE_DMA unless absolutely
+                          needed. It's better to use remapping first. */
+                       if (dma_mask < 0xffffffff && !(gfp & GFP_DMA)) {
+                               gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
+                               goto again;
+                       }
+
+                       /* Let low level make its own zone decisions */
+                       gfp &= ~(GFP_DMA32|GFP_DMA);
+
+                       if (dma_ops->alloc_coherent)
+                               return dma_ops->alloc_coherent(dev, size,
+                                                          dma_handle, gfp);
+                       return NULL;
+               }
+
+               memset(memory, 0, size);
+               if (!mmu) {
+                       *dma_handle = virt_to_bus(memory);
+                       return memory;
+               }
+       }
+
+       if (dma_ops->alloc_coherent) {
+               free_pages((unsigned long)memory, get_order(size));
+               gfp &= ~(GFP_DMA|GFP_DMA32);
+               return dma_ops->alloc_coherent(dev, size, dma_handle, gfp);
+       }
+
+       if (dma_ops->map_simple) {
+               *dma_handle = dma_ops->map_simple(dev, memory,
+                                             size,
+                                             PCI_DMA_BIDIRECTIONAL);
+               if (*dma_handle != bad_dma_address)
+                       return memory;
        }
-       return nents;
-}
 
-EXPORT_SYMBOL(dma_map_sg);
+       if (panic_on_overflow)
+               panic("dma_alloc_coherent: IOMMU overflow by %lu bytes\n",size);
+       free_pages((unsigned long)memory, get_order(size));
+       return NULL;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
 
-/* Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
+/*
+ * Unmap coherent memory.
+ * The caller must ensure that the device has finished accessing the mapping.
  */
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                 int nents, int dir)
+void dma_free_coherent(struct device *dev, size_t size,
+                        void *vaddr, dma_addr_t bus)
+{
+       if (dma_ops->unmap_single)
+               dma_ops->unmap_single(dev, bus, size, 0);
+       free_pages((unsigned long)vaddr, get_order(size));
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+int dma_supported(struct device *dev, u64 mask)
+{
+       if (dma_ops->dma_supported)
+               return dma_ops->dma_supported(dev, mask);
+
+       /* Copied from i386. Doesn't make much sense, because it will
+          only work for pci_alloc_coherent.
+          The caller just has to use GFP_DMA in this case. */
+        if (mask < 0x00ffffff)
+                return 0;
+
+       /* Tell the device to use SAC when IOMMU force is on.  This
+          allows the driver to use cheaper accesses in some cases.
+
+          Problem with this is that if we overflow the IOMMU area and
+          return DAC as fallback address the device may not handle it
+          correctly.
+
+          As a special case some controllers have a 39bit address
+          mode that is as efficient as 32bit (aic79xx). Don't force
+          SAC for these.  Assume all masks <= 40 bits are of this
+          type. Normally this doesn't make any difference, but gives
+          more gentle handling of IOMMU overflow. */
+       if (iommu_sac_force && (mask >= 0xffffffffffULL)) {
+               printk(KERN_INFO "%s: Force SAC with mask %Lx\n", dev->bus_id,mask);
+               return 0;
+       }
+
+       return 1;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 mask)
 {
-       int i;
-       for (i = 0; i < nents; i++) { 
-               struct scatterlist *s = &sg[i];
-               BUG_ON(s->page == NULL); 
-               BUG_ON(s->dma_address == 0); 
-               dma_unmap_single(dev, s->dma_address, s->dma_length, dir);
-       } 
+       if (!dev->dma_mask || !dma_supported(dev, mask))
+               return -EIO;
+       *dev->dma_mask = mask;
+       return 0;
 }
+EXPORT_SYMBOL(dma_set_mask);
+
+/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge]
+         [,forcesac][,fullflush][,nomerge][,biomerge]
+   size  set size of iommu (in bytes)
+   noagp don't initialize the AGP driver and use full aperture.
+   off   don't use the IOMMU
+   leak  turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on)
+   memaper[=order] allocate an own aperture over RAM with size 32MB^order.
+   noforce don't force IOMMU usage. Default.
+   force  Force IOMMU.
+   merge  Do lazy merging. This may improve performance on some block devices.
+          Implies force (experimental)
+   biomerge Do merging at the BIO layer. This is more efficient than merge,
+            but should be only done with very big IOMMUs. Implies merge,force.
+   nomerge Don't do SG merging.
+   forcesac For SAC mode for masks <40bits  (experimental)
+   fullflush Flush IOMMU on each allocation (default)
+   nofullflush Don't use IOMMU fullflush
+   allowed  overwrite iommu off workarounds for specific chipsets.
+   soft         Use software bounce buffering (default for Intel machines)
+   noaperture Don't touch the aperture for AGP.
+*/
+__init int iommu_setup(char *p)
+{
+    iommu_merge = 1;
+
+    while (*p) {
+           if (!strncmp(p,"off",3))
+                   no_iommu = 1;
+           /* gart_parse_options has more force support */
+           if (!strncmp(p,"force",5))
+                   force_iommu = 1;
+           if (!strncmp(p,"noforce",7)) {
+                   iommu_merge = 0;
+                   force_iommu = 0;
+           }
+
+           if (!strncmp(p, "biomerge",8)) {
+                   iommu_bio_merge = 4096;
+                   iommu_merge = 1;
+                   force_iommu = 1;
+           }
+           if (!strncmp(p, "panic",5))
+                   panic_on_overflow = 1;
+           if (!strncmp(p, "nopanic",7))
+                   panic_on_overflow = 0;
+           if (!strncmp(p, "merge",5)) {
+                   iommu_merge = 1;
+                   force_iommu = 1;
+           }
+           if (!strncmp(p, "nomerge",7))
+                   iommu_merge = 0;
+           if (!strncmp(p, "forcesac",8))
+                   iommu_sac_force = 1;
 
-EXPORT_SYMBOL(dma_unmap_sg);
+#ifdef CONFIG_SWIOTLB
+           if (!strncmp(p, "soft",4))
+                   swiotlb = 1;
+#endif
+
+#ifdef CONFIG_GART_IOMMU
+           gart_parse_options(p);
+#endif
+
+           p += strcspn(p, ",");
+           if (*p == ',')
+                   ++p;
+    }
+    return 1;
+}