Message ID | 20241025121547.181633-2-sughosh.ganu@linaro.org |
---|---|
State | Superseded |
Delegated to: | Michal Simek |
Headers | show |
Series | Add generic function for computing ram_top | expand |
On 10/25/24 14:15, Sughosh Ganu wrote: > Add generic logic to determine the ram_top value for boards. Earlier, > this was achieved in an indirect manner through a set of LMB API's. > That has since changed so that the LMB code is available only after > relocation. Replace those LMB calls with a single call to > get_mem_top() to determine the value of ram_top. > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org> > --- > common/Makefile | 1 + > common/memtop.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++ > include/memtop.h | 22 ++++++ > 3 files changed, 209 insertions(+) > create mode 100644 common/memtop.c > create mode 100644 include/memtop.h > > diff --git a/common/Makefile b/common/Makefile > index 2ee5ef9cc6e..35991562a12 100644 > --- a/common/Makefile > +++ b/common/Makefile > @@ -7,6 +7,7 @@ > ifndef CONFIG_XPL_BUILD > obj-y += init/ > obj-y += main.o > +obj-y += memtop.o > obj-y += exports.o > obj-y += cli_getch.o cli_simple.o cli_readline.o > obj-$(CONFIG_HUSH_OLD_PARSER) += cli_hush.o > diff --git a/common/memtop.c b/common/memtop.c > new file mode 100644 > index 00000000000..579daa89136 > --- /dev/null > +++ b/common/memtop.c > @@ -0,0 +1,186 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (c) 2024, Linaro Limited > + */ > + > +#include <fdt_support.h> > +#include <fdtdec.h> > +#include <memtop.h> > + > +#include <asm/types.h> > + > +#define MEM_RGN_COUNT 16 > + > +struct region { > + phys_addr_t base; > + phys_size_t size; > +}; > + > +struct mem_region { > + struct region rgn[MEM_RGN_COUNT]; > + uint count; > +}; > + > +static void add_mem_region(struct mem_region *mem_rgn, phys_addr_t base, > + phys_size_t size) > +{ > + long i; > + > + for (i = mem_rgn->count; i >= 0; i--) { > + if (i && base < mem_rgn->rgn[i - 1].base) { > + mem_rgn->rgn[i] = mem_rgn->rgn[i - 1]; > + } else { > + mem_rgn->rgn[i].base = base; > + mem_rgn->rgn[i].size = size; > + break; > + } > + } > + > + mem_rgn->count++; > +} > + > +static void mem_regions_init(struct mem_region *mem) > +{ > + uint i; > + > + mem->count = 0; > + for (i = 0; i < MEM_RGN_COUNT; i++) { > + mem->rgn[i].base = 0; > + mem->rgn[i].size = 0; > + } > +} > + > +static int fdt_add_reserved_regions(struct mem_region *free_mem, > + struct mem_region *reserved_mem, > + void *fdt_blob) > +{ > + u64 addr, size; > + int i, total, ret; > + int nodeoffset, subnode; > + struct fdt_resource res; > + > + if (fdt_check_header(fdt_blob) != 0) > + return -1; > + > + /* process memreserve sections */ > + total = fdt_num_mem_rsv(fdt_blob); > + assert_noisy(total < MEM_RGN_COUNT); > + for (i = 0; i < total; i++) { > + if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0) > + continue; > + add_mem_region(reserved_mem, addr, size); > + } > + > + i = 0; > + /* process reserved-memory */ > + nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory"); > + if (nodeoffset >= 0) { > + subnode = fdt_first_subnode(fdt_blob, nodeoffset); > + while (subnode >= 0) { > + /* check if this subnode has a reg property */ > + ret = fdt_get_resource(fdt_blob, subnode, "reg", 0, > + &res); > + if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) { > + addr = res.start; > + size = res.end - res.start + 1; > + assert_noisy(i < MEM_RGN_COUNT); > + add_mem_region(reserved_mem, addr, size); > + } > + > + subnode = fdt_next_subnode(fdt_blob, subnode); > + ++i; > + } > + } > + > + return 0; > +} > + > +static long addrs_overlap(phys_addr_t base1, phys_size_t size1, > + phys_addr_t base2, phys_size_t size2) > +{ > + const phys_addr_t base1_end = base1 + size1 - 1; > + const phys_addr_t base2_end = base2 + size2 - 1; > + > + return ((base1 <= base2_end) && (base2 <= base1_end)); > +} > + > +static long region_overlap_check(struct mem_region *mem_rgn, phys_addr_t base, > + phys_size_t size) > +{ > + unsigned long i; > + struct region *rgn = mem_rgn->rgn; > + > + for (i = 0; i < mem_rgn->count; i++) { > + phys_addr_t rgnbase = rgn[i].base; > + phys_size_t rgnsize = rgn[i].size; > + > + if (addrs_overlap(base, size, rgnbase, rgnsize)) > + break; > + } > + > + return (i < mem_rgn->count) ? i : -1; > +} > + > +static int find_ram_top(struct mem_region *free_mem, > + struct mem_region *reserved_mem, phys_size_t size) > +{ > + long i, rgn; > + phys_addr_t base = 0; > + phys_addr_t res_base; > + > + for (i = free_mem->count - 1; i >= 0; i--) { > + phys_addr_t rgnbase = free_mem->rgn[i].base; > + phys_size_t rgnsize = free_mem->rgn[i].size; > + > + if (rgnsize < size) > + continue; > + > + base = rgnbase + rgnsize - size; > + while (base && rgnbase <= base) { > + rgn = region_overlap_check(reserved_mem, base, size); > + if (rgn < 0) > + return base; > + > + res_base = reserved_mem->rgn[rgn].base; > + if (res_base < size) > + break; > + base = res_base - size; > + } > + } > + > + return 0; > +} > + > +/** > + * get_mem_top() - Compute the value of ram_top > + * @ram_start: Start of RAM > + * @ram_size: RAM size > + * @size: Minimum RAM size requested > + * @fdt: FDT blob > + * > + * The function computes the top address of RAM memory that can be > + * used by U-Boot. This is being done by going through the list of > + * reserved memory regions specified in the devicetree blob passed > + * to the function. The logic used here is derived from the lmb > + * allocation function. > + * > + * Return: address of ram top on success, 0 on failure > + */ There is likely no reason to have documentation written twice. Using in just header should be fine. When this is fixed feel free to add Reviewed-by: Michal Simek <michal.simek@amd.com> Thanks, Michal
diff --git a/common/Makefile b/common/Makefile index 2ee5ef9cc6e..35991562a12 100644 --- a/common/Makefile +++ b/common/Makefile @@ -7,6 +7,7 @@ ifndef CONFIG_XPL_BUILD obj-y += init/ obj-y += main.o +obj-y += memtop.o obj-y += exports.o obj-y += cli_getch.o cli_simple.o cli_readline.o obj-$(CONFIG_HUSH_OLD_PARSER) += cli_hush.o diff --git a/common/memtop.c b/common/memtop.c new file mode 100644 index 00000000000..579daa89136 --- /dev/null +++ b/common/memtop.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Linaro Limited + */ + +#include <fdt_support.h> +#include <fdtdec.h> +#include <memtop.h> + +#include <asm/types.h> + +#define MEM_RGN_COUNT 16 + +struct region { + phys_addr_t base; + phys_size_t size; +}; + +struct mem_region { + struct region rgn[MEM_RGN_COUNT]; + uint count; +}; + +static void add_mem_region(struct mem_region *mem_rgn, phys_addr_t base, + phys_size_t size) +{ + long i; + + for (i = mem_rgn->count; i >= 0; i--) { + if (i && base < mem_rgn->rgn[i - 1].base) { + mem_rgn->rgn[i] = mem_rgn->rgn[i - 1]; + } else { + mem_rgn->rgn[i].base = base; + mem_rgn->rgn[i].size = size; + break; + } + } + + mem_rgn->count++; +} + +static void mem_regions_init(struct mem_region *mem) +{ + uint i; + + mem->count = 0; + for (i = 0; i < MEM_RGN_COUNT; i++) { + mem->rgn[i].base = 0; + mem->rgn[i].size = 0; + } +} + +static int fdt_add_reserved_regions(struct mem_region *free_mem, + struct mem_region *reserved_mem, + void *fdt_blob) +{ + u64 addr, size; + int i, total, ret; + int nodeoffset, subnode; + struct fdt_resource res; + + if (fdt_check_header(fdt_blob) != 0) + return -1; + + /* process memreserve sections */ + total = fdt_num_mem_rsv(fdt_blob); + assert_noisy(total < MEM_RGN_COUNT); + for (i = 0; i < total; i++) { + if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0) + continue; + add_mem_region(reserved_mem, addr, size); + } + + i = 0; + /* process reserved-memory */ + nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory"); + if (nodeoffset >= 0) { + subnode = fdt_first_subnode(fdt_blob, nodeoffset); + while (subnode >= 0) { + /* check if this subnode has a reg property */ + ret = fdt_get_resource(fdt_blob, subnode, "reg", 0, + &res); + if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) { + addr = res.start; + size = res.end - res.start + 1; + assert_noisy(i < MEM_RGN_COUNT); + add_mem_region(reserved_mem, addr, size); + } + + subnode = fdt_next_subnode(fdt_blob, subnode); + ++i; + } + } + + return 0; +} + +static long addrs_overlap(phys_addr_t base1, phys_size_t size1, + phys_addr_t base2, phys_size_t size2) +{ + const phys_addr_t base1_end = base1 + size1 - 1; + const phys_addr_t base2_end = base2 + size2 - 1; + + return ((base1 <= base2_end) && (base2 <= base1_end)); +} + +static long region_overlap_check(struct mem_region *mem_rgn, phys_addr_t base, + phys_size_t size) +{ + unsigned long i; + struct region *rgn = mem_rgn->rgn; + + for (i = 0; i < mem_rgn->count; i++) { + phys_addr_t rgnbase = rgn[i].base; + phys_size_t rgnsize = rgn[i].size; + + if (addrs_overlap(base, size, rgnbase, rgnsize)) + break; + } + + return (i < mem_rgn->count) ? i : -1; +} + +static int find_ram_top(struct mem_region *free_mem, + struct mem_region *reserved_mem, phys_size_t size) +{ + long i, rgn; + phys_addr_t base = 0; + phys_addr_t res_base; + + for (i = free_mem->count - 1; i >= 0; i--) { + phys_addr_t rgnbase = free_mem->rgn[i].base; + phys_size_t rgnsize = free_mem->rgn[i].size; + + if (rgnsize < size) + continue; + + base = rgnbase + rgnsize - size; + while (base && rgnbase <= base) { + rgn = region_overlap_check(reserved_mem, base, size); + if (rgn < 0) + return base; + + res_base = reserved_mem->rgn[rgn].base; + if (res_base < size) + break; + base = res_base - size; + } + } + + return 0; +} + +/** + * get_mem_top() - Compute the value of ram_top + * @ram_start: Start of RAM + * @ram_size: RAM size + * @size: Minimum RAM size requested + * @fdt: FDT blob + * + * The function computes the top address of RAM memory that can be + * used by U-Boot. This is being done by going through the list of + * reserved memory regions specified in the devicetree blob passed + * to the function. The logic used here is derived from the lmb + * allocation function. + * + * Return: address of ram top on success, 0 on failure + */ +phys_addr_t get_mem_top(phys_addr_t ram_start, phys_size_t ram_size, + phys_size_t size, void *fdt) +{ + int i; + struct mem_region free_mem; + struct mem_region reserved_mem; + + mem_regions_init(&free_mem); + mem_regions_init(&reserved_mem); + + add_mem_region(&free_mem, ram_start, ram_size); + + i = fdt_add_reserved_regions(&free_mem, &reserved_mem, fdt); + if (i < 0) + return 0; + + return find_ram_top(&free_mem, &reserved_mem, size); +} diff --git a/include/memtop.h b/include/memtop.h new file mode 100644 index 00000000000..28f62e24ea7 --- /dev/null +++ b/include/memtop.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2024, Linaro Limited + */ + +/** + * get_mem_top() - Compute the value of ram_top + * @ram_start: Start of RAM + * @ram_size: RAM size + * @size: Minimum RAM size requested + * @fdt: FDT blob + * + * The function computes the top address of RAM memory that can be + * used by U-Boot. This is being done by going through the list of + * reserved memory regions specified in the devicetree blob passed + * to the function. The logic used here is derived from the lmb + * allocation function. + * + * Return: address of ram top on success, 0 on failure + */ +phys_addr_t get_mem_top(phys_addr_t ram_start, phys_size_t ram_size, + phys_size_t size, void *fdt);
Add generic logic to determine the ram_top value for boards. Earlier, this was achieved in an indirect manner through a set of LMB API's. That has since changed so that the LMB code is available only after relocation. Replace those LMB calls with a single call to get_mem_top() to determine the value of ram_top. Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org> --- common/Makefile | 1 + common/memtop.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++ include/memtop.h | 22 ++++++ 3 files changed, 209 insertions(+) create mode 100644 common/memtop.c create mode 100644 include/memtop.h