Skip to content

Commit 83ba736

Browse files
stephan-ghrobherring
authored andcommitted
of: reserved_mem: Try to keep range allocations contiguous
Right now dynamic reserved memory regions are allocated either bottom-up or top-down, depending on the memblock setting of the architecture. This is fine when the address is arbitrary. However, when using "alloc-ranges" the regions are often placed somewhere in the middle of (free) RAM, even if the range starts or ends next to another (static) reservation. Try to detect this situation, and choose explicitly between bottom-up or top-down to allocate the memory close to the other reservations: 1. If the "alloc-range" starts at the end or inside an existing reservation, use bottom-up. 2. If the "alloc-range" ends at the start or inside an existing reservation, use top-down. 3. If both or none is the case, keep the current (architecture-specific) behavior. There are plenty of edge cases where only a more complex algorithm would help, but even this simple approach helps in many cases to keep the reserved memory (and therefore also the free memory) contiguous. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> Link: https://lore.kernel.org/r/20230510-dt-resv-bottom-up-v2-1-aeb2afc8ac25@gerhold.net Signed-off-by: Rob Herring <robh@kernel.org>
1 parent 02478c9 commit 83ba736

1 file changed

Lines changed: 53 additions & 2 deletions

File tree

drivers/of/of_reserved_mem.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,57 @@ void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
7777
return;
7878
}
7979

80+
/*
81+
* __reserved_mem_alloc_in_range() - allocate reserved memory described with
82+
* 'alloc-ranges'. Choose bottom-up/top-down depending on nearby existing
83+
* reserved regions to keep the reserved memory contiguous if possible.
84+
*/
85+
static int __init __reserved_mem_alloc_in_range(phys_addr_t size,
86+
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
87+
phys_addr_t *res_base)
88+
{
89+
bool prev_bottom_up = memblock_bottom_up();
90+
bool bottom_up = false, top_down = false;
91+
int ret, i;
92+
93+
for (i = 0; i < reserved_mem_count; i++) {
94+
struct reserved_mem *rmem = &reserved_mem[i];
95+
96+
/* Skip regions that were not reserved yet */
97+
if (rmem->size == 0)
98+
continue;
99+
100+
/*
101+
* If range starts next to an existing reservation, use bottom-up:
102+
* |....RRRR................RRRRRRRR..............|
103+
* --RRRR------
104+
*/
105+
if (start >= rmem->base && start <= (rmem->base + rmem->size))
106+
bottom_up = true;
107+
108+
/*
109+
* If range ends next to an existing reservation, use top-down:
110+
* |....RRRR................RRRRRRRR..............|
111+
* -------RRRR-----
112+
*/
113+
if (end >= rmem->base && end <= (rmem->base + rmem->size))
114+
top_down = true;
115+
}
116+
117+
/* Change setting only if either bottom-up or top-down was selected */
118+
if (bottom_up != top_down)
119+
memblock_set_bottom_up(bottom_up);
120+
121+
ret = early_init_dt_alloc_reserved_memory_arch(size, align,
122+
start, end, nomap, res_base);
123+
124+
/* Restore old setting if needed */
125+
if (bottom_up != top_down)
126+
memblock_set_bottom_up(prev_bottom_up);
127+
128+
return ret;
129+
}
130+
80131
/*
81132
* __reserved_mem_alloc_size() - allocate reserved memory described by
82133
* 'size', 'alignment' and 'alloc-ranges' properties.
@@ -137,8 +188,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
137188
end = start + dt_mem_next_cell(dt_root_size_cells,
138189
&prop);
139190

140-
ret = early_init_dt_alloc_reserved_memory_arch(size,
141-
align, start, end, nomap, &base);
191+
ret = __reserved_mem_alloc_in_range(size, align,
192+
start, end, nomap, &base);
142193
if (ret == 0) {
143194
pr_debug("allocated memory for '%s' node: base %pa, size %lu MiB\n",
144195
uname, &base,

0 commit comments

Comments
 (0)