Skip to content

Commit 8a6e02d

Browse files
Oreoluwa Babatunderobherring
authored andcommitted
of: reserved_mem: Restructure how the reserved memory regions are processed
Reserved memory regions defined in the devicetree can be broken up into two groups: i) Statically-placed reserved memory regions i.e. regions defined with a static start address and size using the "reg" property. ii) Dynamically-placed reserved memory regions. i.e. regions defined by specifying an address range where they can be placed in memory using the "alloc_ranges" and "size" properties. These regions are processed and set aside at boot time. This is done in two stages as seen below: Stage 1: At this stage, fdt_scan_reserved_mem() scans through the child nodes of the reserved_memory node using the flattened devicetree and does the following: 1) If the node represents a statically-placed reserved memory region, i.e. if it is defined using the "reg" property: - Call memblock_reserve() or memblock_mark_nomap() as needed. - Add the information for that region into the reserved_mem array using fdt_reserved_mem_save_node(). i.e. fdt_reserved_mem_save_node(node, name, base, size). 2) If the node represents a dynamically-placed reserved memory region, i.e. if it is defined using "alloc-ranges" and "size" properties: - Add the information for that region to the reserved_mem array with the starting address and size set to 0. i.e. fdt_reserved_mem_save_node(node, name, 0, 0). Note: This region is saved to the array with a starting address of 0 because a starting address is not yet allocated for it. Stage 2: After iterating through all the reserved memory nodes and storing their relevant information in the reserved_mem array,fdt_init_reserved_mem() is called and does the following: 1) For statically-placed reserved memory regions: - Call the region specific init function using __reserved_mem_init_node(). 2) For dynamically-placed reserved memory regions: - Call __reserved_mem_alloc_size() which is used to allocate memory for each of these regions, and mark them as nomap if they have the nomap property specified in the DT. - Call the region specific init function. The current size of the resvered_mem array is 64 as is defined by MAX_RESERVED_REGIONS. This means that there is a limitation of 64 for how many reserved memory regions can be specified on a system. As systems continue to grow more and more complex, the number of reserved memory regions needed are also growing and are starting to hit this 64 count limit, hence the need to make the reserved_mem array dynamically sized (i.e. dynamically allocating memory for the reserved_mem array using membock_alloc_*). On architectures such as arm64, memory allocated using memblock is writable only after the page tables have been setup. This means that if the reserved_mem array is going to be dynamically allocated, it needs to happen after the page tables have been setup, not before. Since the reserved memory regions are currently being processed and added to the array before the page tables are setup, there is a need to change the order in which some of the processing is done to allow for the reserved_mem array to be dynamically sized. It is possible to process the statically-placed reserved memory regions without needing to store them in the reserved_mem array until after the page tables have been setup because all the information stored in the array is readily available in the devicetree and can be referenced at any time. Dynamically-placed reserved memory regions on the other hand get assigned a start address only at runtime, and hence need a place to be stored once they are allocated since there is no other referrence to the start address for these regions. Hence this patch changes the processing order of the reserved memory regions in the following ways: Step 1: fdt_scan_reserved_mem() scans through the child nodes of the reserved_memory node using the flattened devicetree and does the following: 1) If the node represents a statically-placed reserved memory region, i.e. if it is defined using the "reg" property: - Call memblock_reserve() or memblock_mark_nomap() as needed. 2) If the node represents a dynamically-placed reserved memory region, i.e. if it is defined using "alloc-ranges" and "size" properties: - Call __reserved_mem_alloc_size() which will: i) Allocate memory for the reserved region and call memblock_mark_nomap() as needed. ii) Call the region specific initialization function using fdt_init_reserved_mem_node(). iii) Save the region information in the reserved_mem array using fdt_reserved_mem_save_node(). Step 2: 1) This stage of the reserved memory processing is now only used to add the statically-placed reserved memory regions into the reserved_mem array using fdt_scan_reserved_mem_reg_nodes(), as well as call their region specific initialization functions. 2) This step has also been moved to be after the page tables are setup. Moving this will allow us to replace the reserved_mem array with a dynamically sized array before storing the rest of these regions. Signed-off-by: Oreoluwa Babatunde <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Rob Herring (Arm) <[email protected]>
1 parent d79616b commit 8a6e02d

File tree

3 files changed

+122
-54
lines changed

3 files changed

+122
-54
lines changed

drivers/of/fdt.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,8 +511,6 @@ void __init early_init_fdt_scan_reserved_mem(void)
511511
break;
512512
memblock_reserve(base, size);
513513
}
514-
515-
fdt_init_reserved_mem();
516514
}
517515

518516
/**
@@ -1212,6 +1210,9 @@ void __init unflatten_device_tree(void)
12121210
{
12131211
void *fdt = initial_boot_params;
12141212

1213+
/* Save the statically-placed regions in the reserved_mem array */
1214+
fdt_scan_reserved_mem_reg_nodes();
1215+
12151216
/* Don't use the bootloader provided DTB if ACPI is enabled */
12161217
if (!acpi_disabled)
12171218
fdt = NULL;

