Skip to content

Commit bf29bfa

Browse files
Yajun DengChristoph Hellwig
authored andcommitted
dma-contiguous: support numa CMA for specified node
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. Adding another kernel parameter 'numa_cma=' to reserve CMA area for the specified node. If we want to use one of these parameters, we need to enable DMA_NUMA_CMA. At the same time, print the node id in cma_declare_contiguous_nid() if CONFIG_NUMA is enabled. Signed-off-by: Yajun Deng <yajun.deng@linux.dev> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 22e4a34 commit bf29bfa

4 files changed

Lines changed: 102 additions & 29 deletions

File tree

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,17 @@
706706
which is located in node nid, if the allocation fails,
707707
they will fallback to the global default memory area.
708708

709+
numa_cma=<node>:nn[MG][,<node>:nn[MG]]
710+
[KNL,CMA]
711+
Sets the size of kernel numa memory area for
712+
contiguous memory allocations. It will reserve CMA
713+
area for the specified node.
714+
715+
With numa CMA enabled, DMA users on node nid will
716+
first try to allocate buffer from the numa area
717+
which is located in node nid, if the allocation fails,
718+
they will fallback to the global default memory area.
719+
709720
cmo_free_hint= [PPC] Format: { yes | no }
710721
Specify whether pages are marked as being inactive
711722
when they are freed. This is used in CMO environments

kernel/dma/Kconfig

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,16 @@ config DMA_CMA
145145

146146
if DMA_CMA
147147

148-
config DMA_PERNUMA_CMA
149-
bool "Enable separate DMA Contiguous Memory Area for each NUMA Node"
148+
config DMA_NUMA_CMA
149+
bool "Enable separate DMA Contiguous Memory Area for NUMA Node"
150150
default NUMA
151151
help
152-
Enable this option to get pernuma CMA areas so that NUMA devices
152+
Enable this option to get numa CMA areas so that NUMA devices
153153
can get local memory by DMA coherent APIs.
154154

155155
You can set the size of pernuma CMA by specifying "cma_pernuma=size"
156-
on the kernel's command line.
156+
or set the node id and its size of CMA by specifying "numa_cma=
157+
<node>:size[,<node>:size]" on the kernel's command line.
157158

158159
comment "Default contiguous memory area size:"
159160

kernel/dma/contiguous.c

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <linux/sizes.h>
5151
#include <linux/dma-map-ops.h>
5252
#include <linux/cma.h>
53+
#include <linux/nospec.h>
5354

5455
#ifdef CONFIG_CMA_SIZE_MBYTES
5556
#define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
@@ -96,11 +97,44 @@ static int __init early_cma(char *p)
9697
}
9798
early_param("cma", early_cma);
9899

99-
#ifdef CONFIG_DMA_PERNUMA_CMA
100+
#ifdef CONFIG_DMA_NUMA_CMA
100101

102+
static struct cma *dma_contiguous_numa_area[MAX_NUMNODES];
103+
static phys_addr_t numa_cma_size[MAX_NUMNODES] __initdata;
101104
static struct cma *dma_contiguous_pernuma_area[MAX_NUMNODES];
102105
static phys_addr_t pernuma_size_bytes __initdata;
103106

