]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/pci-nommu.c
x86: move pci-nommu's dma_mask check to common code
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / pci-nommu.c
index aec43d56f49c57cedffaefad7205fbbfe9b984c2..0f51883cc6a87171178f3f2fa571040dd2de7d18 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 
-#include <asm/gart.h>
+#include <asm/iommu.h>
 #include <asm/processor.h>
 #include <asm/dma.h>
 
@@ -72,21 +72,68 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
        return nents;
 }
 
-/* Make sure we keep the same behaviour */
-static int nommu_mapping_error(dma_addr_t dma_addr)
+static void *
+nommu_alloc_coherent(struct device *hwdev, size_t size,
+                    dma_addr_t *dma_addr, gfp_t gfp)
 {
-#ifdef CONFIG_X86_32
-       return 0;
-#else
-       return (dma_addr == bad_dma_address);
+       unsigned long dma_mask;
+       int node;
+       struct page *page;
+
+       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
+       gfp |= __GFP_ZERO;
+
+       dma_mask = hwdev->coherent_dma_mask;
+       if (!dma_mask)
+               dma_mask = *(hwdev->dma_mask);
+
+       if (dma_mask < DMA_24BIT_MASK)
+               return NULL;
+
+       node = dev_to_node(hwdev);
+
+#ifdef CONFIG_X86_64
+       if (dma_mask <= DMA_32BIT_MASK)
+               gfp |= GFP_DMA32;
 #endif
+
+       /* No alloc-free penalty for ISA devices */
+       if (dma_mask == DMA_24BIT_MASK)
+               gfp |= GFP_DMA;
+
+again:
+       page = alloc_pages_node(node, gfp, get_order(size));
+       if (!page)
+               return NULL;
+
+       if ((page_to_phys(page) + size > dma_mask) && !(gfp & GFP_DMA)) {
+               free_pages((unsigned long)page_address(page), get_order(size));
+               gfp |= GFP_DMA;
+               goto again;
+       }
+
+       *dma_addr = page_to_phys(page);
+       if (check_addr("alloc_coherent", hwdev, *dma_addr, size)) {
+               flush_write_buffers();
+               return page_address(page);
+       }
+
+       free_pages((unsigned long)page_address(page), get_order(size));
+
+       return NULL;
 }
 
+static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr,
+                               dma_addr_t dma_addr)
+{
+       free_pages((unsigned long)vaddr, get_order(size));
+}
 
-const struct dma_mapping_ops nommu_dma_ops = {
+struct dma_mapping_ops nommu_dma_ops = {
+       .alloc_coherent = nommu_alloc_coherent,
+       .free_coherent = nommu_free_coherent,
        .map_single = nommu_map_single,
        .map_sg = nommu_map_sg,
-       .mapping_error = nommu_mapping_error,
        .is_phys = 1,
 };