]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/amd: Narrow the use of struct protection_domain to invalidation
authorJason Gunthorpe <jgg@nvidia.com>
Fri, 30 Aug 2024 00:06:18 +0000 (21:06 -0300)
committerJoerg Roedel <jroedel@suse.de>
Wed, 4 Sep 2024 09:39:00 +0000 (11:39 +0200)
The AMD io_pgtable stuff doesn't implement the tlb ops callbacks, instead
it invokes the invalidation ops directly on the struct protection_domain.

Narrow the use of struct protection_domain to only those few code paths.
Make everything else properly use struct amd_io_pgtable through the call
chains, which is the correct modular type for an io-pgtable module.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
Link: https://lore.kernel.org/r/9-v2-831cdc4d00f3+1a315-amd_iopgtbl_jgg@nvidia.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/io_pgtable.c
drivers/iommu/amd/io_pgtable_v2.c

index 4492a5800b356ebad7ba43c5319465b1ce409d1b..1cf3d580a55107a3fc2bc11afa071fa99d37ddb9 100644 (file)
@@ -137,11 +137,13 @@ static void free_sub_pt(u64 *root, int mode, struct list_head *freelist)
  * another level increases the size of the address space by 9 bits to a size up
  * to 64 bits.
  */
-static bool increase_address_space(struct protection_domain *domain,
+static bool increase_address_space(struct amd_io_pgtable *pgtable,
                                   unsigned long address,
                                   gfp_t gfp)
 {
-       struct io_pgtable_cfg *cfg = &domain->iop.pgtbl.cfg;
+       struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg;
+       struct protection_domain *domain =
+               container_of(pgtable, struct protection_domain, iop);
        unsigned long flags;
        bool ret = true;
        u64 *pte;
@@ -152,17 +154,17 @@ static bool increase_address_space(struct protection_domain *domain,
 
        spin_lock_irqsave(&domain->lock, flags);
 
-       if (address <= PM_LEVEL_SIZE(domain->iop.mode))
+       if (address <= PM_LEVEL_SIZE(pgtable->mode))
                goto out;
 
        ret = false;
-       if (WARN_ON_ONCE(domain->iop.mode == PAGE_MODE_6_LEVEL))
+       if (WARN_ON_ONCE(pgtable->mode == PAGE_MODE_6_LEVEL))
                goto out;
 
-       *pte = PM_LEVEL_PDE(domain->iop.mode, iommu_virt_to_phys(domain->iop.root));
+       *pte = PM_LEVEL_PDE(pgtable->mode, iommu_virt_to_phys(pgtable->root));
 
-       domain->iop.root  = pte;
-       domain->iop.mode += 1;
+       pgtable->root  = pte;
+       pgtable->mode += 1;
        amd_iommu_update_and_flush_device_table(domain);
 
        pte = NULL;
@@ -175,31 +177,31 @@ out:
        return ret;
 }
 
-static u64 *alloc_pte(struct protection_domain *domain,
+static u64 *alloc_pte(struct amd_io_pgtable *pgtable,
                      unsigned long address,
                      unsigned long page_size,
                      u64 **pte_page,
                      gfp_t gfp,
                      bool *updated)
 {
-       struct io_pgtable_cfg *cfg = &domain->iop.pgtbl.cfg;
+       struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg;
        int level, end_lvl;
        u64 *pte, *page;
 
        BUG_ON(!is_power_of_2(page_size));
 
-       while (address > PM_LEVEL_SIZE(domain->iop.mode)) {
+       while (address > PM_LEVEL_SIZE(pgtable->mode)) {
                /*
                 * Return an error if there is no memory to update the
                 * page-table.
                 */
-               if (!increase_address_space(domain, address, gfp))
+               if (!increase_address_space(pgtable, address, gfp))
                        return NULL;
        }
 
 
-       level   = domain->iop.mode - 1;
-       pte     = &domain->iop.root[PM_LEVEL_INDEX(level, address)];
+       level   = pgtable->mode - 1;
+       pte     = &pgtable->root[PM_LEVEL_INDEX(level, address)];
        address = PAGE_SIZE_ALIGN(address, page_size);
        end_lvl = PAGE_SIZE_LEVEL(page_size);
 
@@ -348,7 +350,7 @@ static int iommu_v1_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
                              phys_addr_t paddr, size_t pgsize, size_t pgcount,
                              int prot, gfp_t gfp, size_t *mapped)
 {
-       struct protection_domain *dom = io_pgtable_ops_to_domain(ops);
+       struct amd_io_pgtable *pgtable = io_pgtable_ops_to_data(ops);
        LIST_HEAD(freelist);
        bool updated = false;
        u64 __pte, *pte;
@@ -365,7 +367,7 @@ static int iommu_v1_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
 
        while (pgcount > 0) {
                count = PAGE_SIZE_PTE_COUNT(pgsize);
-               pte   = alloc_pte(dom, iova, pgsize, NULL, gfp, &updated);
+               pte   = alloc_pte(pgtable, iova, pgsize, NULL, gfp, &updated);
 
                ret = -ENOMEM;
                if (!pte)
@@ -402,6 +404,7 @@ static int iommu_v1_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
 
 out:
        if (updated) {
+               struct protection_domain *dom = io_pgtable_ops_to_domain(ops);
                unsigned long flags;
 
                spin_lock_irqsave(&dom->lock, flags);
index 1e3be8c5312b874ca59fcc6e80a11556281e40d4..ed2c1faae6d580539a9ca0ff978f83e4402c505b 100644 (file)
@@ -233,8 +233,8 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
                              phys_addr_t paddr, size_t pgsize, size_t pgcount,
                              int prot, gfp_t gfp, size_t *mapped)
 {
-       struct protection_domain *pdom = io_pgtable_ops_to_domain(ops);
-       struct io_pgtable_cfg *cfg = &pdom->iop.pgtbl.cfg;
+       struct amd_io_pgtable *pgtable = io_pgtable_ops_to_data(ops);
+       struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg;
        u64 *pte;
        unsigned long map_size;
        unsigned long mapped_size = 0;
@@ -251,7 +251,7 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
 
        while (mapped_size < size) {
                map_size = get_alloc_page_size(pgsize);
-               pte = v2_alloc_pte(cfg->amd.nid, pdom->iop.pgd,
+               pte = v2_alloc_pte(cfg->amd.nid, pgtable->pgd,
                                   iova, map_size, gfp, &updated);
                if (!pte) {
                        ret = -EINVAL;
@@ -266,8 +266,11 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
        }
 
 out:
-       if (updated)
+       if (updated) {
+               struct protection_domain *pdom = io_pgtable_ops_to_domain(ops);
+
                amd_iommu_domain_flush_pages(pdom, o_iova, size);
+       }
 
        if (mapped)
                *mapped += mapped_size;