[PATCH RFC 1/3] ARM: LPAE: rework TTBR0/TTBR1 split

From: Konstantin Khlebnikov
Date: Tue Nov 18 2014 - 11:53:22 EST


This patch moves enabling TTBRx split from __v7_setup (v7_ttb_setup)
into cpu_init() which is called in init_mm context after leaving idmap.
Also it disables split in setup_mm_for_reboot() before switching mm to idmap.
After that idmap and VM split never meet, thus they no longer conflict.

Callback keystone_smp_secondary_initmem isn't required, all setup is
done in cpu_init() which is called right before smp_ops.smp_secondary_init.

Also this patch prepares code for enabling split in non-LPAE mode.

Signed-off-by: Konstantin Khlebnikov <k.khlebnikov@xxxxxxxxxxx>
---
arch/arm/include/asm/pgtable-2level-hwdef.h | 2 ++
arch/arm/include/asm/pgtable-3level-hwdef.h | 12 +++++-------
arch/arm/include/asm/proc-fns.h | 13 +++++++++++++
arch/arm/kernel/setup.c | 11 +++++++++++
arch/arm/mach-keystone/platsmp.c | 13 -------------
arch/arm/mm/idmap.c | 6 ++++++
arch/arm/mm/proc-v7-3level.S | 13 -------------
7 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/arch/arm/include/asm/pgtable-2level-hwdef.h b/arch/arm/include/asm/pgtable-2level-hwdef.h
index 5cfba15..c2ed1fa 100644
--- a/arch/arm/include/asm/pgtable-2level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-2level-hwdef.h
@@ -90,4 +90,6 @@

#define PHYS_MASK (~0UL)

+#define TTBR1_SIZE 0
+
#endif
diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
index 9fd61c7..8bb32a0 100644
--- a/arch/arm/include/asm/pgtable-3level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
@@ -89,19 +89,17 @@
* 0x40000000: T0SZ = 2, T1SZ = 0 (not used)
* 0x80000000: T0SZ = 0, T1SZ = 1
* 0xc0000000: T0SZ = 0, T1SZ = 2
- *
- * Only use this feature if PHYS_OFFSET <= PAGE_OFFSET, otherwise
- * booting secondary CPUs would end up using TTBR1 for the identity
- * mapping set up in TTBR0.
*/
#if defined CONFIG_VMSPLIT_2G
#define TTBR1_OFFSET 16 /* skip two L1 entries */
+#define TTBR1_SIZE (1<<16)
#elif defined CONFIG_VMSPLIT_3G
#define TTBR1_OFFSET (4096 * (1 + 3)) /* only L2, skip pgd + 3*pmd */
+#define TTBR1_SIZE (2<<16)
#else
-#define TTBR1_OFFSET 0
+#define TTBR1_OFFSET 8 /* skip one L1 entry */
+/* Not implemented. In this mode TTBR0 points to first pmd instead of pgd. */
+#define TTBR1_SIZE 0
#endif

-#define TTBR1_SIZE (((PAGE_OFFSET >> 30) - 1) << 16)
-
#endif
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index 5324c11..8353eb4 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -149,6 +149,19 @@ extern void cpu_resume(void);
})
#endif

+static inline u32 cpu_get_ttbcr(void)
+{
+ u32 val;
+
+ __asm__("mrc p15, 0, %0, c2, c0, 2" : "=r" (val));
+ return val;
+}
+
+static inline void cpu_set_ttbcr(u32 val)
+{
+ __asm__("mcr p15, 0, %0, c2, c0, 2" : : "r" (val));
+}
+
#else /*!CONFIG_MMU */

#define cpu_switch_mm(pgd,mm) { }
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index c031063..6a54a82 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -488,6 +488,17 @@ void notrace cpu_init(void)
PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
: "r14");
#endif
+
+#ifdef CONFIG_ARM_LPAE
+ /* For short mode TTBR1 already loaded by macro v7_ttb_setup */
+ cpu_set_ttbr(1, __pa(init_mm.pgd) + TTBR1_OFFSET);
+#endif
+
+#if defined(CONFIG_MMU) && TTBR1_SIZE
+ /* Enable TTBR0/TTBR1 split */
+ cpu_set_ttbcr(cpu_get_ttbcr() | TTBR1_SIZE);
+ local_flush_tlb_all();
+#endif
}

u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c
index 5f46a7c..4bbb184 100644
--- a/arch/arm/mach-keystone/platsmp.c
+++ b/arch/arm/mach-keystone/platsmp.c
@@ -39,19 +39,6 @@ static int keystone_smp_boot_secondary(unsigned int cpu,
return error;
}

-#ifdef CONFIG_ARM_LPAE
-static void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu)
-{
- pgd_t *pgd0 = pgd_offset_k(0);
- cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET);
- local_flush_tlb_all();
-}
-#else
-static inline void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu)
-{}
-#endif
-
struct smp_operations keystone_smp_ops __initdata = {
.smp_boot_secondary = keystone_smp_boot_secondary,
- .smp_secondary_init = keystone_smp_secondary_initmem,
};
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index e7a81ceb..cc51b40 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -123,6 +123,12 @@ void setup_mm_for_reboot(void)
{
/* Switch to the identity mapping. */
cpu_switch_mm(idmap_pgd, &init_mm);
+
+#if TTBR1_SIZE
+ /* Disable TTBR0/TTBR1 split, idmap might collide with TTRB1 range */
+ cpu_set_ttbcr(cpu_get_ttbcr() | ~TTBR1_SIZE);
+#endif
+
local_flush_bp_all();

#ifdef CONFIG_CPU_HAS_ASID
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index d3daed0..b8173cf 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -127,26 +127,13 @@ ENDPROC(cpu_v7_set_pte_ext)
* - \ttbr1 updated.
*/
.macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp
- ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address
- mov \tmp, \tmp, lsr #ARCH_PGD_SHIFT
- cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET?
mrc p15, 0, \tmp, c2, c0, 2 @ TTB control register
orr \tmp, \tmp, #TTB_EAE
ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP)
ALT_UP(orr \tmp, \tmp, #TTB_FLAGS_UP)
ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP << 16)
ALT_UP(orr \tmp, \tmp, #TTB_FLAGS_UP << 16)
- /*
- * Only use split TTBRs if PHYS_OFFSET <= PAGE_OFFSET (cmp above),
- * otherwise booting secondary CPUs would end up using TTBR1 for the
- * identity mapping set up in TTBR0.
- */
- orrls \tmp, \tmp, #TTBR1_SIZE @ TTBCR.T1SZ
mcr p15, 0, \tmp, c2, c0, 2 @ TTBCR
- mov \tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits
- mov \ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT @ lower bits
- addls \ttbr1, \ttbr1, #TTBR1_OFFSET
- mcrr p15, 1, \ttbr1, \tmp, c2 @ load TTBR1
mov \tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits
mov \ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT @ lower bits
mcrr p15, 0, \ttbr0, \tmp, c2 @ load TTBR0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/