sparc: Revert generic IOMMU allocator.
[firefly-linux-kernel-4.4.55.git] / arch / sparc / kernel / iommu.c
index 9b16b341b6ae6d02627d185fe927bbd87ca64f56..bfa4d0c2df42db02fdf1518f620511bc458f7ae3 100644 (file)
 #include <linux/errno.h>
 #include <linux/iommu-helper.h>
 #include <linux/bitmap.h>
-#include <linux/hash.h>
-#include <linux/iommu-common.h>
 
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
 
-static DEFINE_PER_CPU(unsigned int, iommu_pool_hash);
-
 #include <asm/iommu.h>
 
 #include "iommu_common.h"
@@ -49,9 +45,8 @@ static        DEFINE_PER_CPU(unsigned int, iommu_pool_hash);
                               "i" (ASI_PHYS_BYPASS_EC_E))
 
 /* Must be invoked under the IOMMU lock. */
-static void iommu_flushall(struct iommu_table *iommu_table)
+static void iommu_flushall(struct iommu *iommu)
 {
-       struct iommu *iommu = container_of(iommu_table, struct iommu, tbl);
        if (iommu->iommu_flushinv) {
                iommu_write(iommu->iommu_flushinv, ~(u64)0);
        } else {
@@ -92,22 +87,93 @@ static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte)
        iopte_val(*iopte) = val;
 }
 
-static struct iommu_tbl_ops iommu_sparc_ops = {
-       .reset  = iommu_flushall
-};
-
-static void setup_iommu_pool_hash(void)
+/* Based almost entirely upon the ppc64 iommu allocator.  If you use the 'handle'
+ * facility it must all be done in one pass while under the iommu lock.
+ *
+ * On sun4u platforms, we only flush the IOMMU once every time we've passed
+ * over the entire page table doing allocations.  Therefore we only ever advance
+ * the hint and cannot backtrack it.
+ */
+unsigned long iommu_range_alloc(struct device *dev,
+                               struct iommu *iommu,
+                               unsigned long npages,
+                               unsigned long *handle)
 {
-       unsigned int i;
-       static bool do_once;
+       unsigned long n, end, start, limit, boundary_size;
+       struct iommu_arena *arena = &iommu->arena;
+       int pass = 0;
 
-       if (do_once)
-               return;
-       do_once = true;
-       for_each_possible_cpu(i)
-               per_cpu(iommu_pool_hash, i) = hash_32(i, IOMMU_POOL_HASHBITS);
+       /* This allocator was derived from x86_64's bit string search */
+
+       /* Sanity check */
+       if (unlikely(npages == 0)) {
+               if (printk_ratelimit())
+                       WARN_ON(1);
+               return DMA_ERROR_CODE;
+       }
+
+       if (handle && *handle)
+               start = *handle;
+       else
+               start = arena->hint;
+
+       limit = arena->limit;
+
+       /* The case below can happen if we have a small segment appended
+        * to a large, or when the previous alloc was at the very end of
+        * the available space. If so, go back to the beginning and flush.
+        */
+       if (start >= limit) {
+               start = 0;
+               if (iommu->flush_all)
+                       iommu->flush_all(iommu);
+       }
+
+ again:
+
+       if (dev)
+               boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+                                     1 << IO_PAGE_SHIFT);
+       else
+               boundary_size = ALIGN(1UL << 32, 1 << IO_PAGE_SHIFT);
+
+       n = iommu_area_alloc(arena->map, limit, start, npages,
+                            iommu->page_table_map_base >> IO_PAGE_SHIFT,
+                            boundary_size >> IO_PAGE_SHIFT, 0);
+       if (n == -1) {
+               if (likely(pass < 1)) {
+                       /* First failure, rescan from the beginning.  */
+                       start = 0;
+                       if (iommu->flush_all)
+                               iommu->flush_all(iommu);
+                       pass++;
+                       goto again;
+               } else {
+                       /* Second failure, give up */
+                       return DMA_ERROR_CODE;
+               }
+       }
+
+       end = n + npages;
+
+       arena->hint = end;
+
+       /* Update handle for SG allocations */
+       if (handle)
+               *handle = end;
+
+       return n;
 }
 
