powerpc/kernel/iommu: Use largepool as a last resort when !largealloc
[linux-2.6-microblaze.git] / arch / powerpc / kernel / iommu.c
index c00214a..57d6b85 100644 (file)
@@ -72,8 +72,7 @@ static void iommu_debugfs_del(struct iommu_table *tbl)
 
        sprintf(name, "%08lx", tbl->it_index);
        liobn_entry = debugfs_lookup(name, iommu_debugfs_dir);
-       if (liobn_entry)
-               debugfs_remove(liobn_entry);
+       debugfs_remove(liobn_entry);
 }
 #else
 static void iommu_debugfs_add(struct iommu_table *tbl){}
@@ -297,6 +296,15 @@ again:
                        pass++;
                        goto again;
 
+               } else if (pass == tbl->nr_pools + 1) {
+                       /* Last resort: try largepool */
+                       spin_unlock(&pool->lock);
+                       pool = &tbl->large_pool;
+                       spin_lock(&pool->lock);
+                       pool->hint = pool->start;
+                       pass++;
+                       goto again;
+
                } else {
                        /* Give up */
                        spin_unlock_irqrestore(&(pool->lock), flags);
@@ -719,7 +727,6 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid,
 {
        unsigned long sz;
        static int welcomed = 0;
-       struct page *page;
        unsigned int i;
        struct iommu_pool *p;
 
@@ -728,11 +735,11 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid,
        /* number of bytes needed for the bitmap */
        sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
 
-       page = alloc_pages_node(nid, GFP_KERNEL, get_order(sz));
-       if (!page)
-               panic("iommu_init_table: Can't allocate %ld bytes\n", sz);
-       tbl->it_map = page_address(page);
-       memset(tbl->it_map, 0, sz);
+       tbl->it_map = vzalloc_node(sz, nid);
+       if (!tbl->it_map) {
+               pr_err("%s: Can't allocate %ld bytes\n", __func__, sz);
+               return NULL;
+       }
 
        iommu_table_reserve_pages(tbl, res_start, res_end);
 
@@ -774,8 +781,6 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid,
 
 static void iommu_table_free(struct kref *kref)
 {
-       unsigned long bitmap_sz;
-       unsigned int order;
        struct iommu_table *tbl;
 
        tbl = container_of(kref, struct iommu_table, it_kref);
@@ -796,12 +801,8 @@ static void iommu_table_free(struct kref *kref)
        if (!bitmap_empty(tbl->it_map, tbl->it_size))
                pr_warn("%s: Unexpected TCEs\n", __func__);
 
-       /* calculate bitmap size in bytes */
-       bitmap_sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
-
        /* free bitmap */
-       order = get_order(bitmap_sz);
-       free_pages((unsigned long) tbl->it_map, order);
+       vfree(tbl->it_map);
 
        /* free table */
        kfree(tbl);
@@ -897,6 +898,7 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
        unsigned int order;
        unsigned int nio_pages, io_order;
        struct page *page;
+       size_t size_io = size;
 
        size = PAGE_ALIGN(size);
        order = get_order(size);
@@ -923,8 +925,9 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
        memset(ret, 0, size);
 
        /* Set up tces to cover the allocated range */
-       nio_pages = size >> tbl->it_page_shift;
-       io_order = get_iommu_order(size, tbl);
+       size_io = IOMMU_PAGE_ALIGN(size_io, tbl);
+       nio_pages = size_io >> tbl->it_page_shift;
+       io_order = get_iommu_order(size_io, tbl);
        mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
                              mask >> tbl->it_page_shift, io_order, 0);
        if (mapping == DMA_MAPPING_ERROR) {
@@ -939,10 +942,9 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
                         void *vaddr, dma_addr_t dma_handle)
 {
        if (tbl) {
-               unsigned int nio_pages;
+               size_t size_io = IOMMU_PAGE_ALIGN(size, tbl);
+               unsigned int nio_pages = size_io >> tbl->it_page_shift;
 
-               size = PAGE_ALIGN(size);
-               nio_pages = size >> tbl->it_page_shift;
                iommu_free(tbl, dma_handle, nio_pages);
                size = PAGE_ALIGN(size);
                free_pages((unsigned long)vaddr, get_order(size));
@@ -1096,7 +1098,7 @@ int iommu_take_ownership(struct iommu_table *tbl)
 
        spin_lock_irqsave(&tbl->large_pool.lock, flags);
        for (i = 0; i < tbl->nr_pools; i++)
-               spin_lock(&tbl->pools[i].lock);
+               spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock);
 
        iommu_table_release_pages(tbl);
 
@@ -1124,7 +1126,7 @@ void iommu_release_ownership(struct iommu_table *tbl)
 
        spin_lock_irqsave(&tbl->large_pool.lock, flags);
        for (i = 0; i < tbl->nr_pools; i++)
-               spin_lock(&tbl->pools[i].lock);
+               spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock);
 
        memset(tbl->it_map, 0, sz);