[PATCH v6 10/23] powerpc/8xx: map more RAM at startup when needed

From: Christophe Leroy
Date: Thu Feb 04 2016 - 05:33:39 EST


On recent kernels, with some debug options like for instance
CONFIG_LOCKDEP, the BSS requires more than 8M memory, allthough
the kernel code fits in the first 8M.
Today, it is necessary to activate CONFIG_PIN_TLB to get more than 8M
at startup, allthough pinning TLB is not necessary for that.

This patch adds more pages (up to 24Mb) to the initial mapping if
possible/needed in order to have the necessary mappings regardless of
CONFIG_PIN_TLB.

We could have mapped 16M or 24M inconditionnally but since some
platforms only have 8M memory, we need something a bit more elaborated

Therefore, if the bootloader is compliant with ePAPR standard, we use
r7 to know how much memory was mapped by the bootloader.
Otherwise, we try to determine the required memory size by looking at
the _end symbol and the address of the device tree.

This patch does not modify the behaviour when CONFIG_PIN_TLB is
selected.

Signed-off-by: Christophe Leroy <christophe.leroy@xxxxxx>
---
v2: no change
v3: Automatic detection of available/needed memory instead of allocating 16M for all.
v4: no change
v5: no change
v6: no change

arch/powerpc/kernel/head_8xx.S | 56 +++++++++++++++++++++++++++++++++++++++---
arch/powerpc/mm/8xx_mmu.c | 10 +++-----
2 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index ae721a1..a268cf4 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -72,6 +72,9 @@
#define RPN_PATTERN 0x00f0
#endif

+/* ePAPR magic value for non BOOK III-E CPUs */
+#define EPAPR_SMAGIC 0x65504150
+
__HEAD
_ENTRY(_stext);
_ENTRY(_start);
@@ -101,6 +104,38 @@ _ENTRY(_start);
*/
.globl __start
__start:
+/*
+ * Determine initial RAM size
+ *
+ * If the Bootloader is ePAPR compliant, the size is given in r7
+ * otherwise, we have to determine how much is needed. For that, we have to
+ * check whether _end of kernel and device tree are within the first 8Mb.
+ */
+ lis r30, 0x00800000@h /* 8Mb by default */
+
+ lis r8, EPAPR_SMAGIC@h
+ ori r8, r8, EPAPR_SMAGIC@l
+ cmplw cr0, r8, r6
+ bne 1f
+ lis r30, 0x01800000@h /* 24Mb max */
+ cmplw cr0, r7, r30
+ bgt 2f
+ mr r30, r7 /* save initial ram size */
+ b 2f
+1:
+ /* is kernel _end or DTB in the first 8M ? if not map 16M */
+ lis r8, (_end - PAGE_OFFSET)@h
+ ori r8, r8, (_end - PAGE_OFFSET)@l
+ addi r8, r8, -1
+ or r8, r8, r3
+ cmplw cr0, r8, r30
+ blt 2f
+ lis r30, 0x01000000@h /* 16Mb */
+ /* is kernel _end or DTB in the first 16M ? if not map 24M */
+ cmplw cr0, r8, r30
+ blt 2f
+ lis r30, 0x01800000@h /* 24Mb */
+2:
mr r31,r3 /* save device tree ptr */

/* We have to turn on the MMU right away so we get cache modes
@@ -737,6 +772,8 @@ start_here:
/*
* Decide what sort of machine this is and initialize the MMU.
*/
+ lis r3, initial_memory_size@ha
+ stw r30, initial_memory_size@l(r3)
li r3,0
mr r4,r31
bl machine_init
@@ -868,10 +905,15 @@ initial_mmu:
mtspr SPRN_MD_RPN, r8

#ifdef CONFIG_PIN_TLB
- /* Map two more 8M kernel data pages.
- */
+ /* Map one more 8M kernel data page. */
addi r10, r10, 0x0100
mtspr SPRN_MD_CTR, r10
+#else
+ /* Map one more 8M kernel data page if needed */
+ lis r10, 0x00800000@h
+ cmplw cr0, r30, r10
+ ble 1f
+#endif

lis r8, KERNELBASE@h /* Create vaddr for TLB */
addis r8, r8, 0x0080 /* Add 8M */
@@ -884,20 +926,28 @@ initial_mmu:
addis r11, r11, 0x0080 /* Add 8M */
mtspr SPRN_MD_RPN, r11

+#ifdef CONFIG_PIN_TLB
+ /* Map one more 8M kernel data page. */
addi r10, r10, 0x0100
mtspr SPRN_MD_CTR, r10
+#else
+ /* Map one more 8M kernel data page if needed */
+ lis r10, 0x01000000@h
+ cmplw cr0, r30, r10
+ ble 1f
+#endif

addis r8, r8, 0x0080 /* Add 8M */
mtspr SPRN_MD_EPN, r8
mtspr SPRN_MD_TWC, r9
addis r11, r11, 0x0080 /* Add 8M */
mtspr SPRN_MD_RPN, r11
-#endif

/* Since the cache is enabled according to the information we
* just loaded into the TLB, invalidate and enable the caches here.
* We should probably check/set other modes....later.
*/
+1:
lis r8, IDC_INVALL@h
mtspr SPRN_IC_CST, r8
mtspr SPRN_DC_CST, r8
diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c
index f37d5ec..50f17d2 100644
--- a/arch/powerpc/mm/8xx_mmu.c
+++ b/arch/powerpc/mm/8xx_mmu.c
@@ -20,6 +20,7 @@
#define IMMR_SIZE (__fix_to_virt(FIX_IMMR_TOP) + PAGE_SIZE - VIRT_IMMR_BASE)

extern int __map_without_ltlbs;
+int initial_memory_size; /* size of initial memory mapped by head_8xx.S */

/*
* Return PA for this VA if it is in IMMR area, or 0
@@ -143,11 +144,6 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
*/
BUG_ON(first_memblock_base != 0);

-#ifdef CONFIG_PIN_TLB
- /* 8xx can only access 24MB at the moment */
- memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01800000));
-#else
- /* 8xx can only access 8MB at the moment */
- memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000));
-#endif
+ memblock_set_current_limit(min_t(u64, first_memblock_size,
+ initial_memory_size));
}
--
2.1.0