Only reserve or free the part of an FDT memory reservation that lies
below ram_top when LMB_LIMIT_DMA_BELOW_RAM_TOP is enabled.
With that option, LMB reserves all memory above ram_top itself, so that
nothing is allocated there. A reserved-memory node above ram_top then
overlaps that reservation, and reserving it fails with -EEXIST, which
prints an irrelevant error on every boot. A reservation that crosses
ram_top fails the same way, which also leaves its part below ram_top
unreserved.
These regions cannot be allocated anyway, like the regions outside the
LMB memory map that commit 94a09715bf4c ("boot: image-fdt: Restore
suppression of irrelevant ERROR message") handled.
Fixes: 623f6c5b6ab7 ("boot: image-fdt: free old dtb reservations")
Signed-off-by: David Lechner <[email protected]>
---
boot/image-fdt.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index 956a3d97c42..7098ab068db 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -19,7 +19,9 @@
#include <log.h>
#include <malloc.h>
#include <asm/global_data.h>
+#include <linux/kernel.h>
#include <linux/libfdt.h>
+#include <linux/sizes.h>
#include <mapmem.h>
#include <asm/io.h>
#include <dm/ofnode.h>
@@ -84,6 +86,25 @@ static void boot_fdt_handle_region(u64 addr, u64 size, u32
flags, bool free)
long ret;
phys_addr_t rsv_addr;
+ /*
+ * LMB already reserves all memory above ram_top so that nothing is
+ * allocated there. Only handle the part of the region below it.
+ */
+ if (IS_ENABLED(CONFIG_LMB_LIMIT_DMA_BELOW_RAM_TOP)) {
+ /* As in lmb_add_memory(), a ram_top of 0 means 4 GiB. */
+ u64 ram_top = gd->ram_top ?: SZ_4G;
+
+ if (addr >= ram_top) {
+ debug(" skip %s fdt memory region above ram_top:
addr=%llx size=%llx flags=%x\n",
+ free ? "freeing" : "reserving",
+ (unsigned long long)addr,
+ (unsigned long long)size, flags);
+ return;
+ }
+
+ size = min(size, ram_top - addr);
+ }
+
rsv_addr = (phys_addr_t)addr;
if (free)
ret = lmb_free(rsv_addr, size, flags);
--
2.53.0