[PATCH] dma-contiguous: simplify numa cma area handling

Feng Tang posted 1 patch 2 weeks ago
.../admin-guide/kernel-parameters.txt         |  4 ++
kernel/dma/Kconfig                            |  4 +-
kernel/dma/contiguous.c                       | 46 +++++--------------
3 files changed, 19 insertions(+), 35 deletions(-)
[PATCH] dma-contiguous: simplify numa cma area handling
Posted by Feng Tang 2 weeks ago
Currently, there are 2 kernel cmdline ways to setup numa cma area:
"cma_pernuma=" and "numa_cma=", and there are 2 cma arrays as well,
while they have no difference technically. Robin suggested to cleanup
the code and only use one array [1], as "the apparent intent that
users only want one _or_ the other".

Simplify the code by only using one array to save the numa cma area.
And in rare case that a user really setup the 2 cmdline parameters
at the same time,  let the per-node specific size setting 'numa_cma='
take priority over the global numa cma setting.

Link[1]: https://lore.kernel.org/lkml/43c5301c-fe6a-41e4-9482-ccfc7b62f2a7@arm.com/

Suggested-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Feng Tang <feng.tang@linux.alibaba.com>
---
 .../admin-guide/kernel-parameters.txt         |  4 ++
 kernel/dma/Kconfig                            |  4 +-
 kernel/dma/contiguous.c                       | 46 +++++--------------
 3 files changed, 19 insertions(+), 35 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..8e717a587870 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -895,6 +895,10 @@ Kernel parameters
 			contiguous memory allocations. It will reserve CMA
 			area for the specified node.
 
+			If it is setup together with upper 'cmd_pernuma='
+			(unlikely), its size setting takes priority for the
+			specified numa nodes.
+
 			With numa CMA enabled, DMA users on node nid will
 			first try to allocate buffer from the numa area
 			which is located in node nid, if the allocation fails,
diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig
index c9fa0a922cba..0a4ba21a57a7 100644
--- a/kernel/dma/Kconfig
+++ b/kernel/dma/Kconfig
@@ -179,7 +179,9 @@ config DMA_NUMA_CMA
 
 	  You can set the size of pernuma CMA by specifying "cma_pernuma=size"
 	  or set the node id and its size of CMA by specifying "numa_cma=
-	  <node>:size[,<node>:size]" on the kernel's command line.
+	  <node>:size[,<node>:size]" on the kernel's command line. And in
+	  rare case that the above 2 are both setup, then the "numa_cma="
+	  takes priority for the specified numa nodes.
 
 config CMA_SIZE_PERNUMA
 	bool "Default CMA area per NUMA node"
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index 799f6e9c88bd..f754079a287d 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -134,7 +134,6 @@ EXPORT_SYMBOL_GPL(dev_get_cma_area);
 
 static struct cma *dma_contiguous_numa_area[MAX_NUMNODES];
 static phys_addr_t numa_cma_size[MAX_NUMNODES] __initdata;
-static struct cma *dma_contiguous_pernuma_area[MAX_NUMNODES];
 static phys_addr_t pernuma_size_bytes __initdata;
 static bool numa_cma_configured __initdata;
 
@@ -208,7 +207,7 @@ static void __init dma_numa_cma_reserve(void)
 		pernuma_size_bytes = cma_get_size(dma_contiguous_default_area);
 
 	for_each_node(nid) {
-		int ret;
+		int size, ret;
 		char name[CMA_MAX_NAME];
 		struct cma **cma;
 
@@ -218,27 +217,17 @@ static void __init dma_numa_cma_reserve(void)
 			continue;
 		}
 
