[PATCH v2] image: fdt: Fix DT relocation handling with multiple DRAM banks with gap

Marek Vasut marex at denx.de
Fri Apr 8 02:09:19 CEST 2022


The current implementation of boot_relocate_fdt() places DT at the
highest usable DRAM address, which is calculated as:
  env_get_bootm_low() + env_get_bootm_mapsize()
which by default becomes gd->ram_base + gd->ram_size.

Systems like i.MX53 can have multiple DRAM banks with gap between them,
e.g. have DRAM at 0x70000000-0x8fffffff and 0xb0000000-0xcfffffff , so
for them the calculated highest DRAM address is 0xafffffff, which is
exactly in the gap and thus not usable.

Fix this by iterating over all DRAM banks and tracking the remaining
amount of the total mapping size obtained from env_get_bootm_mapsize().
Limit the maximum LMB area size to each bank, to avoid using nonexistent
DRAM.

Reviewed-by: Simon Glass <sjg at chromium.org>
Signed-off-by: Marek Vasut <marex at denx.de>
Cc: Heinrich Schuchardt <xypron.glpk at gmx.de>
Cc: Simon Glass <sjg at chromium.org>
Cc: Tom Rini <trini at konsulko.com>
---
V2: Collect RB, rebase on v2022.04+
---
 boot/image-fdt.c | 40 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index 692a9ad3e42..fe2fc3351ba 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -165,8 +165,11 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
 {
 	void	*fdt_blob = *of_flat_tree;
 	void	*of_start = NULL;
+	u64	start, size, usable;
 	char	*fdt_high;
+	ulong	mapsize, low;
 	ulong	of_len = 0;
+	int	bank;
 	int	err;
 	int	disable_relocation = 0;
 
@@ -206,10 +209,39 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
 			    (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
 		}
 	} else {
-		of_start =
-		    (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
-						   env_get_bootm_mapsize()
-						   + env_get_bootm_low());
+		mapsize = env_get_bootm_mapsize();
+		low = env_get_bootm_low();
+		of_start = NULL;
+
+		for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+			start = gd->bd->bi_dram[bank].start;
+			size = gd->bd->bi_dram[bank].size;
+
+			/* DRAM bank addresses are too low, skip it. */
+			if (start + size < low)
+				continue;
+
+			usable = min(size, (u64)mapsize);
+
+			/*
+			 * At least part of this DRAM bank is usable, try
+			 * using it for LMB allocation.
+			 */
+			of_start =
+			    (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
+							   start + usable);
+			/* Allocation succeeded, use this block. */
+			if (of_start != NULL)
+				break;
+
+			/*
+			 * Reduce the mapping size in the next bank
+			 * by the size of attempt in current bank.
+			 */
+			mapsize -= usable - max(start, (u64)low);
+			if (!mapsize)
+				break;
+		}
 	}
 
 	if (of_start == NULL) {
-- 
2.35.1



More information about the U-Boot mailing list