From: Mostafa Saleh Date: Wed, 13 May 2026 21:52:02 +0000 (+0000) Subject: iommu/io-pgtable-arm: Rework to use the iommu-pages API X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d996116cde972756e8415d6e070b960f6f6a8f6c;p=thirdparty%2Fkernel%2Flinux.git iommu/io-pgtable-arm: Rework to use the iommu-pages API 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 Signed-off-by: Mostafa Saleh Reviewed-by: Jason Gunthorpe Signed-off-by: Joerg Roedel --- diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 0cbe545c491df..86b23aa043244 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -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); }