-		if (pernuma_size_bytes) {
-
-			cma = &dma_contiguous_pernuma_area[nid];
-			snprintf(name, sizeof(name), "pernuma%d", nid);
-			ret = cma_declare_contiguous_nid(0, pernuma_size_bytes, 0, 0,
-							 0, false, name, cma, nid);
-			if (ret)
-				pr_warn("%s: reservation failed: err %d, node %d", __func__,
-					ret, nid);
-		}
-
-		if (numa_cma_size[nid]) {
+		/* per-node numa setting has the priority */
+		size = numa_cma_size[nid] ?: pernuma_size_bytes;
+		if (!size)
+			continue;
 
-			cma = &dma_contiguous_numa_area[nid];
-			snprintf(name, sizeof(name), "numa%d", nid);
-			ret = cma_declare_contiguous_nid(0, numa_cma_size[nid], 0, 0, 0, false,
-							 name, cma, nid);
-			if (ret)
-				pr_warn("%s: reservation failed: err %d, node %d", __func__,
-					ret, nid);
-		}
+		cma = &dma_contiguous_numa_area[nid];
+		snprintf(name, sizeof(name), "numa%d", nid);
+		ret = cma_declare_contiguous_nid(0, size, 0, 0, 0, false, name, cma, nid);
+		if (ret)
+			pr_warn("%s: reservation failed: err %d, node %d", __func__,
+				ret, nid);
 	}
 }
 #else
