]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/amd: Use ida interface to manage protection domain ID
authorVasant Hegde <vasant.hegde@amd.com>
Wed, 30 Oct 2024 06:35:46 +0000 (06:35 +0000)
committerJoerg Roedel <jroedel@suse.de>
Wed, 30 Oct 2024 10:06:40 +0000 (11:06 +0100)
Replace custom domain ID allocator with IDA interface.

Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/20241030063556.6104-3-vasant.hegde@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/init.c
drivers/iommu/amd/iommu.c

index 601fb4ee69009ee2c3fc394161043b00d2b6a613..e70f6299f765c3e8bfb1baad94662ab51262ef1b 100644 (file)
@@ -912,14 +912,14 @@ struct unity_map_entry {
 /* size of the dma_ops aperture as power of 2 */
 extern unsigned amd_iommu_aperture_order;
 
-/* allocation bitmap for domain ids */
-extern unsigned long *amd_iommu_pd_alloc_bitmap;
-
 extern bool amd_iommu_force_isolation;
 
 /* Max levels of glxval supported */
 extern int amd_iommu_max_glx_val;
 
+/* IDA to track protection domain IDs */
+extern struct ida pdom_ids;
+
 /* Global EFR and EFR2 registers */
 extern u64 amd_iommu_efr;
 extern u64 amd_iommu_efr2;
index ca7ae13968e310b4eced246fe1b844094346d8a4..939b011d6ff2aa3a420a1ac96b8e86240b9f2e8d 100644 (file)
@@ -194,12 +194,6 @@ bool amd_iommu_force_isolation __read_mostly;
 
 unsigned long amd_iommu_pgsize_bitmap __ro_after_init = AMD_IOMMU_PGSIZES;
 
-/*
- * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
- * to know which ones are already in use.
- */
-unsigned long *amd_iommu_pd_alloc_bitmap;
-
 enum iommu_init_state {
        IOMMU_START_STATE,
        IOMMU_IVRS_DETECTED,
@@ -1082,7 +1076,12 @@ static bool __copy_device_table(struct amd_iommu *iommu)
                if (dte_v && dom_id) {
                        pci_seg->old_dev_tbl_cpy[devid].data[0] = old_devtb[devid].data[0];
                        pci_seg->old_dev_tbl_cpy[devid].data[1] = old_devtb[devid].data[1];
-                       __set_bit(dom_id, amd_iommu_pd_alloc_bitmap);
+                       /* Reserve the Domain IDs used by previous kernel */
+                       if (ida_alloc_range(&pdom_ids, dom_id, dom_id, GFP_ATOMIC) != dom_id) {
+                               pr_err("Failed to reserve domain ID 0x%x\n", dom_id);
+                               memunmap(old_devtb);
+                               return false;
+                       }
                        /* If gcr3 table existed, mask it out */
                        if (old_devtb[devid].data[0] & DTE_FLAG_GV) {
                                tmp = DTE_GCR3_VAL_B(~0ULL) << DTE_GCR3_SHIFT_B;
@@ -2985,9 +2984,7 @@ static bool __init check_ioapic_information(void)
 
 static void __init free_dma_resources(void)
 {
-       iommu_free_pages(amd_iommu_pd_alloc_bitmap,
-                        get_order(MAX_DOMAIN_ID / 8));
-       amd_iommu_pd_alloc_bitmap = NULL;
+       ida_destroy(&pdom_ids);
 
        free_unity_maps();
 }
@@ -3055,20 +3052,6 @@ static int __init early_amd_iommu_init(void)
        amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
        DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type);
 
-       /* Device table - directly used by all IOMMUs */
-       ret = -ENOMEM;
-
-       amd_iommu_pd_alloc_bitmap = iommu_alloc_pages(GFP_KERNEL,
-                                                     get_order(MAX_DOMAIN_ID / 8));
-       if (amd_iommu_pd_alloc_bitmap == NULL)
-               goto out;
-
-       /*
-        * never allocate domain 0 because its used as the non-allocated and
-        * error value placeholder
-        */
-       __set_bit(0, amd_iommu_pd_alloc_bitmap);
-
        /*
         * now the data structures are allocated and basically initialized
         * start the real acpi table scan
index 35af5b470421c708888bb128e458868ba002da54..f831526b65f405fd82f9e3c1b14df6c419a3ccac 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-map-ops.h>
 #include <linux/dma-direct.h>
+#include <linux/idr.h>
 #include <linux/iommu-helper.h>
 #include <linux/delay.h>
 #include <linux/amd-iommu.h>
@@ -52,8 +53,6 @@
 #define HT_RANGE_START         (0xfd00000000ULL)
 #define HT_RANGE_END           (0xffffffffffULL)
 
-static DEFINE_SPINLOCK(pd_bitmap_lock);
-
 LIST_HEAD(ioapic_map);
 LIST_HEAD(hpet_map);
 LIST_HEAD(acpihid_map);
@@ -70,6 +69,12 @@ struct iommu_cmd {
        u32 data[4];
 };
 
+/*
+ * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
+ * to know which ones are already in use.
+ */
+DEFINE_IDA(pdom_ids);
+
 struct kmem_cache *amd_iommu_irq_cache;
 
 static void detach_device(struct device *dev);
@@ -1643,31 +1648,14 @@ int amd_iommu_complete_ppr(struct device *dev, u32 pasid, int status, int tag)
  *
  ****************************************************************************/
 
-static u16 domain_id_alloc(void)
+static int pdom_id_alloc(void)
 {
-       unsigned long flags;
-       int id;
-
-       spin_lock_irqsave(&pd_bitmap_lock, flags);
-       id = find_first_zero_bit(amd_iommu_pd_alloc_bitmap, MAX_DOMAIN_ID);
-       BUG_ON(id == 0);
-       if (id > 0 && id < MAX_DOMAIN_ID)
-               __set_bit(id, amd_iommu_pd_alloc_bitmap);
-       else
-               id = 0;
-       spin_unlock_irqrestore(&pd_bitmap_lock, flags);
-
-       return id;
+       return ida_alloc_range(&pdom_ids, 1, MAX_DOMAIN_ID - 1, GFP_ATOMIC);
 }
 
-static void domain_id_free(int id)
+static void pdom_id_free(int id)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&pd_bitmap_lock, flags);
-       if (id > 0 && id < MAX_DOMAIN_ID)
-               __clear_bit(id, amd_iommu_pd_alloc_bitmap);
-       spin_unlock_irqrestore(&pd_bitmap_lock, flags);
+       ida_free(&pdom_ids, id);
 }
 
 static void free_gcr3_tbl_level1(u64 *tbl)
@@ -1712,7 +1700,7 @@ static void free_gcr3_table(struct gcr3_tbl_info *gcr3_info)
        gcr3_info->glx = 0;
 
        /* Free per device domain ID */
-       domain_id_free(gcr3_info->domid);
+       pdom_id_free(gcr3_info->domid);
 
        iommu_free_page(gcr3_info->gcr3_tbl);
        gcr3_info->gcr3_tbl = NULL;
@@ -1739,6 +1727,7 @@ static int setup_gcr3_table(struct gcr3_tbl_info *gcr3_info,
 {
        int levels = get_gcr3_levels(pasids);
        int nid = iommu ? dev_to_node(&iommu->dev->dev) : NUMA_NO_NODE;
+       int domid;
 
        if (levels > amd_iommu_max_glx_val)
                return -EINVAL;
@@ -1747,11 +1736,14 @@ static int setup_gcr3_table(struct gcr3_tbl_info *gcr3_info,
                return -EBUSY;
 
        /* Allocate per device domain ID */
-       gcr3_info->domid = domain_id_alloc();
+       domid = pdom_id_alloc();
+       if (domid <= 0)
+               return -ENOSPC;
+       gcr3_info->domid = domid;
 
        gcr3_info->gcr3_tbl = iommu_alloc_page_node(nid, GFP_ATOMIC);
        if (gcr3_info->gcr3_tbl == NULL) {
-               domain_id_free(gcr3_info->domid);
+               pdom_id_free(domid);
                return -ENOMEM;
        }
 
@@ -2262,7 +2254,7 @@ void protection_domain_free(struct protection_domain *domain)
        WARN_ON(!list_empty(&domain->dev_list));
        if (domain->domain.type & __IOMMU_DOMAIN_PAGING)
                free_io_pgtable_ops(&domain->iop.pgtbl.ops);
-       domain_id_free(domain->id);
+       pdom_id_free(domain->id);
        kfree(domain);
 }
 
@@ -2277,16 +2269,18 @@ static void protection_domain_init(struct protection_domain *domain, int nid)
 struct protection_domain *protection_domain_alloc(unsigned int type, int nid)
 {
        struct protection_domain *domain;
+       int domid;
 
        domain = kzalloc(sizeof(*domain), GFP_KERNEL);
        if (!domain)
                return NULL;
 
-       domain->id = domain_id_alloc();
-       if (!domain->id) {
+       domid = pdom_id_alloc();
+       if (domid <= 0) {
                kfree(domain);
                return NULL;
        }
+       domain->id = domid;
 
        protection_domain_init(domain, nid);
 
@@ -2361,7 +2355,7 @@ static struct iommu_domain *do_iommu_domain_alloc(unsigned int type,
 
        ret = pdom_setup_pgtable(domain, type, pgtable);
        if (ret) {
-               domain_id_free(domain->id);
+               pdom_id_free(domain->id);
                kfree(domain);
                return ERR_PTR(ret);
        }
@@ -2493,7 +2487,7 @@ void amd_iommu_init_identity_domain(void)
        domain->ops = &identity_domain_ops;
        domain->owner = &amd_iommu_ops;
 
-       identity_domain.id = domain_id_alloc();
+       identity_domain.id = pdom_id_alloc();
 
        protection_domain_init(&identity_domain, NUMA_NO_NODE);
 }