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

Reply via email to