diff options
author | Ahmad Fatoum <a.fatoum@pengutronix.de> | 2021-05-31 09:12:35 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-06-02 08:37:22 +0200 |
commit | 0a78ac84e9fe3e91d9b01b1e128ea493c6ebc3f4 (patch) | |
tree | dfee4cf3c4932c1fa7aa7399ecf8e10faee45158 /common/memory.c | |
parent | b9958d497dfd9fc563b198f7233c57388d76cd06 (diff) | |
download | barebox-0a78ac84e9fe3e91d9b01b1e128ea493c6ebc3f4.tar.gz |
memory: fuse overlapping memory banks
Some ARM subarchitectures read back RAM size from the SDRAM
controller and use the info to register memory banks.
If an overlapping memory region is already registered, e.g. via device
tree /memory, this second registration will fail.
This is especially annoying as it can regress after a device tree sync:
- Kind soul updates upstream device tree to describe minimal available
RAM across hardware variants
- barebox PBL has enough info about the board to set up larger RAM size
and relocates barebox to the end of the RAM
- barebox proper starts with new device tree and is upset to
find itself outside of registered memory
Account for this by growing the existing bank if a bank to be added
happens to overlap it. As a special case, if the existing bank
completely contains the new memory bank, the function is a no-op.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Link: https://lore.barebox.org/20210531071239.30653-3-a.fatoum@pengutronix.de
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'common/memory.c')
-rw-r--r-- | common/memory.c | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/common/memory.c b/common/memory.c index 612ed87168..95995bb6e3 100644 --- a/common/memory.c +++ b/common/memory.c @@ -111,15 +111,56 @@ void *sbrk(ptrdiff_t increment) LIST_HEAD(memory_banks); +static int barebox_grow_memory_bank(struct memory_bank *bank, const char *name, + const struct resource *newres) +{ + struct resource *res; + resource_size_t bank_end = bank->res->end; + + if (newres->start < bank->start) { + res = request_iomem_region(name, newres->start, bank->start - 1); + if (IS_ERR(res)) + return PTR_ERR(res); + __merge_regions(name, bank->res, res); + } + + if (bank_end < newres->end) { + res = request_iomem_region(name, bank_end + 1, newres->end); + if (IS_ERR(res)) + return PTR_ERR(res); + __merge_regions(name, bank->res, res); + } + + bank->start = newres->start; + bank->size = resource_size(bank->res); + + return 0; +} + int barebox_add_memory_bank(const char *name, resource_size_t start, resource_size_t size) { - struct memory_bank *bank = xzalloc(sizeof(*bank)); + struct memory_bank *bank; + struct resource *res; + struct resource newres = { + .start = start, + .end = start + size - 1, + }; + + for_each_memory_bank(bank) { + if (resource_contains(bank->res, &newres)) + return 0; + if (resource_contains(&newres, bank->res)) + return barebox_grow_memory_bank(bank, name, &newres); + } + + res = request_iomem_region(name, start, start + size - 1); + if (IS_ERR(res)) + return PTR_ERR(res); - bank->res = request_iomem_region(name, start, start + size - 1); - if (IS_ERR(bank->res)) - return PTR_ERR(bank->res); + bank = xzalloc(sizeof(*bank)); + bank->res = res; bank->start = start; bank->size = size; |