+void iommu_range_free(struct iommu *iommu, dma_addr_t dma_addr, unsigned long npages)
+{
+       struct iommu_arena *arena = &iommu->arena;
+       unsigned long entry;
+
+       entry = (dma_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT;
+
+       bitmap_clear(arena->map, entry, npages);
+}
 
 int iommu_table_init(struct iommu *iommu, int tsbsize,
                     u32 dma_offset, u32 dma_addr_mask,
@@ -121,22 +187,22 @@ int iommu_table_init(struct iommu *iommu, int tsbsize,
        /* Setup initial software IOMMU state. */
        spin_lock_init(&iommu->lock);
        iommu->ctx_lowest_free = 1;
-       iommu->tbl.page_table_map_base = dma_offset;
+       iommu->page_table_map_base = dma_offset;
        iommu->dma_addr_mask = dma_addr_mask;
 
        /* Allocate and initialize the free area map.  */
        sz = num_tsb_entries / 8;
        sz = (sz + 7UL) & ~7UL;
-       iommu->tbl.map = kmalloc_node(sz, GFP_KERNEL, numa_node);
-       if (!iommu->tbl.map)
+       iommu->arena.map = kmalloc_node(sz, GFP_KERNEL, numa_node);
+       if (!iommu->arena.map) {
+               printk(KERN_ERR "IOMMU: Error, kmalloc(arena.map) failed.\n");
                return -ENOMEM;
-       memset(iommu->tbl.map, 0, sz);
-       if (tlb_type != hypervisor)
-               iommu_sparc_ops.reset = NULL; /* not needed on on sun4v */
+       }
+       memset(iommu->arena.map, 0, sz);
+       iommu->arena.limit = num_tsb_entries;
 
-       setup_iommu_pool_hash();
-       iommu_tbl_pool_init(&iommu->tbl, num_tsb_entries, IO_PAGE_SHIFT,
-                           &iommu_sparc_ops, false, 1);
+       if (tlb_type != hypervisor)
+               iommu->flush_all = iommu_flushall;
 
        /* Allocate and initialize the dummy page which we
         * set inactive IO PTEs to point to.
@@ -169,20 +235,18 @@ out_free_dummy_page:
        iommu->dummy_page = 0UL;
 
 out_free_map:
-       kfree(iommu->tbl.map);
-       iommu->tbl.map = NULL;
+       kfree(iommu->arena.map);
+       iommu->arena.map = NULL;
 
        return -ENOMEM;
 }
 
-static inline iopte_t *alloc_npages(struct device *dev,
-                                   struct iommu *iommu,
+static inline iopte_t *alloc_npages(struct device *dev, struct iommu *iommu,
                                    unsigned long npages)
 {
        unsigned long entry;
 
-       entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL,
-                                     __this_cpu_read(iommu_pool_hash));
+       entry = iommu_range_alloc(dev, iommu, npages, NULL);
        if (unlikely(entry == DMA_ERROR_CODE))
                return NULL;
 
@@ -220,7 +284,7 @@ static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
                                   dma_addr_t *dma_addrp, gfp_t gfp,
                                   struct dma_attrs *attrs)
 {
-       unsigned long order, first_page;
+       unsigned long flags, order, first_page;
        struct iommu *iommu;
        struct page *page;
        int npages, nid;
@@ -242,14 +306,16 @@ static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
 
        iommu = dev->archdata.iommu;
 
+       spin_lock_irqsave(&iommu->lock, flags);
        iopte = alloc_npages(dev, iommu, size >> IO_PAGE_SHIFT);
+       spin_unlock_irqrestore(&iommu->lock, flags);
 
        if (unlikely(iopte == NULL)) {
                free_pages(first_page, order);
                return NULL;
        }
 
-       *dma_addrp = (iommu->tbl.page_table_map_base +
+       *dma_addrp = (iommu->page_table_map_base +
                      ((iopte - iommu->page_table) << IO_PAGE_SHIFT));
        ret = (void *) first_page;
        npages = size >> IO_PAGE_SHIFT;
@@ -270,12 +336,16 @@ static void dma_4u_free_coherent(struct device *dev, size_t size,
                                 struct dma_attrs *attrs)
 {
        struct iommu *iommu;
-       unsigned long order, npages;
+       unsigned long flags, order, npages;
 
        npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
        iommu = dev->archdata.iommu;
 
-       iommu_tbl_range_free(&iommu->tbl, dvma, npages, false, NULL);
+       spin_lock_irqsave(&iommu->lock, flags);
+
+       iommu_range_free(iommu, dvma, npages);
+
+       spin_unlock_irqrestore(&iommu->lock, flags);
 
        order = get_order(size);
        if (order < 10)
@@ -305,8 +375,8 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
        npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
 
-       base = alloc_npages(dev, iommu, npages);
        spin_lock_irqsave(&iommu->lock, flags);
+       base = alloc_npages(dev, iommu, npages);
        ctx = 0;
        if (iommu->iommu_ctxflush)
                ctx = iommu_alloc_ctx(iommu);
@@ -315,7 +385,7 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
        if (unlikely(!base))
                goto bad;
 
-       bus_addr = (iommu->tbl.page_table_map_base +
+       bus_addr = (iommu->page_table_map_base +
                    ((base - iommu->page_table) << IO_PAGE_SHIFT));
        ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
        base_paddr = __pa(oaddr & IO_PAGE_MASK);
@@ -426,7 +496,7 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
        npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
        base = iommu->page_table +
-               ((bus_addr - iommu->tbl.page_table_map_base) >> IO_PAGE_SHIFT);
+               ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
        bus_addr &= IO_PAGE_MASK;
 
        spin_lock_irqsave(&iommu->lock, flags);
@@ -445,11 +515,11 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
        for (i = 0; i < npages; i++)
                iopte_make_dummy(iommu, base + i);
 
+       iommu_range_free(iommu, bus_addr, npages);
+
        iommu_free_ctx(iommu, ctx);
-       spin_unlock_irqrestore(&iommu->lock, flags);
 
-       iommu_tbl_range_free(&iommu->tbl, bus_addr, npages,
-                            false, NULL);
+       spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
 static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
@@ -497,7 +567,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        max_seg_size = dma_get_max_seg_size(dev);
        seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
                                  IO_PAGE_SIZE) >> IO_PAGE_SHIFT;
-       base_shift = iommu->tbl.page_table_map_base >> IO_PAGE_SHIFT;
+       base_shift = iommu->page_table_map_base >> IO_PAGE_SHIFT;
        for_each_sg(sglist, s, nelems, i) {
                unsigned long paddr, npages, entry, out_entry = 0, slen;
                iopte_t *base;
@@ -511,8 +581,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
                /* Allocate iommu entries for that segment */
                paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
                npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE);
-               entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, &handle,
-                                             __this_cpu_read(iommu_pool_hash));
+               entry = iommu_range_alloc(dev, iommu, npages, &handle);
 
                /* Handle failure */
                if (unlikely(entry == DMA_ERROR_CODE)) {
@@ -525,7 +594,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
                base = iommu->page_table + entry;
 
                /* Convert entry to a dma_addr_t */
-               dma_addr = iommu->tbl.page_table_map_base +
+               dma_addr = iommu->page_table_map_base +
                        (entry << IO_PAGE_SHIFT);
                dma_addr |= (s->offset & ~IO_PAGE_MASK);
 
@@ -585,17 +654,15 @@ iommu_map_failed:
                        vaddr = s->dma_address & IO_PAGE_MASK;
                        npages = iommu_num_pages(s->dma_address, s->dma_length,
                                                 IO_PAGE_SIZE);
+                       iommu_range_free(iommu, vaddr, npages);
 
-                       entry = (vaddr - iommu->tbl.page_table_map_base)
+                       entry = (vaddr - iommu->page_table_map_base)
                                >> IO_PAGE_SHIFT;
                        base = iommu->page_table + entry;
 
                        for (j = 0; j < npages; j++)
                                iopte_make_dummy(iommu, base + j);
 
-                       iommu_tbl_range_free(&iommu->tbl, vaddr, npages,
-                                            false, NULL);
-
                        s->dma_address = DMA_ERROR_CODE;
                        s->dma_length = 0;
                }
@@ -610,19 +677,17 @@ iommu_map_failed:
 /* If contexts are being used, they are the same in all of the mappings
  * we make for a particular SG.
  */
-static unsigned long fetch_sg_ctx(struct iommu *iommu,
-                                 struct scatterlist *sg)
+static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg)
 {
        unsigned long ctx = 0;
 
        if (iommu->iommu_ctxflush) {
                iopte_t *base;
                u32 bus_addr;
-               struct iommu_table *tbl = &iommu->tbl;
 
                bus_addr = sg->dma_address & IO_PAGE_MASK;
                base = iommu->page_table +
-                      ((bus_addr - tbl->page_table_map_base) >> IO_PAGE_SHIFT);
+                       ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
                ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
        }
@@ -658,8 +723,9 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
                if (!len)
                        break;
                npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE);