drivers/of/of_private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#define FDT_ALIGN_SIZE 8
12+
#define MAX_RESERVED_REGIONS 64
1213

1314
/**
1415
* struct alias_prop - Alias property in 'aliases' node
@@ -180,7 +181,7 @@ static inline struct device_node *__of_get_dma_parent(const struct device_node *
180181
#endif
181182

182183
int fdt_scan_reserved_mem(void);
183-
void fdt_init_reserved_mem(void);
184+
void __init fdt_scan_reserved_mem_reg_nodes(void);
184185

185186
bool of_fdt_device_is_available(const void *blob, unsigned long node);
186187

drivers/of/of_reserved_mem.c

Lines changed: 117 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
#include "of_private.h"
2929

30-
#define MAX_RESERVED_REGIONS 64
3130
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
3231
static int reserved_mem_count;
3332

@@ -56,6 +55,7 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
5655
return err;
5756
}
5857

58+
static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem);
5959
/*
6060
* fdt_reserved_mem_save_node() - save fdt node for second pass initialization
6161
*/
@@ -74,6 +74,9 @@ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *un
7474
rmem->base = base;
7575
rmem->size = size;
7676

77+
/* Call the region specific initialization function */
78+
fdt_init_reserved_mem_node(rmem);
79+
7780
reserved_mem_count++;
7881
return;
7982
}
@@ -106,7 +109,6 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
106109
phys_addr_t base, size;
107110
int len;
108111
const __be32 *prop;
109-
int first = 1;
110112
bool nomap;
111113

112114
prop = of_get_flat_dt_prop(node, "reg", &len);
@@ -134,10 +136,6 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
134136
uname, &base, (unsigned long)(size / SZ_1M));
135137

136138
len -= t_len;
137-
if (first) {
138-
fdt_reserved_mem_save_node(node, uname, base, size);
139-
first = 0;
140-
}
141139
}
142140
return 0;
143141
}
@@ -165,12 +163,77 @@ static int __init __reserved_mem_check_root(unsigned long node)
165163
return 0;
166164
}
167165

166+
static void __init __rmem_check_for_overlap(void);
167+
168+
/**
169+
* fdt_scan_reserved_mem_reg_nodes() - Store info for the "reg" defined
170+
* reserved memory regions.
171+
*
172+
* This function is used to scan through the DT and store the
173+
* information for the reserved memory regions that are defined using
174+
* the "reg" property. The region node number, name, base address, and
175+
* size are all stored in the reserved_mem array by calling the
176+
* fdt_reserved_mem_save_node() function.
177+
*/
178+
void __init fdt_scan_reserved_mem_reg_nodes(void)
179+
{
180+
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
181+
const void *fdt = initial_boot_params;
182+
phys_addr_t base, size;
183+
const __be32 *prop;
184+
int node, child;
185+
int len;
186+
187+
if (!fdt)
188+
return;
189+
190+
node = fdt_path_offset(fdt, "/reserved-memory");
191+
if (node < 0) {
192+
pr_info("Reserved memory: No reserved-memory node in the DT\n");
193+
return;
194+
}
195+
196+
if (__reserved_mem_check_root(node)) {
197+
pr_err("Reserved memory: unsupported node format, ignoring\n");
198+
return;
199+
}
200+
201+
fdt_for_each_subnode(child, fdt, node) {
202+
const char *uname;
203+
204+
prop = of_get_flat_dt_prop(child, "reg", &len);
205+
if (!prop)
206+
continue;
207+
if (!of_fdt_device_is_available(fdt, child))
208+
continue;
209+
210+
uname = fdt_get_name(fdt, child, NULL);
211+
if (len && len % t_len != 0) {
212+
pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
213+
uname);
214+
continue;
215+
}
216+
base = dt_mem_next_cell(dt_root_addr_cells, &prop);
217+
size = dt_mem_next_cell(dt_root_size_cells, &prop);
218+
219+
if (size)
220+
fdt_reserved_mem_save_node(child, uname, base, size);
221+
}
222+
223+
/* check for overlapping reserved regions */
224+
__rmem_check_for_overlap();
225+
}
226+
227+
static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname);
228+
168229
/*
169230
* fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
170231
*/
171232
int __init fdt_scan_reserved_mem(void)
172233
{
173234
int node, child;
235+
int dynamic_nodes_cnt = 0;
236+
int dynamic_nodes[MAX_RESERVED_REGIONS];
174237
const void *fdt = initial_boot_params;
175238

176239
node = fdt_path_offset(fdt, "/reserved-memory");
@@ -192,8 +255,24 @@ int __init fdt_scan_reserved_mem(void)
192255
uname = fdt_get_name(fdt, child, NULL);
193256

194257
err = __reserved_mem_reserve_reg(child, uname);
195-
if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL))
196-
fdt_reserved_mem_save_node(child, uname, 0, 0);
258+
/*
259+
* Save the nodes for the dynamically-placed regions
260+
* into an array which will be used for allocation right
261+
* after all the statically-placed regions are reserved
262+
* or marked as no-map. This is done to avoid dynamically
263+
* allocating from one of the statically-placed regions.
264+
*/
265+
if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) {
266+
dynamic_nodes[dynamic_nodes_cnt] = child;
267+
dynamic_nodes_cnt++;
268+
}
269+
}
270+
for (int i = 0; i < dynamic_nodes_cnt; i++) {
271+
const char *uname;
272+
273+
child = dynamic_nodes[i];
274+
uname = fdt_get_name(fdt, child, NULL);
275+
__reserved_mem_alloc_size(child, uname);
197276
}
198277
return 0;
199278
}
@@ -253,8 +332,7 @@ static int __init __reserved_mem_alloc_in_range(phys_addr_t size,
253332
* __reserved_mem_alloc_size() - allocate reserved memory described by
254333
* 'size', 'alignment' and 'alloc-ranges' properties.
255334
*/
256-
static int __init __reserved_mem_alloc_size(unsigned long node,
257-
const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
335+
static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname)
258336
{
259337
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
260338
phys_addr_t start = 0, end = 0;
@@ -334,9 +412,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
334412
return -ENOMEM;
335413
}
336414

337-
*res_base = base;
338-
*res_size = size;
339-
415+
/* Save region in the reserved_mem array */
416+
fdt_reserved_mem_save_node(node, uname, base, size);
340417
return 0;
341418
}
342419