107+
static int __init early_numa_cma(char *p)
108+
{
109+
int nid, count = 0;
110+
unsigned long tmp;
111+
char *s = p;
112+
113+
while (*s) {
114+
if (sscanf(s, "%lu%n", &tmp, &count) != 1)
115+
break;
116+
117+
if (s[count] == ':') {
118+
if (tmp >= MAX_NUMNODES)
119+
break;
120+
nid = array_index_nospec(tmp, MAX_NUMNODES);
121+
122+
s += count + 1;
123+
tmp = memparse(s, &s);
124+
numa_cma_size[nid] = tmp;
125+
126+
if (*s == ',')
127+
s++;
128+
else
129+
break;
130+
} else
131+
break;
132+
}
133+
134+
return 0;
135+
}
136+
early_param("numa_cma", early_numa_cma);
137+
104138
static int __init early_cma_pernuma(char *p)
105139
{
106140
pernuma_size_bytes = memparse(p, &p);
@@ -127,34 +161,47 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
127161

128162
#endif
129163

130-
#ifdef CONFIG_DMA_PERNUMA_CMA
131-
static void __init dma_pernuma_cma_reserve(void)
164+
#ifdef CONFIG_DMA_NUMA_CMA
165+
static void __init dma_numa_cma_reserve(void)
132166
{
133167
int nid;
134168

135-
if (!pernuma_size_bytes)
136-
return;
137-
138-
for_each_online_node(nid) {
169+
for_each_node(nid) {
139170
int ret;
140171
char name[CMA_MAX_NAME];
141-
struct cma **cma = &dma_contiguous_pernuma_area[nid];
142-
143-
snprintf(name, sizeof(name), "pernuma%d", nid);
144-
ret = cma_declare_contiguous_nid(0, pernuma_size_bytes, 0, 0,
145-
0, false, name, cma, nid);
146-
if (ret) {
147-
pr_warn("%s: reservation failed: err %d, node %d", __func__,
148-
ret, nid);
172+
struct cma **cma;
173+
174+
if (!node_online(nid)) {
175+
if (pernuma_size_bytes || numa_cma_size[nid])
176+
pr_warn("invalid node %d specified\n", nid);
149177
continue;
150178
}
151179

152-
pr_debug("%s: reserved %llu MiB on node %d\n", __func__,
153-
(unsigned long long)pernuma_size_bytes / SZ_1M, nid);
180+
if (pernuma_size_bytes) {
181+
182+
cma = &dma_contiguous_pernuma_area[nid];
183+
snprintf(name, sizeof(name), "pernuma%d", nid);
184+
ret = cma_declare_contiguous_nid(0, pernuma_size_bytes, 0, 0,
185+
0, false, name, cma, nid);
186+
if (ret)
187+
pr_warn("%s: reservation failed: err %d, node %d", __func__,
188+
ret, nid);
189+
}
190+
191+
if (numa_cma_size[nid]) {
192+
193+
cma = &dma_contiguous_numa_area[nid];
194+
snprintf(name, sizeof(name), "numa%d", nid);
195+
ret = cma_declare_contiguous_nid(0, numa_cma_size[nid], 0, 0, 0, false,
196+
name, cma, nid);
197+
if (ret)
198+
pr_warn("%s: reservation failed: err %d, node %d", __func__,
199+
ret, nid);
200+
}
154201
}
155202
}
156203
#else
157-
static inline void __init dma_pernuma_cma_reserve(void)
204+
static inline void __init dma_numa_cma_reserve(void)
158205
{
159206
}
160207
#endif
@@ -175,7 +222,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
175222
phys_addr_t selected_limit = limit;
176223
bool fixed = false;
177224

178-
dma_pernuma_cma_reserve();
225+
dma_numa_cma_reserve();
179226

180227
pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
181228

@@ -309,7 +356,7 @@ static struct page *cma_alloc_aligned(struct cma *cma, size_t size, gfp_t gfp)
309356
*/
310357
struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
311358
{
312-
#ifdef CONFIG_DMA_PERNUMA_CMA
359+
#ifdef CONFIG_DMA_NUMA_CMA
313360
int nid = dev_to_node(dev);
314361
#endif
315362

@@ -321,7 +368,7 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
321368
if (size <= PAGE_SIZE)
322369
return NULL;
323370

324-
#ifdef CONFIG_DMA_PERNUMA_CMA
371+
#ifdef CONFIG_DMA_NUMA_CMA
325372
if (nid != NUMA_NO_NODE && !(gfp & (GFP_DMA | GFP_DMA32))) {
326373
struct cma *cma = dma_contiguous_pernuma_area[nid];
327374
struct page *page;
@@ -331,6 +378,13 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
331378
if (page)
332379
return page;
333380
}
381+
382+
cma = dma_contiguous_numa_area[nid];
383+
if (cma) {
384+
page = cma_alloc_aligned(cma, size, gfp);
385+
if (page)
386+
return page;
387+
}
334388
}
335389
#endif
336390
if (!dma_contiguous_default_area)
@@ -362,10 +416,13 @@ void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
362416
/*
363417
* otherwise, page is from either per-numa cma or default cma
364418
*/
365-
#ifdef CONFIG_DMA_PERNUMA_CMA
419+
#ifdef CONFIG_DMA_NUMA_CMA
366420
if (cma_release(dma_contiguous_pernuma_area[page_to_nid(page)],
367421
page, count))
368422
return;
423+
if (cma_release(dma_contiguous_numa_area[page_to_nid(page)],
424+
page, count))
425+
return;
369426
#endif
370427
if (cma_release(dma_contiguous_default_area, page, count))
371428
return;

mm/cma.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ int __init cma_declare_contiguous_nid(phys_addr_t base,
267267
if (alignment && !is_power_of_2(alignment))
268268
return -EINVAL;
269269

270+
if (!IS_ENABLED(CONFIG_NUMA))
271+
nid = NUMA_NO_NODE;
272+
270273
/* Sanitise input arguments. */
271274
alignment = max_t(phys_addr_t, alignment, CMA_MIN_ALIGNMENT_BYTES);
272275
if (fixed && base & (alignment - 1)) {
@@ -372,14 +375,15 @@ int __init cma_declare_contiguous_nid(phys_addr_t base,
372375
if (ret)
373376
goto free_mem;
374377

375-
pr_info("Reserved %ld MiB at %pa\n", (unsigned long)size / SZ_1M,
376-
&base);
378+
pr_info("Reserved %ld MiB at %pa on node %d\n", (unsigned long)size / SZ_1M,
379+
&base, nid);
377380
return 0;
378381

379382
free_mem:
380383
memblock_phys_free(base, size);
381384
err:
382-
pr_err("Failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
385+
pr_err("Failed to reserve %ld MiB on node %d\n", (unsigned long)size / SZ_1M,
386+
nid);
383387
return ret;
384388
}
385389

0 commit comments

Comments
 (0)