+               iommu_range_free(iommu, dma_handle, npages);
 
-               entry = ((dma_handle - iommu->tbl.page_table_map_base)
+               entry = ((dma_handle - iommu->page_table_map_base)
                         >> IO_PAGE_SHIFT);
                base = iommu->page_table + entry;
 
@@ -671,8 +737,6 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
                for (i = 0; i < npages; i++)
                        iopte_make_dummy(iommu, base + i);
 
-               iommu_tbl_range_free(&iommu->tbl, dma_handle, npages, false,
-                                    NULL);
                sg = sg_next(sg);
        }
 
@@ -706,10 +770,9 @@ static void dma_4u_sync_single_for_cpu(struct device *dev,
        if (iommu->iommu_ctxflush &&
            strbuf->strbuf_ctxflush) {
                iopte_t *iopte;
-               struct iommu_table *tbl = &iommu->tbl;
 
                iopte = iommu->page_table +
-                       ((bus_addr - tbl->page_table_map_base)>>IO_PAGE_SHIFT);
+                       ((bus_addr - iommu->page_table_map_base)>>IO_PAGE_SHIFT);
                ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
        }
 
@@ -742,10 +805,9 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev,
        if (iommu->iommu_ctxflush &&
            strbuf->strbuf_ctxflush) {
                iopte_t *iopte;
-               struct iommu_table *tbl = &iommu->tbl;
 
-               iopte = iommu->page_table + ((sglist[0].dma_address -
-                       tbl->page_table_map_base) >> IO_PAGE_SHIFT);
+               iopte = iommu->page_table +
+                       ((sglist[0].dma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
                ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
        }