@@ -437,16 +426,8 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
 
 #ifdef CONFIG_DMA_NUMA_CMA
 	if (nid != NUMA_NO_NODE && !(gfp & (GFP_DMA | GFP_DMA32))) {
-		struct cma *cma = dma_contiguous_pernuma_area[nid];
+		struct cma *cma = dma_contiguous_numa_area[nid];
 		struct page *page;
-
-		if (cma) {
-			page = cma_alloc_aligned(cma, size, gfp);
-			if (page)
-				return page;
-		}
-
-		cma = dma_contiguous_numa_area[nid];
 		if (cma) {
 			page = cma_alloc_aligned(cma, size, gfp);
 			if (page)
@@ -484,9 +465,6 @@ void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
 		 * otherwise, page is from either per-numa cma or default cma
 		 */
 #ifdef CONFIG_DMA_NUMA_CMA
-		if (cma_release(dma_contiguous_pernuma_area[page_to_nid(page)],
-					page, count))
-			return;
 		if (cma_release(dma_contiguous_numa_area[page_to_nid(page)],
 					page, count))
 			return;

base-commit: 7e6ace2535d032c908e4d8747d9a7952617c001a
-- 
2.43.5
Re: [PATCH] dma-contiguous: simplify numa cma area handling
Posted by Marek Szyprowski 1 week, 4 days ago
On 25.05.2026 03:51, Feng Tang wrote:
> Currently, there are 2 kernel cmdline ways to setup numa cma area:
> "cma_pernuma=" and "numa_cma=", and there are 2 cma arrays as well,
> while they have no difference technically. Robin suggested to cleanup
> the code and only use one array [1], as "the apparent intent that
> users only want one _or_ the other".
>
> Simplify the code by only using one array to save the numa cma area.
> And in rare case that a user really setup the 2 cmdline parameters
> at the same time,  let the per-node specific size setting 'numa_cma='
> take priority over the global numa cma setting.
>
> Link[1]: https://lore.kernel.org/lkml/43c5301c-fe6a-41e4-9482-ccfc7b62f2a7@arm.com/
>
> Suggested-by: Robin Murphy <robin.murphy@arm.com>
> Signed-off-by: Feng Tang <feng.tang@linux.alibaba.com>

Applied to dma-mapping-for-next. Thanks!


> ---
>  .../admin-guide/kernel-parameters.txt         |  4 ++
>  kernel/dma/Kconfig                            |  4 +-
>  kernel/dma/contiguous.c                       | 46 +++++--------------
>  3 files changed, 19 insertions(+), 35 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 4d0f545fb3ec..8e717a587870 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -895,6 +895,10 @@ Kernel parameters
>  			contiguous memory allocations. It will reserve CMA
>  			area for the specified node.
>  
> +			If it is setup together with upper 'cmd_pernuma='
> +			(unlikely), its size setting takes priority for the
> +			specified numa nodes.
> +
>  			With numa CMA enabled, DMA users on node nid will
>  			first try to allocate buffer from the numa area
>  			which is located in node nid, if the allocation fails,
> diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig
> index c9fa0a922cba..0a4ba21a57a7 100644
> --- a/kernel/dma/Kconfig
> +++ b/kernel/dma/Kconfig
> @@ -179,7 +179,9 @@ config DMA_NUMA_CMA
>  
>  	  You can set the size of pernuma CMA by specifying "cma_pernuma=size"
>  	  or set the node id and its size of CMA by specifying "numa_cma=
> -	  <node>:size[,<node>:size]" on the kernel's command line.
> +	  <node>:size[,<node>:size]" on the kernel's command line. And in
> +	  rare case that the above 2 are both setup, then the "numa_cma="
> +	  takes priority for the specified numa nodes.
>  
>  config CMA_SIZE_PERNUMA
>  	bool "Default CMA area per NUMA node"
> diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
> index 799f6e9c88bd..f754079a287d 100644
> --- a/kernel/dma/contiguous.c
> +++ b/kernel/dma/contiguous.c
> @@ -134,7 +134,6 @@ EXPORT_SYMBOL_GPL(dev_get_cma_area);
>  
>  static struct cma *dma_contiguous_numa_area[MAX_NUMNODES];
>  static phys_addr_t numa_cma_size[MAX_NUMNODES] __initdata;
> -static struct cma *dma_contiguous_pernuma_area[MAX_NUMNODES];
>  static phys_addr_t pernuma_size_bytes __initdata;
>  static bool numa_cma_configured __initdata;
>  
> @@ -208,7 +207,7 @@ static void __init dma_numa_cma_reserve(void)
>  		pernuma_size_bytes = cma_get_size(dma_contiguous_default_area);
>  
>  	for_each_node(nid) {
> -		int ret;
> +		int size, ret;
>  		char name[CMA_MAX_NAME];
>  		struct cma **cma;
>  
> @@ -218,27 +217,17 @@ static void __init dma_numa_cma_reserve(void)
>  			continue;
>  		}
>  
> -		if (pernuma_size_bytes) {
> -
> -			cma = &dma_contiguous_pernuma_area[nid];
> -			snprintf(name, sizeof(name), "pernuma%d", nid);
> -			ret = cma_declare_contiguous_nid(0, pernuma_size_bytes, 0, 0,
> -							 0, false, name, cma, nid);
> -			if (ret)
> -				pr_warn("%s: reservation failed: err %d, node %d", __func__,
> -					ret, nid);
> -		}
> -
> -		if (numa_cma_size[nid]) {
> +		/* per-node numa setting has the priority */
> +		size = numa_cma_size[nid] ?: pernuma_size_bytes;
> +		if (!size)
> +			continue;
>  
> -			cma = &dma_contiguous_numa_area[nid];
> -			snprintf(name, sizeof(name), "numa%d", nid);
> -			ret = cma_declare_contiguous_nid(0, numa_cma_size[nid], 0, 0, 0, false,
> -							 name, cma, nid);
> -			if (ret)
> -				pr_warn("%s: reservation failed: err %d, node %d", __func__,
> -					ret, nid);
> -		}
> +		cma = &dma_contiguous_numa_area[nid];
> +		snprintf(name, sizeof(name), "numa%d", nid);
> +		ret = cma_declare_contiguous_nid(0, size, 0, 0, 0, false, name, cma, nid);
> +		if (ret)
> +			pr_warn("%s: reservation failed: err %d, node %d", __func__,
> +				ret, nid);
>  	}
>  }
>  #else
> @@ -437,16 +426,8 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
>  
>  #ifdef CONFIG_DMA_NUMA_CMA
>  	if (nid != NUMA_NO_NODE && !(gfp & (GFP_DMA | GFP_DMA32))) {
> -		struct cma *cma = dma_contiguous_pernuma_area[nid];
> +		struct cma *cma = dma_contiguous_numa_area[nid];
>  		struct page *page;
> -
> -		if (cma) {
> -			page = cma_alloc_aligned(cma, size, gfp);
> -			if (page)
> -				return page;
> -		}
> -
> -		cma = dma_contiguous_numa_area[nid];
>  		if (cma) {
>  			page = cma_alloc_aligned(cma, size, gfp);
>  			if (page)
> @@ -484,9 +465,6 @@ void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
>  		 * otherwise, page is from either per-numa cma or default cma
>  		 */
>  #ifdef CONFIG_DMA_NUMA_CMA
> -		if (cma_release(dma_contiguous_pernuma_area[page_to_nid(page)],
> -					page, count))
> -			return;
>  		if (cma_release(dma_contiguous_numa_area[page_to_nid(page)],
>  					page, count))
>  			return;
>
> base-commit: 7e6ace2535d032c908e4d8747d9a7952617c001a

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland