Merge tag 'powerpc-5.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-microblaze.git] / arch / powerpc / kernel / iommu.c
index 30b7736..07093b7 100644 (file)
@@ -688,32 +688,24 @@ static void iommu_table_reserve_pages(struct iommu_table *tbl,
        if (tbl->it_offset == 0)
                set_bit(0, tbl->it_map);
 
-       tbl->it_reserved_start = res_start;
-       tbl->it_reserved_end = res_end;
-
-       /* Check if res_start..res_end isn't empty and overlaps the table */
-       if (res_start && res_end &&
-                       (tbl->it_offset + tbl->it_size < res_start ||
-                        res_end < tbl->it_offset))
-               return;
+       if (res_start < tbl->it_offset)
+               res_start = tbl->it_offset;
 
-       for (i = tbl->it_reserved_start; i < tbl->it_reserved_end; ++i)
-               set_bit(i - tbl->it_offset, tbl->it_map);
-}
+       if (res_end > (tbl->it_offset + tbl->it_size))
+               res_end = tbl->it_offset + tbl->it_size;
 
-static void iommu_table_release_pages(struct iommu_table *tbl)
-{
-       int i;
+       /* Check if res_start..res_end is a valid range in the table */
+       if (res_start >= res_end) {
+               tbl->it_reserved_start = tbl->it_offset;
+               tbl->it_reserved_end = tbl->it_offset;
+               return;
+       }
 
-       /*
-        * In case we have reserved the first bit, we should not emit
-        * the warning below.
-        */
-       if (tbl->it_offset == 0)
-               clear_bit(0, tbl->it_map);
+       tbl->it_reserved_start = res_start;
+       tbl->it_reserved_end = res_end;
 
        for (i = tbl->it_reserved_start; i < tbl->it_reserved_end; ++i)
-               clear_bit(i - tbl->it_offset, tbl->it_map);
+               set_bit(i - tbl->it_offset, tbl->it_map);
 }
 
 /*
@@ -777,6 +769,22 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid,
        return tbl;
 }
 
+bool iommu_table_in_use(struct iommu_table *tbl)
+{
+       unsigned long start = 0, end;
+
+       /* ignore reserved bit0 */
+       if (tbl->it_offset == 0)
+               start = 1;
+       end = tbl->it_reserved_start - tbl->it_offset;
+       if (find_next_bit(tbl->it_map, end, start) != end)
+               return true;
+
+       start = tbl->it_reserved_end - tbl->it_offset;
+       end = tbl->it_size;
+       return find_next_bit(tbl->it_map, end, start) != end;
+}
+
 static void iommu_table_free(struct kref *kref)
 {
        struct iommu_table *tbl;
@@ -793,10 +801,8 @@ static void iommu_table_free(struct kref *kref)
 
        iommu_debugfs_del(tbl);
 
-       iommu_table_release_pages(tbl);
-
        /* verify that table contains no entries */
-       if (!bitmap_empty(tbl->it_map, tbl->it_size))
+       if (iommu_table_in_use(tbl))
                pr_warn("%s: Unexpected TCEs\n", __func__);
 
        /* free bitmap */
@@ -1097,14 +1103,9 @@ int iommu_take_ownership(struct iommu_table *tbl)
        for (i = 0; i < tbl->nr_pools; i++)
                spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock);
 
-       iommu_table_release_pages(tbl);
-
-       if (!bitmap_empty(tbl->it_map, tbl->it_size)) {
+       if (iommu_table_in_use(tbl)) {
                pr_err("iommu_tce: it_map is not empty");
                ret = -EBUSY;
-               /* Undo iommu_table_release_pages, i.e. restore bit#0, etc */
-               iommu_table_reserve_pages(tbl, tbl->it_reserved_start,
-                               tbl->it_reserved_end);
        } else {
                memset(tbl->it_map, 0xff, sz);
        }