iommu/amd: Introduce helper functions for managing GCR3 table
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Thu, 21 Sep 2023 09:21:38 +0000 (09:21 +0000)
committerJoerg Roedel <jroedel@suse.de>
Mon, 25 Sep 2023 10:39:01 +0000 (12:39 +0200)
Refactor domain_enable_v2() into helper functions for managing GCR3 table
(i.e. setup_gcr3_table() and get_gcr3_levels()), which will be used in
subsequent patches. Also re-arrange code and remove forward declaration.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Co-developed-by: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Link: https://lore.kernel.org/r/20230921092147.5930-6-vasant.hegde@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/iommu.c

index bc1fa6e..46a10b4 100644 (file)
@@ -77,7 +77,6 @@ struct iommu_cmd {
 struct kmem_cache *amd_iommu_irq_cache;
 
 static void detach_device(struct device *dev);
-static int domain_enable_v2(struct protection_domain *domain, int pasids);
 
 /****************************************************************************
  *
@@ -1575,6 +1574,42 @@ static void free_gcr3_table(struct protection_domain *domain)
        free_page((unsigned long)domain->gcr3_tbl);
 }
 
+/*
+ * Number of GCR3 table levels required. Level must be 4-Kbyte
+ * page and can contain up to 512 entries.
+ */
+static int get_gcr3_levels(int pasids)
+{
+       int levels;
+
+       if (pasids == -1)
+               return amd_iommu_max_glx_val;
+
+       levels = get_count_order(pasids);
+
+       return levels ? (DIV_ROUND_UP(levels, 9) - 1) : levels;
+}
+
+/* Note: This function expects iommu_domain->lock to be held prior calling the function. */
+static int setup_gcr3_table(struct protection_domain *domain, int pasids)
+{
+       int levels = get_gcr3_levels(pasids);
+
+       if (levels > amd_iommu_max_glx_val)
+               return -EINVAL;
+
+       domain->gcr3_tbl = alloc_pgtable_page(domain->nid, GFP_ATOMIC);
+       if (domain->gcr3_tbl == NULL)
+               return -ENOMEM;
+
+       domain->glx      = levels;
+       domain->flags   |= PD_IOMMUV2_MASK;
+
+       amd_iommu_domain_update(domain);
+
+       return 0;
+}
+
 static void set_dte_entry(struct amd_iommu *iommu, u16 devid,
                          struct protection_domain *domain, bool ats, bool ppr)
 {
@@ -2065,7 +2100,7 @@ static int protection_domain_init_v2(struct protection_domain *domain)
 
        domain->domain.pgsize_bitmap = AMD_IOMMU_PGSIZES_V2;
 
-       if (domain_enable_v2(domain, 1)) {
+       if (setup_gcr3_table(domain, 1)) {
                domain_id_free(domain->id);
                return -ENOMEM;
        }
@@ -2514,30 +2549,6 @@ void amd_iommu_domain_direct_map(struct iommu_domain *dom)
 }
 EXPORT_SYMBOL(amd_iommu_domain_direct_map);
 
-/* Note: This function expects iommu_domain->lock to be held prior calling the function. */
-static int domain_enable_v2(struct protection_domain *domain, int pasids)
-{
-       int levels;
-
-       /* Number of GCR3 table levels required */
-       for (levels = 0; (pasids - 1) & ~0x1ff; pasids >>= 9)
-               levels += 1;
-
-       if (levels > amd_iommu_max_glx_val)
-               return -EINVAL;
-
-       domain->gcr3_tbl = (void *)get_zeroed_page(GFP_ATOMIC);
-       if (domain->gcr3_tbl == NULL)
-               return -ENOMEM;
-
-       domain->glx      = levels;
-       domain->flags   |= PD_IOMMUV2_MASK;
-
-       amd_iommu_domain_update(domain);
-
-       return 0;
-}
-
 int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids)
 {
        struct protection_domain *pdom = to_pdomain(dom);
@@ -2556,7 +2567,7 @@ int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids)
                goto out;
 
        if (!pdom->gcr3_tbl)
-               ret = domain_enable_v2(pdom, pasids);
+               ret = setup_gcr3_table(pdom, pasids);
 
 out:
        spin_unlock_irqrestore(&pdom->lock, flags);