@@ -425,48 +502,37 @@ static void __init __rmem_check_for_overlap(void)
425502
}
426503

427504
/**
428-
* fdt_init_reserved_mem() - allocate and init all saved reserved memory regions
505+
* fdt_init_reserved_mem_node() - Initialize a reserved memory region
506+
* @rmem: reserved_mem struct of the memory region to be initialized.
507+
*
508+
* This function is used to call the region specific initialization
509+
* function for a reserved memory region.
429510
*/
430-
void __init fdt_init_reserved_mem(void)
511+
static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem)
431512
{
432-
int i;
433-
434-
/* check for overlapping reserved regions */
435-
__rmem_check_for_overlap();
436-
437-
for (i = 0; i < reserved_mem_count; i++) {
438-
struct reserved_mem *rmem = &reserved_mem[i];
439-
unsigned long node = rmem->fdt_node;
440-
int err = 0;
441-
bool nomap;
513+
unsigned long node = rmem->fdt_node;
514+
int err = 0;
515+
bool nomap;
442516

443-
nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
517+
nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
444518

445-
if (rmem->size == 0)
446-
err = __reserved_mem_alloc_size(node, rmem->name,
447-
&rmem->base, &rmem->size);
448-
if (err == 0) {
449-
err = __reserved_mem_init_node(rmem);
450-
if (err != 0 && err != -ENOENT) {
451-
pr_info("node %s compatible matching fail\n",
452-
rmem->name);
453-
if (nomap)
454-
memblock_clear_nomap(rmem->base, rmem->size);
455-
else
456-
memblock_phys_free(rmem->base,
457-
rmem->size);
458-
} else {
459-
phys_addr_t end = rmem->base + rmem->size - 1;
460-
bool reusable =
461-
(of_get_flat_dt_prop(node, "reusable", NULL)) != NULL;
462-
463-
pr_info("%pa..%pa (%lu KiB) %s %s %s\n",
464-
&rmem->base, &end, (unsigned long)(rmem->size / SZ_1K),
465-
nomap ? "nomap" : "map",
466-
reusable ? "reusable" : "non-reusable",
467-
rmem->name ? rmem->name : "unknown");
468-
}
469-
}
519+
err = __reserved_mem_init_node(rmem);
520+
if (err != 0 && err != -ENOENT) {
521+
pr_info("node %s compatible matching fail\n", rmem->name);
522+
if (nomap)
523+
memblock_clear_nomap(rmem->base, rmem->size);
524+
else
525+
memblock_phys_free(rmem->base, rmem->size);
526+
} else {
527+
phys_addr_t end = rmem->base + rmem->size - 1;
528+
bool reusable =
529+
(of_get_flat_dt_prop(node, "reusable", NULL)) != NULL;
530+
531+
pr_info("%pa..%pa (%lu KiB) %s %s %s\n",
532+
&rmem->base, &end, (unsigned long)(rmem->size / SZ_1K),
533+
nomap ? "nomap" : "map",
534+
reusable ? "reusable" : "non-reusable",
535+
rmem->name ? rmem->name : "unknown");
470536
}
471537
}
472538

0 commit comments

Comments
 (0)