]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/pci-gart_64.c
x86: gart alloc_coherent doesn't need to check NULL device argument
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / pci-gart_64.c
index 744126e64950ee5a7bbceb66ec31d7084dc6b42e..0b99d4a06f74a8599248ab0768ee63a1e5b33356 100644 (file)
@@ -67,9 +67,6 @@ static u32 gart_unmapped_entry;
        (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT)
 #define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28))
 
-#define to_pages(addr, size) \
-       (round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT)
-
 #define EMERGENCY_PAGES 32 /* = 128KB */
 
 #ifdef CONFIG_AGP
@@ -85,7 +82,8 @@ AGPEXTERN __u32 *agp_gatt_table;
 static unsigned long next_bit;  /* protected by iommu_bitmap_lock */
 static int need_flush;         /* global flush state. set for each gart wrap */
 
-static unsigned long alloc_iommu(struct device *dev, int size)
+static unsigned long alloc_iommu(struct device *dev, int size,
+                                unsigned long align_mask)
 {
        unsigned long offset, flags;
        unsigned long boundary_size;
@@ -93,16 +91,17 @@ static unsigned long alloc_iommu(struct device *dev, int size)
 
        base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev),
                           PAGE_SIZE) >> PAGE_SHIFT;
-       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+       boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1,
                              PAGE_SIZE) >> PAGE_SHIFT;
 
        spin_lock_irqsave(&iommu_bitmap_lock, flags);
        offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit,
-                                 size, base_index, boundary_size, 0);
+                                 size, base_index, boundary_size, align_mask);
        if (offset == -1) {
                need_flush = 1;
                offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0,
-                                         size, base_index, boundary_size, 0);
+                                         size, base_index, boundary_size,
+                                         align_mask);
        }
        if (offset != -1) {
                next_bit = offset+size;
@@ -239,10 +238,10 @@ nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
  * Caller needs to check if the iommu is needed and flush.
  */
 static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
-                               size_t size, int dir)
+                               size_t size, int dir, unsigned long align_mask)
 {
-       unsigned long npages = to_pages(phys_mem, size);
-       unsigned long iommu_page = alloc_iommu(dev, npages);
+       unsigned long npages = iommu_num_pages(phys_mem, size);
+       unsigned long iommu_page = alloc_iommu(dev, npages, align_mask);
        int i;
 
        if (iommu_page == -1) {
@@ -262,16 +261,6 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
        return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK);
 }
 
-static dma_addr_t
-gart_map_simple(struct device *dev, phys_addr_t paddr, size_t size, int dir)
-{
-       dma_addr_t map = dma_map_area(dev, paddr, size, dir);
-
-       flush_gart();
-
-       return map;
-}
-
 /* Map a single area into the IOMMU */
 static dma_addr_t
 gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir)
@@ -279,12 +268,13 @@ gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir)
        unsigned long bus;
 
        if (!dev)
-               dev = &fallback_dev;
+               dev = &x86_dma_fallback_dev;
 
        if (!need_iommu(dev, paddr, size))
                return paddr;
 
-       bus = gart_map_simple(dev, paddr, size, dir);
+       bus = dma_map_area(dev, paddr, size, dir, 0);
+       flush_gart();
 
        return bus;
 }
@@ -304,7 +294,7 @@ static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
                return;
 
        iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;
-       npages = to_pages(dma_addr, size);
+       npages = iommu_num_pages(dma_addr, size);
        for (i = 0; i < npages; i++) {
                iommu_gatt_base[iommu_page + i] = gart_unmapped_entry;
                CLEAR_LEAK(iommu_page + i);
@@ -343,7 +333,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
                unsigned long addr = sg_phys(s);
 
                if (nonforced_iommu(dev, addr, s->length)) {
-                       addr = dma_map_area(dev, addr, s->length, dir);
+                       addr = dma_map_area(dev, addr, s->length, dir, 0);
                        if (addr == bad_dma_address) {
                                if (i > 0)
                                        gart_unmap_sg(dev, sg, i, dir);
@@ -365,7 +355,7 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start,
                          int nelems, struct scatterlist *sout,
                          unsigned long pages)
 {
-       unsigned long iommu_start = alloc_iommu(dev, pages);
+       unsigned long iommu_start = alloc_iommu(dev, pages, 0);
        unsigned long iommu_page = iommu_start;
        struct scatterlist *s;
        int i;
@@ -387,7 +377,7 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start,
                }
 
                addr = phys_addr;
-               pages = to_pages(s->offset, s->length);
+               pages = iommu_num_pages(s->offset, s->length);
                while (pages--) {
                        iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr);
                        SET_LEAK(iommu_page);
@@ -430,7 +420,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
                return 0;
 
        if (!dev)
-               dev = &fallback_dev;
+               dev = &x86_dma_fallback_dev;
 
        out = 0;
        start = 0;
@@ -470,7 +460,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
 
                seg_size += s->length;
                need = nextneed;
-               pages += to_pages(s->offset, s->length);
+               pages += iommu_num_pages(s->offset, s->length);
                ps = s;
        }
        if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0)
@@ -502,6 +492,41 @@ error:
        return 0;
 }
 
+/* allocate and map a coherent mapping */
+static void *
+gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
+                   gfp_t flag)
+{
+       void *vaddr;
+       unsigned long align_mask;
+
+       vaddr = (void *)__get_free_pages(flag | __GFP_ZERO, get_order(size));
+       if (!vaddr)
+               return NULL;
+
+       align_mask = (1UL << get_order(size)) - 1;
+
+       *dma_addr = dma_map_area(dev, __pa(vaddr), size, DMA_BIDIRECTIONAL,
+                                align_mask);
+       flush_gart();
+
+       if (*dma_addr != bad_dma_address)
+               return vaddr;
+
+       free_pages((unsigned long)vaddr, get_order(size));
+
+       return NULL;
+}
+
+/* free a coherent mapping */
+static void
+gart_free_coherent(struct device *dev, size_t size, void *vaddr,
+                  dma_addr_t dma_addr)
+{
+       gart_unmap_single(dev, dma_addr, size, DMA_BIDIRECTIONAL);
+       free_pages((unsigned long)vaddr, get_order(size));
+}
+
 static int no_agp;
 
 static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
@@ -694,7 +719,6 @@ extern int agp_amd64_init(void);
 
 static struct dma_mapping_ops gart_dma_ops = {
        .map_single                     = gart_map_single,
-       .map_simple                     = gart_map_simple,
        .unmap_single                   = gart_unmap_single,
        .sync_single_for_cpu            = NULL,
        .sync_single_for_device         = NULL,
@@ -704,6 +728,8 @@ static struct dma_mapping_ops gart_dma_ops = {
        .sync_sg_for_device             = NULL,
        .map_sg                         = gart_map_sg,
        .unmap_sg                       = gart_unmap_sg,
+       .alloc_coherent                 = gart_alloc_coherent,
+       .free_coherent                  = gart_free_coherent,
 };
 
 void gart_iommu_shutdown(void)