Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: redo TTBR setup code for LPAE

Re-engineer the LPAE TTBR setup code. Rather than passing some shifted
address in order to fit in a CPU register, pass either a full physical
address (in the case of r4, r5 for TTBR0) or a PFN (for TTBR1).

This removes the ARCH_PGD_SHIFT hack, and the last dangerous user of
cpu_set_ttbr() in the secondary CPU startup code path (which was there
to re-set TTBR1 to the appropriate high physical address space on
Keystone2.)

Tested-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

+60 -78
-16
arch/arm/include/asm/memory.h
··· 18 18 #include <linux/types.h> 19 19 #include <linux/sizes.h> 20 20 21 - #include <asm/cache.h> 22 - 23 21 #ifdef CONFIG_NEED_MACH_MEMORY_H 24 22 #include <mach/memory.h> 25 23 #endif ··· 129 131 */ 130 132 #define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) 131 133 #define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) 132 - 133 - /* 134 - * Minimum guaranted alignment in pgd_alloc(). The page table pointers passed 135 - * around in head.S and proc-*.S are shifted by this amount, in order to 136 - * leave spare high bits for systems with physical address extension. This 137 - * does not fully accomodate the 40-bit addressing capability of ARM LPAE, but 138 - * gives us about 38-bits or so. 139 - */ 140 - #ifdef CONFIG_ARM_LPAE 141 - #define ARCH_PGD_SHIFT L1_CACHE_SHIFT 142 - #else 143 - #define ARCH_PGD_SHIFT 0 144 - #endif 145 - #define ARCH_PGD_MASK ((1 << ARCH_PGD_SHIFT) - 1) 146 134 147 135 /* 148 136 * PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical
-7
arch/arm/include/asm/proc-fns.h
··· 125 125 ttbr; \ 126 126 }) 127 127 128 - #define cpu_set_ttbr(nr, val) \ 129 - do { \ 130 - u64 ttbr = val; \ 131 - __asm__("mcrr p15, " #nr ", %Q0, %R0, c2" \ 132 - : : "r" (ttbr)); \ 133 - } while (0) 134 - 135 128 #define cpu_get_pgd() \ 136 129 ({ \ 137 130 u64 pg = cpu_get_ttbr(0); \
+1 -1
arch/arm/include/asm/smp.h
··· 61 61 struct secondary_data { 62 62 union { 63 63 unsigned long mpu_rgn_szr; 64 - unsigned long pgdir; 64 + u64 pgdir; 65 65 }; 66 66 unsigned long swapper_pg_dir; 67 67 void *stack;
+1 -1
arch/arm/kernel/head-nommu.S
··· 123 123 ENDPROC(secondary_startup) 124 124 125 125 ENTRY(__secondary_switched) 126 - ldr sp, [r7, #8] @ set up the stack pointer 126 + ldr sp, [r7, #12] @ set up the stack pointer 127 127 mov fp, #0 128 128 b secondary_start_kernel 129 129 ENDPROC(__secondary_switched)
+31 -11
arch/arm/kernel/head.S
··· 131 131 * The following calls CPU specific code in a position independent 132 132 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of 133 133 * xxx_proc_info structure selected by __lookup_processor_type 134 - * above. On return, the CPU will be ready for the MMU to be 135 - * turned on, and r0 will hold the CPU control register value. 134 + * above. 135 + * 136 + * The processor init function will be called with: 137 + * r1 - machine type 138 + * r2 - boot data (atags/dt) pointer 139 + * r4 - translation table base (low word) 140 + * r5 - translation table base (high word, if LPAE) 141 + * r8 - translation table base 1 (pfn if LPAE) 142 + * r9 - cpuid 143 + * r13 - virtual address for __enable_mmu -> __turn_mmu_on 144 + * 145 + * On return, the CPU will be ready for the MMU to be turned on, 146 + * r0 will hold the CPU control register value, r1, r2, r4, and 147 + * r9 will be preserved. r5 will also be preserved if LPAE. 136 148 */ 137 149 ldr r13, =__mmap_switched @ address to jump to after 138 150 @ mmu has been enabled 139 151 adr lr, BSYM(1f) @ return (PIC) address 152 + #ifdef CONFIG_ARM_LPAE 153 + mov r5, #0 @ high TTBR0 154 + mov r8, r4, lsr #12 @ TTBR1 is swapper_pg_dir pfn 155 + #else 140 156 mov r8, r4 @ set TTBR1 to swapper_pg_dir 157 + #endif 141 158 ldr r12, [r10, #PROCINFO_INITFUNC] 142 159 add r12, r12, r10 143 160 ret r12 ··· 175 158 * 176 159 * Returns: 177 160 * r0, r3, r5-r7 corrupted 178 - * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) 161 + * r4 = physical page table address 179 162 */ 180 163 __create_page_tables: 181 164 pgtbl r4, r8 @ page table address ··· 350 333 #endif 351 334 #ifdef CONFIG_ARM_LPAE 352 335 sub r4, r4, #0x1000 @ point to the PGD table 353 - mov r4, r4, lsr #ARCH_PGD_SHIFT 354 336 #endif 355 337 ret lr 356 338 ENDPROC(__create_page_tables) ··· 397 381 adr r4, __secondary_data 398 382 ldmia r4, {r5, r7, r12} @ address to jump to after 399 383 sub lr, r4, r5 @ mmu has been enabled 400 - ldr r4, [r7, lr] @ get secondary_data.pgdir 401 - add r7, r7, #4 402 - ldr r8, [r7, lr] @ get secondary_data.swapper_pg_dir 384 + add r3, r7, lr 385 + ldrd r4, [r3, #0] @ get secondary_data.pgdir 386 + ldr r8, [r3, #8] @ get secondary_data.swapper_pg_dir 403 387 adr lr, BSYM(__enable_mmu) @ return address 404 388 mov r13, r12 @ __secondary_switched address 405 389 ldr r12, [r10, #PROCINFO_INITFUNC] ··· 413 397 * r6 = &secondary_data 414 398 */ 415 399 ENTRY(__secondary_switched) 416 - ldr sp, [r7, #4] @ get secondary_data.stack 400 + ldr sp, [r7, #12] @ get secondary_data.stack 417 401 mov fp, #0 418 402 b secondary_start_kernel 419 403 ENDPROC(__secondary_switched) ··· 432 416 /* 433 417 * Setup common bits before finally enabling the MMU. Essentially 434 418 * this is just loading the page table pointer and domain access 435 - * registers. 419 + * registers. All these registers need to be preserved by the 420 + * processor setup function (or set in the case of r0) 436 421 * 437 422 * r0 = cp#15 control register 438 423 * r1 = machine ID 439 424 * r2 = atags or dtb pointer 440 - * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) 425 + * r4 = TTBR pointer (low word) 426 + * r5 = TTBR pointer (high word if LPAE) 441 427 * r9 = processor ID 442 428 * r13 = *virtual* address to jump to upon completion 443 429 */ ··· 458 440 #ifdef CONFIG_CPU_ICACHE_DISABLE 459 441 bic r0, r0, #CR_I 460 442 #endif 461 - #ifndef CONFIG_ARM_LPAE 443 + #ifdef CONFIG_ARM_LPAE 444 + mcrr p15, 0, r4, r5, c2 @ load TTBR0 445 + #else 462 446 mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ 463 447 domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ 464 448 domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
+6 -4
arch/arm/kernel/smp.c
··· 86 86 87 87 static unsigned long get_arch_pgd(pgd_t *pgd) 88 88 { 89 - phys_addr_t pgdir = virt_to_idmap(pgd); 90 - BUG_ON(pgdir & ARCH_PGD_MASK); 91 - return pgdir >> ARCH_PGD_SHIFT; 89 + #ifdef CONFIG_ARM_LPAE 90 + return __phys_to_pfn(virt_to_phys(pgd)); 91 + #else 92 + return virt_to_phys(pgd); 93 + #endif 92 94 } 93 95 94 96 int __cpu_up(unsigned int cpu, struct task_struct *idle) ··· 110 108 #endif 111 109 112 110 #ifdef CONFIG_MMU 113 - secondary_data.pgdir = get_arch_pgd(idmap_pgd); 111 + secondary_data.pgdir = virt_to_phys(idmap_pgd); 114 112 secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir); 115 113 #endif 116 114 sync_cache_w(&secondary_data);
-13
arch/arm/mach-keystone/platsmp.c
··· 39 39 return error; 40 40 } 41 41 42 - #ifdef CONFIG_ARM_LPAE 43 - static void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) 44 - { 45 - pgd_t *pgd0 = pgd_offset_k(0); 46 - cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET); 47 - local_flush_tlb_all(); 48 - } 49 - #else 50 - static inline void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) 51 - {} 52 - #endif 53 - 54 42 struct smp_operations keystone_smp_ops __initdata = { 55 43 .smp_boot_secondary = keystone_smp_boot_secondary, 56 - .smp_secondary_init = keystone_smp_secondary_initmem, 57 44 };
+3 -3
arch/arm/mm/proc-v7-2level.S
··· 148 148 * Macro for setting up the TTBRx and TTBCR registers. 149 149 * - \ttb0 and \ttb1 updated with the corresponding flags. 150 150 */ 151 - .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp 151 + .macro v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp 152 152 mcr p15, 0, \zero, c2, c0, 2 @ TTB control register 153 - ALT_SMP(orr \ttbr0, \ttbr0, #TTB_FLAGS_SMP) 154 - ALT_UP(orr \ttbr0, \ttbr0, #TTB_FLAGS_UP) 153 + ALT_SMP(orr \ttbr0l, \ttbr0l, #TTB_FLAGS_SMP) 154 + ALT_UP(orr \ttbr0l, \ttbr0l, #TTB_FLAGS_UP) 155 155 ALT_SMP(orr \ttbr1, \ttbr1, #TTB_FLAGS_SMP) 156 156 ALT_UP(orr \ttbr1, \ttbr1, #TTB_FLAGS_UP) 157 157 mcr p15, 0, \ttbr1, c2, c0, 1 @ load TTB1
+5 -9
arch/arm/mm/proc-v7-3level.S
··· 126 126 * Macro for setting up the TTBRx and TTBCR registers. 127 127 * - \ttbr1 updated. 128 128 */ 129 - .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp 129 + .macro v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp 130 130 ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address 131 - mov \tmp, \tmp, lsr #ARCH_PGD_SHIFT 132 - cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET? 133 - mrc p15, 0, \tmp, c2, c0, 2 @ TTB control register 131 + cmp \ttbr1, \tmp, lsr #12 @ PHYS_OFFSET > PAGE_OFFSET? 132 + mrc p15, 0, \tmp, c2, c0, 2 @ TTB control egister 134 133 orr \tmp, \tmp, #TTB_EAE 135 134 ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP) 136 135 ALT_UP(orr \tmp, \tmp, #TTB_FLAGS_UP) ··· 142 143 */ 143 144 orrls \tmp, \tmp, #TTBR1_SIZE @ TTBCR.T1SZ 144 145 mcr p15, 0, \tmp, c2, c0, 2 @ TTBCR 145 - mov \tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits 146 - mov \ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT @ lower bits 146 + mov \tmp, \ttbr1, lsr #20 147 + mov \ttbr1, \ttbr1, lsl #12 147 148 addls \ttbr1, \ttbr1, #TTBR1_OFFSET 148 149 mcrr p15, 1, \ttbr1, \tmp, c2 @ load TTBR1 149 - mov \tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits 150 - mov \ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT @ lower bits 151 - mcrr p15, 0, \ttbr0, \tmp, c2 @ load TTBR0 152 150 .endm 153 151 154 152 /*
+13 -13
arch/arm/mm/proc-v7.S
··· 343 343 and r10, r0, #0xff000000 @ ARM? 344 344 teq r10, #0x41000000 345 345 bne 3f 346 - and r5, r0, #0x00f00000 @ variant 346 + and r3, r0, #0x00f00000 @ variant 347 347 and r6, r0, #0x0000000f @ revision 348 - orr r6, r6, r5, lsr #20-4 @ combine variant and revision 348 + orr r6, r6, r3, lsr #20-4 @ combine variant and revision 349 349 ubfx r0, r0, #4, #12 @ primary part number 350 350 351 351 /* Cortex-A8 Errata */ ··· 354 354 bne 2f 355 355 #if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM) 356 356 357 - teq r5, #0x00100000 @ only present in r1p* 357 + teq r3, #0x00100000 @ only present in r1p* 358 358 mrceq p15, 0, r10, c1, c0, 1 @ read aux control register 359 359 orreq r10, r10, #(1 << 6) @ set IBE to 1 360 360 mcreq p15, 0, r10, c1, c0, 1 @ write aux control register ··· 395 395 mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register 396 396 #endif 397 397 #ifdef CONFIG_ARM_ERRATA_743622 398 - teq r5, #0x00200000 @ only present in r2p* 398 + teq r3, #0x00200000 @ only present in r2p* 399 399 mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register 400 400 orreq r10, r10, #1 << 6 @ set bit #6 401 401 mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register ··· 425 425 mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate 426 426 #ifdef CONFIG_MMU 427 427 mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs 428 - v7_ttb_setup r10, r4, r8, r5 @ TTBCR, TTBRx setup 429 - ldr r5, =PRRR @ PRRR 428 + v7_ttb_setup r10, r4, r5, r8, r3 @ TTBCR, TTBRx setup 429 + ldr r3, =PRRR @ PRRR 430 430 ldr r6, =NMRR @ NMRR 431 - mcr p15, 0, r5, c10, c2, 0 @ write PRRR 431 + mcr p15, 0, r3, c10, c2, 0 @ write PRRR 432 432 mcr p15, 0, r6, c10, c2, 1 @ write NMRR 433 433 #endif 434 434 dsb @ Complete invalidations ··· 437 437 and r0, r0, #(0xf << 12) @ ThumbEE enabled field 438 438 teq r0, #(1 << 12) @ check if ThumbEE is present 439 439 bne 1f 440 - mov r5, #0 441 - mcr p14, 6, r5, c1, c0, 0 @ Initialize TEEHBR to 0 440 + mov r3, #0 441 + mcr p14, 6, r3, c1, c0, 0 @ Initialize TEEHBR to 0 442 442 mrc p14, 6, r0, c0, c0, 0 @ load TEECR 443 443 orr r0, r0, #1 @ set the 1st bit in order to 444 444 mcr p14, 6, r0, c0, c0, 0 @ stop userspace TEEHBR access 445 445 1: 446 446 #endif 447 - adr r5, v7_crval 448 - ldmia r5, {r5, r6} 447 + adr r3, v7_crval 448 + ldmia r3, {r3, r6} 449 449 ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables 450 450 #ifdef CONFIG_SWP_EMULATE 451 - orr r5, r5, #(1 << 10) @ set SW bit in "clear" 451 + orr r3, r3, #(1 << 10) @ set SW bit in "clear" 452 452 bic r6, r6, #(1 << 10) @ clear it in "mmuset" 453 453 #endif 454 454 mrc p15, 0, r0, c1, c0, 0 @ read control register 455 - bic r0, r0, r5 @ clear bits them 455 + bic r0, r0, r3 @ clear bits them 456 456 orr r0, r0, r6 @ set them 457 457 THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions 458 458 ret lr @ return to head.S:__ret