Commit 4756dcbfd37819a8359d3c69a22be2ee41666d0f
Committed by
Will Deacon
1 parent
a7fbc0d62a
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
ARM: LPAE: accomodate >32-bit addresses for page table base
This patch redefines the early boot time use of the R4 register to steal a few low order bits (ARCH_PGD_SHIFT bits) on LPAE systems. This allows for up to 38-bit physical addresses. Signed-off-by: Cyril Chemparathy <cyril@ti.com> Signed-off-by: Vitaly Andrianov <vitalya@ti.com> Acked-by: Nicolas Pitre <nico@linaro.org> Tested-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Tested-by: Subash Patel <subash.rp@samsung.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Showing 4 changed files with 37 additions and 8 deletions Side-by-side Diff
arch/arm/include/asm/memory.h
... | ... | @@ -18,6 +18,8 @@ |
18 | 18 | #include <linux/types.h> |
19 | 19 | #include <linux/sizes.h> |
20 | 20 | |
21 | +#include <asm/cache.h> | |
22 | + | |
21 | 23 | #ifdef CONFIG_NEED_MACH_MEMORY_H |
22 | 24 | #include <mach/memory.h> |
23 | 25 | #endif |
... | ... | @@ -140,6 +142,20 @@ |
140 | 142 | */ |
141 | 143 | #define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) |
142 | 144 | #define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) |
145 | + | |
146 | +/* | |
147 | + * Minimum guaranted alignment in pgd_alloc(). The page table pointers passed | |
148 | + * around in head.S and proc-*.S are shifted by this amount, in order to | |
149 | + * leave spare high bits for systems with physical address extension. This | |
150 | + * does not fully accomodate the 40-bit addressing capability of ARM LPAE, but | |
151 | + * gives us about 38-bits or so. | |
152 | + */ | |
153 | +#ifdef CONFIG_ARM_LPAE | |
154 | +#define ARCH_PGD_SHIFT L1_CACHE_SHIFT | |
155 | +#else | |
156 | +#define ARCH_PGD_SHIFT 0 | |
157 | +#endif | |
158 | +#define ARCH_PGD_MASK ((1 << ARCH_PGD_SHIFT) - 1) | |
143 | 159 | |
144 | 160 | #ifndef __ASSEMBLY__ |
145 | 161 |
arch/arm/kernel/head.S
... | ... | @@ -156,7 +156,7 @@ |
156 | 156 | * |
157 | 157 | * Returns: |
158 | 158 | * r0, r3, r5-r7 corrupted |
159 | - * r4 = physical page table address | |
159 | + * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) | |
160 | 160 | */ |
161 | 161 | __create_page_tables: |
162 | 162 | pgtbl r4, r8 @ page table address |
... | ... | @@ -331,6 +331,7 @@ |
331 | 331 | #endif |
332 | 332 | #ifdef CONFIG_ARM_LPAE |
333 | 333 | sub r4, r4, #0x1000 @ point to the PGD table |
334 | + mov r4, r4, lsr #ARCH_PGD_SHIFT | |
334 | 335 | #endif |
335 | 336 | mov pc, lr |
336 | 337 | ENDPROC(__create_page_tables) |
... | ... | @@ -408,7 +409,7 @@ |
408 | 409 | * r0 = cp#15 control register |
409 | 410 | * r1 = machine ID |
410 | 411 | * r2 = atags or dtb pointer |
411 | - * r4 = page table pointer | |
412 | + * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) | |
412 | 413 | * r9 = processor ID |
413 | 414 | * r13 = *virtual* address to jump to upon completion |
414 | 415 | */ |
... | ... | @@ -427,10 +428,7 @@ |
427 | 428 | #ifdef CONFIG_CPU_ICACHE_DISABLE |
428 | 429 | bic r0, r0, #CR_I |
429 | 430 | #endif |
430 | -#ifdef CONFIG_ARM_LPAE | |
431 | - mov r5, #0 | |
432 | - mcrr p15, 0, r4, r5, c2 @ load TTBR0 | |
433 | -#else | |
431 | +#ifndef CONFIG_ARM_LPAE | |
434 | 432 | mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ |
435 | 433 | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ |
436 | 434 | domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ |
arch/arm/kernel/smp.c
... | ... | @@ -78,6 +78,13 @@ |
78 | 78 | smp_ops = *ops; |
79 | 79 | }; |
80 | 80 | |
81 | +static unsigned long get_arch_pgd(pgd_t *pgd) | |
82 | +{ | |
83 | + phys_addr_t pgdir = virt_to_phys(pgd); | |
84 | + BUG_ON(pgdir & ARCH_PGD_MASK); | |
85 | + return pgdir >> ARCH_PGD_SHIFT; | |
86 | +} | |
87 | + | |
81 | 88 | int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) |
82 | 89 | { |
83 | 90 | int ret; |
... | ... | @@ -87,8 +94,8 @@ |
87 | 94 | * its stack and the page tables. |
88 | 95 | */ |
89 | 96 | secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; |
90 | - secondary_data.pgdir = virt_to_phys(idmap_pgd); | |
91 | - secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir); | |
97 | + secondary_data.pgdir = get_arch_pgd(idmap_pgd); | |
98 | + secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir); | |
92 | 99 | __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data)); |
93 | 100 | outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1)); |
94 | 101 |
arch/arm/mm/proc-v7-3level.S
... | ... | @@ -114,6 +114,7 @@ |
114 | 114 | */ |
115 | 115 | .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp |
116 | 116 | ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address |
117 | + mov \tmp, \tmp, lsr #ARCH_PGD_SHIFT | |
117 | 118 | cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET? |
118 | 119 | mrc p15, 0, \tmp, c2, c0, 2 @ TTB control register |
119 | 120 | orr \tmp, \tmp, #TTB_EAE |
120 | 121 | |
... | ... | @@ -128,8 +129,15 @@ |
128 | 129 | */ |
129 | 130 | orrls \tmp, \tmp, #TTBR1_SIZE @ TTBCR.T1SZ |
130 | 131 | mcr p15, 0, \tmp, c2, c0, 2 @ TTBCR |
132 | + mov \tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits | |
133 | + mov \ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT @ lower bits | |
131 | 134 | addls \ttbr1, \ttbr1, #TTBR1_OFFSET |
132 | 135 | mcrr p15, 1, \ttbr1, \zero, c2 @ load TTBR1 |
136 | + mov \tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits | |
137 | + mov \ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT @ lower bits | |
138 | + mcrr p15, 0, \ttbr0, \zero, c2 @ load TTBR0 | |
139 | + mcrr p15, 1, \ttbr1, \zero, c2 @ load TTBR1 | |
140 | + mcrr p15, 0, \ttbr0, \zero, c2 @ load TTBR0 | |
133 | 141 | .endm |
134 | 142 | |
135 | 143 | __CPUINIT |