]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/io-pgtable-arm: Rework to use the iommu-pages API
authorMostafa Saleh <smostafa@google.com>
Wed, 13 May 2026 21:52:02 +0000 (21:52 +0000)
committerJoerg Roedel <joerg.roedel@amd.com>
Tue, 19 May 2026 09:03:45 +0000 (11:03 +0200)
Update the io-pgtable-arm allocator to use the iommu-pages API.

Replace the DMA API usage from __arm_lpae_alloc_pages() with
iommu_pages_start_incoherent() and from __arm_lpae_free_pages() with
iommu_pages_free_incoherent().

Since the iommu-pages API relies on metadata stored in the struct page
during iommu_alloc_pages_node_sz(), it cannot be used safely with memory
allocated via the custom cfg->alloc (which may not be backed by pages).
So, isolate that logic and keep it as it.

Suggested-by: Jason Gunthorpe <jgg@ziepe.ca>
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
drivers/iommu/io-pgtable-arm.c

index 0cbe545c491df2414d241771575be35fafa363c5..86b23aa0432440e47a166639b3d7c8362a00885d 100644 (file)
@@ -248,24 +248,15 @@ static dma_addr_t __arm_lpae_dma_addr(void *pages)
        return (dma_addr_t)virt_to_phys(pages);
 }
 
-static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
-                                   struct io_pgtable_cfg *cfg,
-                                   void *cookie)
+static void *__arm_lpae_cfg_alloc(size_t size, gfp_t gfp,
+                                 struct io_pgtable_cfg *cfg,
+                                 void *cookie)
 {
        struct device *dev = cfg->iommu_dev;
        dma_addr_t dma;
        void *pages;
 
-       /*
-        * For very small starting-level translation tables the HW requires a
-        * minimum alignment of at least 64 to cover all cases.
-        */
-       size = max(size, 64);
-       if (cfg->alloc)
-               pages = cfg->alloc(cookie, size, gfp);
-       else
-               pages = iommu_alloc_pages_node_sz(dev_to_node(dev), gfp, size);
-
+       pages = cfg->alloc(cookie, size, gfp);
        if (!pages)
                return NULL;
 
@@ -289,14 +280,55 @@ out_unmap:
        dma_unmap_single(dev, dma, size, DMA_TO_DEVICE);
 
 out_free:
-       if (cfg->free)
-               cfg->free(cookie, pages, size);
-       else
-               iommu_free_pages(pages);
-
+       cfg->free(cookie, pages, size);
        return NULL;
 }
 
+static void __arm_lpae_cfg_free(void *pages, size_t size,
+                               struct io_pgtable_cfg *cfg,
+                               void *cookie)
+{
+       if (!cfg->coherent_walk)
+               dma_unmap_single(cfg->iommu_dev, __arm_lpae_dma_addr(pages),
+                                size, DMA_TO_DEVICE);
+
+       cfg->free(cookie, pages, size);
+}
+
+static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
+                                   struct io_pgtable_cfg *cfg,
+                                   void *cookie)
+{
+       struct device *dev = cfg->iommu_dev;
+       void *pages;
+
+       /*
+        * For very small starting-level translation tables the HW requires a
+        * minimum alignment of at least 64 to cover all cases.
+        */
+       size = max(size, 64);
+
+       if (cfg->alloc)
+               return __arm_lpae_cfg_alloc(size, gfp, cfg, cookie);
+
+       pages = iommu_alloc_pages_node_sz(dev_to_node(dev), gfp, size);
+       if (!pages)
+               return NULL;
+
+       if (!cfg->coherent_walk) {
+               int ret = iommu_pages_start_incoherent(pages, dev);
+
+               if (ret) {
+                       if (ret == -EOPNOTSUPP)
+                               dev_err(dev, "Cannot accommodate DMA translation for IOMMU page tables\n");
+                       iommu_free_pages(pages);
+                       return NULL;
+               }
+       }
+
+       return pages;
+}
+
 static void __arm_lpae_free_pages(void *pages, size_t size,
                                  struct io_pgtable_cfg *cfg,
                                  void *cookie)
@@ -304,12 +336,13 @@ static void __arm_lpae_free_pages(void *pages, size_t size,
        /* See __arm_lpae_alloc_pages(). */
        size = max(size, 64);
 
-       if (!cfg->coherent_walk)
-               dma_unmap_single(cfg->iommu_dev, __arm_lpae_dma_addr(pages),
-                                size, DMA_TO_DEVICE);
+       if (cfg->free) {
+               __arm_lpae_cfg_free(pages, size, cfg, cookie);
+               return;
+       }
 
-       if (cfg->free)
-               cfg->free(cookie, pages, size);
+       if (!cfg->coherent_walk)
+               iommu_pages_free_incoherent(pages, cfg->iommu_dev);
        else
                iommu_free_pages(pages);
 }