Implement the core logic for per-domain IOPT page accounting. Introduce iommu_alloc_pages_node_sz_attributed() which increments the domain's nr_pages counter & stores the domain ptr in the ioptdesc. Update the free path to recover domain ptr and decrement the count.
Modify iommu_alloc_pages_node_sz() to be a legacy wrapper that passes a NULL domain, ensuring backwards compatibility for non-domain use-cases. Co-developed-by: Logan Odell <[email protected]> Signed-off-by: Logan Odell <[email protected]> Signed-off-by: Pranjal Shrivastava <[email protected]> --- drivers/iommu/iommu-pages.c | 35 ++++++++++++++++++++++++++++++++--- drivers/iommu/iommu-pages.h | 17 +++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/iommu-pages.c b/drivers/iommu/iommu-pages.c index 3bab175d8557..81fa01b763b7 100644 --- a/drivers/iommu/iommu-pages.c +++ b/drivers/iommu/iommu-pages.c @@ -29,8 +29,10 @@ static inline size_t ioptdesc_mem_size(struct ioptdesc *desc) } /** - * iommu_alloc_pages_node_sz - Allocate a zeroed page of a given size from - * specific NUMA node + * iommu_alloc_pages_node_sz_attributed - Allocate a zeroed page of a given size + * from specific NUMA node for a specific + * iommu domain + * @domain: IOMMU domain to which the page will belong * @nid: memory NUMA node id * @gfp: buddy allocator flags * @size: Memory size to allocate, rounded up to a power of 2 @@ -40,7 +42,8 @@ static inline size_t ioptdesc_mem_size(struct ioptdesc *desc) * returned allocation is round_up_pow_two(size) big, and is physically aligned * to its size. */ -void *iommu_alloc_pages_node_sz(int nid, gfp_t gfp, size_t size) +void *iommu_alloc_pages_node_sz_attributed(struct iommu_domain *domain, int nid, + gfp_t gfp, size_t size) { struct ioptdesc *iopt; unsigned long pgcnt; @@ -83,18 +86,44 @@ void *iommu_alloc_pages_node_sz(int nid, gfp_t gfp, size_t size) mod_node_page_state(folio_pgdat(folio), NR_IOMMU_PAGES, pgcnt); lruvec_stat_mod_folio(folio, NR_SECONDARY_PAGETABLE, pgcnt); + iopt->domain = domain; + if (domain) + atomic_long_add(pgcnt, &domain->nr_pages); + return folio_address(folio); } +EXPORT_SYMBOL_GPL(iommu_alloc_pages_node_sz_attributed); + +/** + * iommu_alloc_pages_node_sz - Allocate a zeroed page of a given size from + * specific NUMA node + * @nid: memory NUMA node id + * @gfp: buddy allocator flags + * @size: Memory size to allocate, rounded up to a power of 2 + * + * Returns the virtual address of the allocated page. The page must be freed + * either by calling iommu_free_pages() or via iommu_put_pages_list(). The + * returned allocation is round_up_pow_two(size) big, and is physically aligned + * to its size. + */ +void *iommu_alloc_pages_node_sz(int nid, gfp_t gfp, size_t size) +{ + return iommu_alloc_pages_node_sz_attributed(NULL, nid, gfp, size); +} EXPORT_SYMBOL_GPL(iommu_alloc_pages_node_sz); static void __iommu_free_desc(struct ioptdesc *iopt) { struct folio *folio = ioptdesc_folio(iopt); const unsigned long pgcnt = folio_nr_pages(folio); + struct iommu_domain *domain = iopt->domain; if (IOMMU_PAGES_USE_DMA_API) WARN_ON_ONCE(iopt->incoherent); + if (domain) + atomic_long_sub(pgcnt, &domain->nr_pages); + mod_node_page_state(folio_pgdat(folio), NR_IOMMU_PAGES, -pgcnt); lruvec_stat_mod_folio(folio, NR_SECONDARY_PAGETABLE, -pgcnt); folio_put(folio); diff --git a/drivers/iommu/iommu-pages.h b/drivers/iommu/iommu-pages.h index edf75c81054f..a4a8e9ba57c5 100644 --- a/drivers/iommu/iommu-pages.h +++ b/drivers/iommu/iommu-pages.h @@ -55,6 +55,8 @@ static inline struct ioptdesc *virt_to_ioptdesc(void *virt) return folio_ioptdesc(virt_to_folio(virt)); } +void *iommu_alloc_pages_node_sz_attributed(struct iommu_domain *domain, int nid, + gfp_t gfp, size_t size); void *iommu_alloc_pages_node_sz(int nid, gfp_t gfp, size_t size); void iommu_free_pages(void *virt); void iommu_put_pages_list(struct iommu_pages_list *list); @@ -107,6 +109,21 @@ static inline void *iommu_alloc_pages_sz(gfp_t gfp, size_t size) return iommu_alloc_pages_node_sz(NUMA_NO_NODE, gfp, size); } +/** + * iommu_alloc_pages_sz_attributed - Allocate a zeroed page of a given size from + * specific NUMA node for a specific domain + * @domain: iommu domain + * @gfp: buddy allocator flags + * @size: Memory size to allocate, this is rounded up to a power of 2 + * + * Returns the virtual address of the allocated page. + */ +static inline void *iommu_alloc_pages_sz_attributed(struct iommu_domain *domain, + gfp_t gfp, size_t size) +{ + return iommu_alloc_pages_node_sz_attributed(domain, NUMA_NO_NODE, gfp, size); +} + int iommu_pages_start_incoherent(void *virt, struct device *dma_dev); int iommu_pages_start_incoherent_list(struct iommu_pages_list *list, struct device *dma_dev); -- 2.56.0.rc1.315.gc6ed9934b7-goog

