lkml.org 
[lkml]   [2023]   [Jul]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: [PATCH] dma-contiguous: support numa CMA for specified node
From
On 10.07.23 09:49, Yajun Deng wrote:
> The kernel parameter 'cma_pernuma=' only supports reserving the same
> size of CMA area for each node. We need to reserve different sizes of
> CMA area for specified nodes if these devices belong to different nodes.
>
> Change kernel parameter from 'cma_pernuma=' to 'numa_cma='. If node
> isn't specified, it will reserve CMA area for per-numa node. if the node
> is specified, it will reserve CMA area for the specified node.
>
> At the same time, print the node id in cma_declare_contiguous_nid() if
> enabled CONFIG_NUMA.
>
> Signed-off-by: Yajun Deng <yajun.deng@linux.dev>
> ---
> .../admin-guide/kernel-parameters.txt | 17 ++--
> kernel/dma/Kconfig | 11 +--
> kernel/dma/contiguous.c | 90 +++++++++++++------
> mm/cma.c | 12 ++-
> 4 files changed, 89 insertions(+), 41 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index bdf0ab6716c8..b287647f0873 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -695,14 +695,19 @@
> altogether. For more information, see
> kernel/dma/contiguous.c
>
> - cma_pernuma=nn[MG]
> + numa_cma=nn[MG] or (node format)
> + <node>:nn[MG][,<node>:nn[MG]]
> [KNL,CMA]
> - Sets the size of kernel per-numa memory area for
> + Sets the size of kernel numa memory area for
> contiguous memory allocations. A value of 0 disables
> - per-numa CMA altogether. And If this option is not
> - specified, the default value is 0.
> - With per-numa CMA enabled, DMA users on node nid will
> - first try to allocate buffer from the pernuma area
> + numa CMA altogether. If this option is not specified,
> + the default value is 0. If node isn't specified, it
> + will reserve CMA area for per-numa node, if the node
> + is specified, it will reserve CMA area for the
> + specified node.
> +
> + 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,
> they will fallback to the global default memory area.
>
> diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig
> index 7afde9bc529f..f07fb97ef3e8 100644
> --- a/kernel/dma/Kconfig
> +++ b/kernel/dma/Kconfig
> @@ -145,15 +145,16 @@ config DMA_CMA
>
> if DMA_CMA
>
> -config DMA_PERNUMA_CMA
> - bool "Enable separate DMA Contiguous Memory Area for each NUMA Node"
> +config DMA_NUMA_CMA
> + bool "Enable separate DMA Contiguous Memory Area for NUMA Node"
> default NUMA
> help
> - Enable this option to get pernuma CMA areas so that NUMA devices
> + Enable this option to get numa CMA areas so that NUMA devices
> can get local memory by DMA coherent APIs.
>
> - You can set the size of pernuma CMA by specifying "cma_pernuma=size"
> - on the kernel's command line.
> + You can set the size of pernuma CMA by specifying "numa_cma=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.
>
> comment "Default contiguous memory area size:"
>
> diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
> index 26a8e5365fcd..bf62d78abff7 100644
> --- a/kernel/dma/contiguous.c
> +++ b/kernel/dma/contiguous.c
> @@ -50,6 +50,7 @@
> #include <linux/sizes.h>
> #include <linux/dma-map-ops.h>
> #include <linux/cma.h>
> +#include <linux/nospec.h>
>
> #ifdef CONFIG_CMA_SIZE_MBYTES
> #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
> @@ -96,17 +97,44 @@ static int __init early_cma(char *p)
> }
> early_param("cma", early_cma);
>
> -#ifdef CONFIG_DMA_PERNUMA_CMA
> +#ifdef CONFIG_DMA_NUMA_CMA
>
> -static struct cma *dma_contiguous_pernuma_area[MAX_NUMNODES];
> +static struct cma *dma_contiguous_numa_area[MAX_NUMNODES];
> static phys_addr_t pernuma_size_bytes __initdata;
> +static phys_addr_t numa_cma_size_in_node[MAX_NUMNODES] __initdata;
>
> -static int __init early_cma_pernuma(char *p)
> +static int __init early_numa_cma(char *p)
> {
> - pernuma_size_bytes = memparse(p, &p);
> + int nid, count = 0;
> + unsigned long tmp;
> + char *s = p;
> +
> + while (*s) {
> + if (sscanf(s, "%lu%n", &tmp, &count) != 1)
> + break;
> +
> + if (s[count] == ':') {
> + if (tmp >= MAX_NUMNODES)
> + break;
> + nid = array_index_nospec(tmp, MAX_NUMNODES);
> +
> + s += count + 1;
> + tmp = memparse(s, &s);
> + numa_cma_size_in_node[nid] = tmp;
> +
> + if (*s == ',')
> + s++;
> + else
> + break;
> + } else {
> + pernuma_size_bytes = memparse(p, &p);
> + break;
> + }
> + }
> +
> return 0;
> }
> -early_param("cma_pernuma", early_cma_pernuma);
> +early_param("numa_cma", early_numa_cma);
> #endif
>
> #ifdef CONFIG_CMA_SIZE_PERCENTAGE
> @@ -127,34 +155,42 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
>
> #endif
>
> -#ifdef CONFIG_DMA_PERNUMA_CMA
> -static void __init dma_pernuma_cma_reserve(void)
> +#ifdef CONFIG_DMA_NUMA_CMA
> +static void __init dma_numa_cma_reserve(void)
> {
> + phys_addr_t size;
> int nid;
>
> - if (!pernuma_size_bytes)
> - return;
> -
> - for_each_online_node(nid) {
> + for_each_node(nid) {
> int ret;
> char name[CMA_MAX_NAME];
> - struct cma **cma = &dma_contiguous_pernuma_area[nid];
> + struct cma **numa_cma;
>
> - 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 (!node_online(nid)) {
> + if (pernuma_size_bytes || numa_cma_size_in_node[nid])
> + pr_warn("invalid node %d specified\n", nid);
> continue;
> }
>
> - pr_debug("%s: reserved %llu MiB on node %d\n", __func__,
> - (unsigned long long)pernuma_size_bytes / SZ_1M, nid);
> + if (pernuma_size_bytes)
> + size = pernuma_size_bytes;
> + else
> + size = numa_cma_size_in_node[nid];
> +
> + if (!size)
> + continue;
> +
> + numa_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, numa_cma, nid);
> + if (ret)
> + pr_warn("%s: reservation failed: err %d, node %d", __func__,
> + ret, nid);
> }
> }
> #else
> -static inline void __init dma_pernuma_cma_reserve(void)
> +static inline void __init dma_numa_cma_reserve(void)
> {
> }
> #endif
> @@ -175,7 +211,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
> phys_addr_t selected_limit = limit;
> bool fixed = false;
>
> - dma_pernuma_cma_reserve();
> + dma_numa_cma_reserve();
>
> pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
>
> @@ -309,7 +345,7 @@ static struct page *cma_alloc_aligned(struct cma *cma, size_t size, gfp_t gfp)
> */
> struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
> {
> -#ifdef CONFIG_DMA_PERNUMA_CMA
> +#ifdef CONFIG_DMA_NUMA_CMA
> int nid = dev_to_node(dev);
> #endif
>
> @@ -321,9 +357,9 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
> if (size <= PAGE_SIZE)
> return NULL;
>
> -#ifdef CONFIG_DMA_PERNUMA_CMA
> +#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) {
> @@ -362,8 +398,8 @@ 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_PERNUMA_CMA
> - if (cma_release(dma_contiguous_pernuma_area[page_to_nid(page)],
> +#ifdef CONFIG_DMA_NUMA_CMA
> + if (cma_release(dma_contiguous_numa_area[page_to_nid(page)],
> page, count))
> return;
> #endif
> diff --git a/mm/cma.c b/mm/cma.c
> index 4880f72102fa..af5945932e9e 100644
> --- a/mm/cma.c
> +++ b/mm/cma.c
> @@ -244,6 +244,7 @@ int __init cma_declare_contiguous_nid(phys_addr_t base,
> {
> phys_addr_t memblock_end = memblock_end_of_DRAM();
> phys_addr_t highmem_start;
> + char nid_buf[32] = "";

That's a but ugly just for the sake of printing an info/error.


if (!IS_ENABLED(CONFIG_NUMA))
nid = NUMA_NO_NODE;

...

pr_info("Reserved %ld MiB at %pa on node %d\n", (unsigned long)size /
SZ_1M, &base, nid);


"on node -1" would certainly be good enough for my taste.

--
Cheers,

David / dhildenb

\
 
 \ /
  Last update: 2023-07-11 13:55    [W:0.046 / U:0.348 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site