[U-Boot] [PATCH] mpc86xx: adjust the DDR BATs after calculating true DDR size

Timur Tabi timur at freescale.com
Mon Mar 29 19:51:07 CEST 2010


After determining how much DDR is actually in the system, adjust DBAT0 and
IBAT0 accordingly.  This ensures that the CPU won't attempt to access
(via speculation) addresses outside of actual memory.

On 86xx systems, DBAT0 and IBAT0 (the BATs for DDR) are initialized to 2GB and
kept that way.  If the system has less than 2GB of memory (typical for an
MPC8610 HPCD), the CPU may attempt to access this memory during speculation.
The zlib code is notorious for generating such memory reads, and indeed on the
MPC8610, uncompressing the Linux kernel causes a machine check (without this
patch).

Signed-off-by: Timur Tabi <timur at freescale.com>
---
 board/freescale/mpc8610hpcd/mpc8610hpcd.c |    2 +
 board/freescale/mpc8641hpcn/mpc8641hpcn.c |    2 +
 cpu/mpc86xx/cpu.c                         |   44 +++++++++++++++++++++++++++++
 include/asm-ppc/mmu.h                     |    4 ++-
 include/mpc86xx.h                         |    2 +
 5 files changed, 53 insertions(+), 1 deletions(-)

diff --git a/board/freescale/mpc8610hpcd/mpc8610hpcd.c b/board/freescale/mpc8610hpcd/mpc8610hpcd.c
index 15a5b7b..b1623ba 100644
--- a/board/freescale/mpc8610hpcd/mpc8610hpcd.c
+++ b/board/freescale/mpc8610hpcd/mpc8610hpcd.c
@@ -125,6 +125,8 @@ initdram(int board_type)
 	dram_size = fixed_sdram();
 #endif
 
+	adjust_ddr_bat(dram_size);
+
 	puts(" DDR: ");
 	return dram_size;
 }
diff --git a/board/freescale/mpc8641hpcn/mpc8641hpcn.c b/board/freescale/mpc8641hpcn/mpc8641hpcn.c
index 7e6aabf..1f8b717 100644
--- a/board/freescale/mpc8641hpcn/mpc8641hpcn.c
+++ b/board/freescale/mpc8641hpcn/mpc8641hpcn.c
@@ -72,6 +72,8 @@ initdram(int board_type)
 	dram_size = fixed_sdram();
 #endif
 
+	adjust_ddr_bat(dram_size);
+
 	puts("    DDR: ");
 	return dram_size;
 }
diff --git a/cpu/mpc86xx/cpu.c b/cpu/mpc86xx/cpu.c
index f7e012d..00039d3 100644
--- a/cpu/mpc86xx/cpu.c
+++ b/cpu/mpc86xx/cpu.c
@@ -197,3 +197,47 @@ void mpc86xx_reginfo(void)
 	printf("\tBR7\t0x%08X\tOR7\t0x%08X \n", in_be32(&lbc->br7), in_be32(&lbc->or7));
 
 }
+
+/*
+ * Update the DDR BATs to reflect the actual size of DDR.
+ *
+ * On 86xx, the CONFIG_SYS_DBAT0U macro is used to specify the initial size of
+ * the BAT for DDR.  After the actual size of DDR is determined (which is
+ * usually smaller than the initial size), this BAT should be adjusted
+ * accordingly.  Otherwise, any inadvertent access to addresses beyond DDR
+ * (such as via speculative execution) can cause a machine check.
+ *
+ * dram_size is the actual size of DDR, in bytes
+ *
+ * Note: we assume that CONFIG_MAX_MEM_MAPPED is <= BATU_SIZE(BATU_BL_MAX);
+ * that is, the maximum amount of memory that U-Boot will ever map will always
+ * fit into one BAT.  If this is not true, (e.g. CONFIG_MAX_MEM_MAPPED is 2GB
+ * but HID0_XBSEN is not defined) then we might have a situation where U-Boot
+ * will attempt to relocated itself outside of the region mapped by DBAT0.
+ * This will cause a machine check.
+ *
+ * We also assume that the XBL bits are ignored by the processor (even if set)
+ * if extended BAT addressing is disabled.
+ */
+void adjust_ddr_bat(phys_addr_t dram_size)
+{
+	unsigned long batl, batu, bl;
+
+	bl = KB_TO_BATU(dram_size / 1024) & BATU_BL_MAX;
+
+	if (BATU_SIZE(bl) != dram_size) {
+		puts("(limiting mapped memory to ");
+		print_size(BATU_SIZE(bl), ")");
+		bl = BATU_BL_MAX;
+	}
+
+	read_bat(DBAT0, &batu, &batl);
+	batu &= ~BATU_BL_MAX;
+	batu |= bl;
+	write_bat(DBAT0, batu, batl);
+
+	read_bat(IBAT0, &batu, &batl);
+	batu &= ~BATU_BL_MAX;
+	batu |= bl;
+	write_bat(IBAT0, batu, batl);
+}
diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
index fd10249..34a292d 100644
--- a/include/asm-ppc/mmu.h
+++ b/include/asm-ppc/mmu.h
@@ -213,7 +213,9 @@ extern void print_bats(void);
 #define BATL_PADDR(x) ((phys_addr_t)((x & 0xfffe0000)		\
 				     | ((x & 0x0e00ULL) << 24)	\
 				     | ((x & 0x04ULL) << 30)))
-#define BATU_SIZE(x) (1UL << (fls((x & BATU_BL_MAX) >> 2) + 17))
+#define BATU_SIZE(x) (1ULL << (fls((x & BATU_BL_MAX) >> 2) + 17))
+
+#define KB_TO_BATU(x) ((((x)/128) - 1) * 4) /* Convert KBs to BATU value */
 
 /* Used to set up SDR1 register */
 #define HASH_TABLE_SIZE_64K	0x00010000
diff --git a/include/mpc86xx.h b/include/mpc86xx.h
index c6f30f9..42f8b13 100644
--- a/include/mpc86xx.h
+++ b/include/mpc86xx.h
@@ -83,5 +83,7 @@ static __inline__ unsigned long get_l2cr (void)
    return l2cr_val;
 }
 
+void adjust_ddr_bat(phys_addr_t dram_kb);
+
 #endif  /* _ASMLANGUAGE */
 #endif	/* __MPC86xx_H__ */
-- 
1.6.5



More information about the U-Boot mailing list