diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-10-15 09:12:24 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-10-18 14:16:01 -0400 |
commit | 8754c4bf2ac1a64d5c1409a0ae98e21a8f3541c5 (patch) | |
tree | 2a579c5437b1cbf2af86a891bcc2368608983b69 /arch/arm | |
parent | 75c912a367fbdc07f0ef6f5384acd5028beb225e (diff) | |
parent | a77e0c7b2774fd52ce6bf25c2c3ffdccb7b110ff (diff) |
Merge branch 'for-rmk/arm-mm-lpae' of git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone into devel-stable
This series extends the existing ARM v2p runtime patching for 64 bit.
Needed for LPAE machines which have physical memory beyond 4GB.
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/include/asm/mach/arch.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/memory.h | 75 | ||||
-rw-r--r-- | arch/arm/kernel/armksyms.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 63 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 2 | ||||
-rw-r--r-- | arch/arm/mm/idmap.c | 8 | ||||
-rw-r--r-- | arch/arm/mm/mmu.c | 82 |
8 files changed, 206 insertions, 30 deletions
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 402a2bc6aa68..17a3fa2979e8 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h | |||
@@ -49,6 +49,7 @@ struct machine_desc { | |||
49 | bool (*smp_init)(void); | 49 | bool (*smp_init)(void); |
50 | void (*fixup)(struct tag *, char **, | 50 | void (*fixup)(struct tag *, char **, |
51 | struct meminfo *); | 51 | struct meminfo *); |
52 | void (*init_meminfo)(void); | ||
52 | void (*reserve)(void);/* reserve mem blocks */ | 53 | void (*reserve)(void);/* reserve mem blocks */ |
53 | void (*map_io)(void);/* IO mapping function */ | 54 | void (*map_io)(void);/* IO mapping function */ |
54 | void (*init_early)(void); | 55 | void (*init_early)(void); |
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index e750a938fd3c..6748d6295a1a 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h | |||
@@ -172,8 +172,14 @@ | |||
172 | * so that all we need to do is modify the 8-bit constant field. | 172 | * so that all we need to do is modify the 8-bit constant field. |
173 | */ | 173 | */ |
174 | #define __PV_BITS_31_24 0x81000000 | 174 | #define __PV_BITS_31_24 0x81000000 |
175 | #define __PV_BITS_7_0 0x81 | ||
176 | |||
177 | extern phys_addr_t (*arch_virt_to_idmap) (unsigned long x); | ||
178 | extern u64 __pv_phys_offset; | ||
179 | extern u64 __pv_offset; | ||
180 | extern void fixup_pv_table(const void *, unsigned long); | ||
181 | extern const void *__pv_table_begin, *__pv_table_end; | ||
175 | 182 | ||
176 | extern unsigned long __pv_phys_offset; | ||
177 | #define PHYS_OFFSET __pv_phys_offset | 183 | #define PHYS_OFFSET __pv_phys_offset |
178 | 184 | ||
179 | #define __pv_stub(from,to,instr,type) \ | 185 | #define __pv_stub(from,to,instr,type) \ |
@@ -185,22 +191,58 @@ extern unsigned long __pv_phys_offset; | |||
185 | : "=r" (to) \ | 191 | : "=r" (to) \ |
186 | : "r" (from), "I" (type)) | 192 | : "r" (from), "I" (type)) |
187 | 193 | ||
188 | static inline unsigned long __virt_to_phys(unsigned long x) | 194 | #define __pv_stub_mov_hi(t) \ |
195 | __asm__ volatile("@ __pv_stub_mov\n" \ | ||
196 | "1: mov %R0, %1\n" \ | ||
197 | " .pushsection .pv_table,\"a\"\n" \ | ||
198 | " .long 1b\n" \ | ||
199 | " .popsection\n" \ | ||
200 | : "=r" (t) \ | ||
201 | : "I" (__PV_BITS_7_0)) | ||
202 | |||
203 | #define __pv_add_carry_stub(x, y) \ | ||
204 | __asm__ volatile("@ __pv_add_carry_stub\n" \ | ||
205 | "1: adds %Q0, %1, %2\n" \ | ||
206 | " adc %R0, %R0, #0\n" \ | ||
207 | " .pushsection .pv_table,\"a\"\n" \ | ||
208 | " .long 1b\n" \ | ||
209 | " .popsection\n" \ | ||
210 | : "+r" (y) \ | ||
211 | : "r" (x), "I" (__PV_BITS_31_24) \ | ||
212 | : "cc") | ||
213 | |||
214 | static inline phys_addr_t __virt_to_phys(unsigned long x) | ||
189 | { | 215 | { |
190 | unsigned long t; | 216 | phys_addr_t t; |
191 | __pv_stub(x, t, "add", __PV_BITS_31_24); | 217 | |
218 | if (sizeof(phys_addr_t) == 4) { | ||
219 | __pv_stub(x, t, "add", __PV_BITS_31_24); | ||
220 | } else { | ||
221 | __pv_stub_mov_hi(t); | ||
222 | __pv_add_carry_stub(x, t); | ||
223 | } | ||
192 | return t; | 224 | return t; |
193 | } | 225 | } |
194 | 226 | ||
195 | static inline unsigned long __phys_to_virt(unsigned long x) | 227 | static inline unsigned long __phys_to_virt(phys_addr_t x) |
196 | { | 228 | { |
197 | unsigned long t; | 229 | unsigned long t; |
198 | __pv_stub(x, t, "sub", __PV_BITS_31_24); | 230 | __pv_stub(x, t, "sub", __PV_BITS_31_24); |
199 | return t; | 231 | return t; |
200 | } | 232 | } |
233 | |||
201 | #else | 234 | #else |
202 | #define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) | 235 | |
203 | #define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) | 236 | static inline phys_addr_t __virt_to_phys(unsigned long x) |
237 | { | ||
238 | return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET; | ||
239 | } | ||
240 | |||
241 | static inline unsigned long __phys_to_virt(phys_addr_t x) | ||
242 | { | ||
243 | return x - PHYS_OFFSET + PAGE_OFFSET; | ||
244 | } | ||
245 | |||
204 | #endif | 246 | #endif |
205 | #endif | 247 | #endif |
206 | #endif /* __ASSEMBLY__ */ | 248 | #endif /* __ASSEMBLY__ */ |
@@ -238,17 +280,32 @@ static inline phys_addr_t virt_to_phys(const volatile void *x) | |||
238 | 280 | ||
239 | static inline void *phys_to_virt(phys_addr_t x) | 281 | static inline void *phys_to_virt(phys_addr_t x) |
240 | { | 282 | { |
241 | return (void *)(__phys_to_virt((unsigned long)(x))); | 283 | return (void *)__phys_to_virt(x); |
242 | } | 284 | } |
243 | 285 | ||
244 | /* | 286 | /* |
245 | * Drivers should NOT use these either. | 287 | * Drivers should NOT use these either. |
246 | */ | 288 | */ |
247 | #define __pa(x) __virt_to_phys((unsigned long)(x)) | 289 | #define __pa(x) __virt_to_phys((unsigned long)(x)) |
248 | #define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) | 290 | #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) |
249 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) | 291 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) |
250 | 292 | ||
251 | /* | 293 | /* |
294 | * These are for systems that have a hardware interconnect supported alias of | ||
295 | * physical memory for idmap purposes. Most cases should leave these | ||
296 | * untouched. | ||
297 | */ | ||
298 | static inline phys_addr_t __virt_to_idmap(unsigned long x) | ||
299 | { | ||
300 | if (arch_virt_to_idmap) | ||
301 | return arch_virt_to_idmap(x); | ||
302 | else | ||
303 | return __virt_to_phys(x); | ||
304 | } | ||
305 | |||
306 | #define virt_to_idmap(x) __virt_to_idmap((unsigned long)(x)) | ||
307 | |||
308 | /* | ||
252 | * Virtual <-> DMA view memory address translations | 309 | * Virtual <-> DMA view memory address translations |
253 | * Again, these are *only* valid on the kernel direct mapped RAM | 310 | * Again, these are *only* valid on the kernel direct mapped RAM |
254 | * memory. Use of these is *deprecated* (and that doesn't mean | 311 | * memory. Use of these is *deprecated* (and that doesn't mean |
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 60d3b738d420..1f031ddd0667 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c | |||
@@ -155,4 +155,5 @@ EXPORT_SYMBOL(__gnu_mcount_nc); | |||
155 | 155 | ||
156 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | 156 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT |
157 | EXPORT_SYMBOL(__pv_phys_offset); | 157 | EXPORT_SYMBOL(__pv_phys_offset); |
158 | EXPORT_SYMBOL(__pv_offset); | ||
158 | #endif | 159 | #endif |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 2c7cc1e03473..54547947a4e9 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -536,6 +536,14 @@ ENTRY(fixup_smp) | |||
536 | ldmfd sp!, {r4 - r6, pc} | 536 | ldmfd sp!, {r4 - r6, pc} |
537 | ENDPROC(fixup_smp) | 537 | ENDPROC(fixup_smp) |
538 | 538 | ||
539 | #ifdef __ARMEB_ | ||
540 | #define LOW_OFFSET 0x4 | ||
541 | #define HIGH_OFFSET 0x0 | ||
542 | #else | ||
543 | #define LOW_OFFSET 0x0 | ||
544 | #define HIGH_OFFSET 0x4 | ||
545 | #endif | ||
546 | |||
539 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | 547 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT |
540 | 548 | ||
541 | /* __fixup_pv_table - patch the stub instructions with the delta between | 549 | /* __fixup_pv_table - patch the stub instructions with the delta between |
@@ -546,17 +554,20 @@ ENDPROC(fixup_smp) | |||
546 | __HEAD | 554 | __HEAD |
547 | __fixup_pv_table: | 555 | __fixup_pv_table: |
548 | adr r0, 1f | 556 | adr r0, 1f |
549 | ldmia r0, {r3-r5, r7} | 557 | ldmia r0, {r3-r7} |
550 | sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET | 558 | mvn ip, #0 |
559 | subs r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET | ||
551 | add r4, r4, r3 @ adjust table start address | 560 | add r4, r4, r3 @ adjust table start address |
552 | add r5, r5, r3 @ adjust table end address | 561 | add r5, r5, r3 @ adjust table end address |
553 | add r7, r7, r3 @ adjust __pv_phys_offset address | 562 | add r6, r6, r3 @ adjust __pv_phys_offset address |
554 | str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset | 563 | add r7, r7, r3 @ adjust __pv_offset address |
564 | str r8, [r6, #LOW_OFFSET] @ save computed PHYS_OFFSET to __pv_phys_offset | ||
565 | strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits | ||
555 | mov r6, r3, lsr #24 @ constant for add/sub instructions | 566 | mov r6, r3, lsr #24 @ constant for add/sub instructions |
556 | teq r3, r6, lsl #24 @ must be 16MiB aligned | 567 | teq r3, r6, lsl #24 @ must be 16MiB aligned |
557 | THUMB( it ne @ cross section branch ) | 568 | THUMB( it ne @ cross section branch ) |
558 | bne __error | 569 | bne __error |
559 | str r6, [r7, #4] @ save to __pv_offset | 570 | str r3, [r7, #LOW_OFFSET] @ save to __pv_offset low bits |
560 | b __fixup_a_pv_table | 571 | b __fixup_a_pv_table |
561 | ENDPROC(__fixup_pv_table) | 572 | ENDPROC(__fixup_pv_table) |
562 | 573 | ||
@@ -565,10 +576,19 @@ ENDPROC(__fixup_pv_table) | |||
565 | .long __pv_table_begin | 576 | .long __pv_table_begin |
566 | .long __pv_table_end | 577 | .long __pv_table_end |
567 | 2: .long __pv_phys_offset | 578 | 2: .long __pv_phys_offset |
579 | .long __pv_offset | ||
568 | 580 | ||
569 | .text | 581 | .text |
570 | __fixup_a_pv_table: | 582 | __fixup_a_pv_table: |
583 | adr r0, 3f | ||
584 | ldr r6, [r0] | ||
585 | add r6, r6, r3 | ||
586 | ldr r0, [r6, #HIGH_OFFSET] @ pv_offset high word | ||
587 | ldr r6, [r6, #LOW_OFFSET] @ pv_offset low word | ||
588 | mov r6, r6, lsr #24 | ||
589 | cmn r0, #1 | ||
571 | #ifdef CONFIG_THUMB2_KERNEL | 590 | #ifdef CONFIG_THUMB2_KERNEL |
591 | moveq r0, #0x200000 @ set bit 21, mov to mvn instruction | ||
572 | lsls r6, #24 | 592 | lsls r6, #24 |
573 | beq 2f | 593 | beq 2f |
574 | clz r7, r6 | 594 | clz r7, r6 |
@@ -582,18 +602,28 @@ __fixup_a_pv_table: | |||
582 | b 2f | 602 | b 2f |
583 | 1: add r7, r3 | 603 | 1: add r7, r3 |
584 | ldrh ip, [r7, #2] | 604 | ldrh ip, [r7, #2] |
585 | and ip, 0x8f00 | 605 | tst ip, #0x4000 |
586 | orr ip, r6 @ mask in offset bits 31-24 | 606 | and ip, #0x8f00 |
607 | orrne ip, r6 @ mask in offset bits 31-24 | ||
608 | orreq ip, r0 @ mask in offset bits 7-0 | ||
587 | strh ip, [r7, #2] | 609 | strh ip, [r7, #2] |
610 | ldrheq ip, [r7] | ||
611 | biceq ip, #0x20 | ||
612 | orreq ip, ip, r0, lsr #16 | ||
613 | strheq ip, [r7] | ||
588 | 2: cmp r4, r5 | 614 | 2: cmp r4, r5 |
589 | ldrcc r7, [r4], #4 @ use branch for delay slot | 615 | ldrcc r7, [r4], #4 @ use branch for delay slot |
590 | bcc 1b | 616 | bcc 1b |
591 | bx lr | 617 | bx lr |
592 | #else | 618 | #else |
619 | moveq r0, #0x400000 @ set bit 22, mov to mvn instruction | ||
593 | b 2f | 620 | b 2f |
594 | 1: ldr ip, [r7, r3] | 621 | 1: ldr ip, [r7, r3] |
595 | bic ip, ip, #0x000000ff | 622 | bic ip, ip, #0x000000ff |
596 | orr ip, ip, r6 @ mask in offset bits 31-24 | 623 | tst ip, #0xf00 @ check the rotation field |
624 | orrne ip, ip, r6 @ mask in offset bits 31-24 | ||
625 | biceq ip, ip, #0x400000 @ clear bit 22 | ||
626 | orreq ip, ip, r0 @ mask in offset bits 7-0 | ||
597 | str ip, [r7, r3] | 627 | str ip, [r7, r3] |
598 | 2: cmp r4, r5 | 628 | 2: cmp r4, r5 |
599 | ldrcc r7, [r4], #4 @ use branch for delay slot | 629 | ldrcc r7, [r4], #4 @ use branch for delay slot |
@@ -602,28 +632,29 @@ __fixup_a_pv_table: | |||
602 | #endif | 632 | #endif |
603 | ENDPROC(__fixup_a_pv_table) | 633 | ENDPROC(__fixup_a_pv_table) |
604 | 634 | ||
635 | 3: .long __pv_offset | ||
636 | |||
605 | ENTRY(fixup_pv_table) | 637 | ENTRY(fixup_pv_table) |
606 | stmfd sp!, {r4 - r7, lr} | 638 | stmfd sp!, {r4 - r7, lr} |
607 | ldr r2, 2f @ get address of __pv_phys_offset | ||
608 | mov r3, #0 @ no offset | 639 | mov r3, #0 @ no offset |
609 | mov r4, r0 @ r0 = table start | 640 | mov r4, r0 @ r0 = table start |
610 | add r5, r0, r1 @ r1 = table size | 641 | add r5, r0, r1 @ r1 = table size |
611 | ldr r6, [r2, #4] @ get __pv_offset | ||
612 | bl __fixup_a_pv_table | 642 | bl __fixup_a_pv_table |
613 | ldmfd sp!, {r4 - r7, pc} | 643 | ldmfd sp!, {r4 - r7, pc} |
614 | ENDPROC(fixup_pv_table) | 644 | ENDPROC(fixup_pv_table) |
615 | 645 | ||
616 | .align | ||
617 | 2: .long __pv_phys_offset | ||
618 | |||
619 | .data | 646 | .data |
620 | .globl __pv_phys_offset | 647 | .globl __pv_phys_offset |
621 | .type __pv_phys_offset, %object | 648 | .type __pv_phys_offset, %object |
622 | __pv_phys_offset: | 649 | __pv_phys_offset: |
623 | .long 0 | 650 | .quad 0 |
624 | .size __pv_phys_offset, . - __pv_phys_offset | 651 | .size __pv_phys_offset, . -__pv_phys_offset |
652 | |||
653 | .globl __pv_offset | ||
654 | .type __pv_offset, %object | ||
625 | __pv_offset: | 655 | __pv_offset: |
626 | .long 0 | 656 | .quad 0 |
657 | .size __pv_offset, . -__pv_offset | ||
627 | #endif | 658 | #endif |
628 | 659 | ||
629 | #include "head-common.S" | 660 | #include "head-common.S" |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 0e1e2b3afa45..af7b7db4699e 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -73,6 +73,8 @@ __setup("fpe=", fpe_setup); | |||
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | extern void paging_init(const struct machine_desc *desc); | 75 | extern void paging_init(const struct machine_desc *desc); |
76 | extern void early_paging_init(const struct machine_desc *, | ||
77 | struct proc_info_list *); | ||
76 | extern void sanity_check_meminfo(void); | 78 | extern void sanity_check_meminfo(void); |
77 | extern enum reboot_mode reboot_mode; | 79 | extern enum reboot_mode reboot_mode; |
78 | extern void setup_dma_zone(const struct machine_desc *desc); | 80 | extern void setup_dma_zone(const struct machine_desc *desc); |
@@ -878,6 +880,8 @@ void __init setup_arch(char **cmdline_p) | |||
878 | parse_early_param(); | 880 | parse_early_param(); |
879 | 881 | ||
880 | sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); | 882 | sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); |
883 | |||
884 | early_paging_init(mdesc, lookup_processor_type(read_cpuid_id())); | ||
881 | sanity_check_meminfo(); | 885 | sanity_check_meminfo(); |
882 | arm_memblock_init(&meminfo, mdesc); | 886 | arm_memblock_init(&meminfo, mdesc); |
883 | 887 | ||
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 7d80a549cae5..5c820cbcf918 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -81,7 +81,7 @@ void __init smp_set_ops(struct smp_operations *ops) | |||
81 | 81 | ||
82 | static unsigned long get_arch_pgd(pgd_t *pgd) | 82 | static unsigned long get_arch_pgd(pgd_t *pgd) |
83 | { | 83 | { |
84 | phys_addr_t pgdir = virt_to_phys(pgd); | 84 | phys_addr_t pgdir = virt_to_idmap(pgd); |
85 | BUG_ON(pgdir & ARCH_PGD_MASK); | 85 | BUG_ON(pgdir & ARCH_PGD_MASK); |
86 | return pgdir >> ARCH_PGD_SHIFT; | 86 | return pgdir >> ARCH_PGD_SHIFT; |
87 | } | 87 | } |
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index 83cb3ac27095..8e0e52eb76b5 100644 --- a/arch/arm/mm/idmap.c +++ b/arch/arm/mm/idmap.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <asm/system_info.h> | 10 | #include <asm/system_info.h> |
11 | 11 | ||
12 | pgd_t *idmap_pgd; | 12 | pgd_t *idmap_pgd; |
13 | phys_addr_t (*arch_virt_to_idmap) (unsigned long x); | ||
13 | 14 | ||
14 | #ifdef CONFIG_ARM_LPAE | 15 | #ifdef CONFIG_ARM_LPAE |
15 | static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end, | 16 | static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end, |
@@ -67,8 +68,9 @@ static void identity_mapping_add(pgd_t *pgd, const char *text_start, | |||
67 | unsigned long addr, end; | 68 | unsigned long addr, end; |
68 | unsigned long next; | 69 | unsigned long next; |
69 | 70 | ||
70 | addr = virt_to_phys(text_start); | 71 | addr = virt_to_idmap(text_start); |
71 | end = virt_to_phys(text_end); | 72 | end = virt_to_idmap(text_end); |
73 | pr_info("Setting up static identity map for 0x%lx - 0x%lx\n", addr, end); | ||
72 | 74 | ||
73 | prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; | 75 | prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; |
74 | 76 | ||
@@ -90,8 +92,6 @@ static int __init init_static_idmap(void) | |||
90 | if (!idmap_pgd) | 92 | if (!idmap_pgd) |
91 | return -ENOMEM; | 93 | return -ENOMEM; |
92 | 94 | ||
93 | pr_info("Setting up static identity map for 0x%p - 0x%p\n", | ||
94 | __idmap_text_start, __idmap_text_end); | ||
95 | identity_mapping_add(idmap_pgd, __idmap_text_start, | 95 | identity_mapping_add(idmap_pgd, __idmap_text_start, |
96 | __idmap_text_end, 0); | 96 | __idmap_text_end, 0); |
97 | 97 | ||
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index b1d17eeb59b8..78eeeca78f5a 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <asm/highmem.h> | 28 | #include <asm/highmem.h> |
29 | #include <asm/system_info.h> | 29 | #include <asm/system_info.h> |
30 | #include <asm/traps.h> | 30 | #include <asm/traps.h> |
31 | #include <asm/procinfo.h> | ||
32 | #include <asm/memory.h> | ||
31 | 33 | ||
32 | #include <asm/mach/arch.h> | 34 | #include <asm/mach/arch.h> |
33 | #include <asm/mach/map.h> | 35 | #include <asm/mach/map.h> |
@@ -1315,6 +1317,86 @@ static void __init map_lowmem(void) | |||
1315 | } | 1317 | } |
1316 | } | 1318 | } |
1317 | 1319 | ||
1320 | #ifdef CONFIG_ARM_LPAE | ||
1321 | /* | ||
1322 | * early_paging_init() recreates boot time page table setup, allowing machines | ||
1323 | * to switch over to a high (>4G) address space on LPAE systems | ||
1324 | */ | ||
1325 | void __init early_paging_init(const struct machine_desc *mdesc, | ||
1326 | struct proc_info_list *procinfo) | ||
1327 | { | ||
1328 | pmdval_t pmdprot = procinfo->__cpu_mm_mmu_flags; | ||
1329 | unsigned long map_start, map_end; | ||
1330 | pgd_t *pgd0, *pgdk; | ||
1331 | pud_t *pud0, *pudk, *pud_start; | ||
1332 | pmd_t *pmd0, *pmdk; | ||
1333 | phys_addr_t phys; | ||
1334 | int i; | ||
1335 | |||
1336 | if (!(mdesc->init_meminfo)) | ||
1337 | return; | ||
1338 | |||
1339 | /* remap kernel code and data */ | ||
1340 | map_start = init_mm.start_code; | ||
1341 | map_end = init_mm.brk; | ||
1342 | |||
1343 | /* get a handle on things... */ | ||
1344 | pgd0 = pgd_offset_k(0); | ||
1345 | pud_start = pud0 = pud_offset(pgd0, 0); | ||
1346 | pmd0 = pmd_offset(pud0, 0); | ||
1347 | |||
1348 | pgdk = pgd_offset_k(map_start); | ||
1349 | pudk = pud_offset(pgdk, map_start); | ||
1350 | pmdk = pmd_offset(pudk, map_start); | ||
1351 | |||
1352 | mdesc->init_meminfo(); | ||
1353 | |||
1354 | /* Run the patch stub to update the constants */ | ||
1355 | fixup_pv_table(&__pv_table_begin, | ||
1356 | (&__pv_table_end - &__pv_table_begin) << 2); | ||
1357 | |||
1358 | /* | ||
1359 | * Cache cleaning operations for self-modifying code | ||
1360 | * We should clean the entries by MVA but running a | ||
1361 | * for loop over every pv_table entry pointer would | ||
1362 | * just complicate the code. | ||
1363 | */ | ||
1364 | flush_cache_louis(); | ||
1365 | dsb(); | ||
1366 | isb(); | ||
1367 | |||
1368 | /* remap level 1 table */ | ||
1369 | for (i = 0; i < PTRS_PER_PGD; pud0++, i++) { | ||
1370 | set_pud(pud0, | ||
1371 | __pud(__pa(pmd0) | PMD_TYPE_TABLE | L_PGD_SWAPPER)); | ||
1372 | pmd0 += PTRS_PER_PMD; | ||
1373 | } | ||
1374 | |||
1375 | /* remap pmds for kernel mapping */ | ||
1376 | phys = __pa(map_start) & PMD_MASK; | ||
1377 | do { | ||
1378 | *pmdk++ = __pmd(phys | pmdprot); | ||
1379 | phys += PMD_SIZE; | ||
1380 | } while (phys < map_end); | ||
1381 | |||
1382 | flush_cache_all(); | ||
1383 | cpu_switch_mm(pgd0, &init_mm); | ||
1384 | cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET); | ||
1385 | local_flush_bp_all(); | ||
1386 | local_flush_tlb_all(); | ||
1387 | } | ||
1388 | |||
1389 | #else | ||
1390 | |||
1391 | void __init early_paging_init(const struct machine_desc *mdesc, | ||
1392 | struct proc_info_list *procinfo) | ||
1393 | { | ||
1394 | if (mdesc->init_meminfo) | ||
1395 | mdesc->init_meminfo(); | ||
1396 | } | ||
1397 | |||
1398 | #endif | ||
1399 | |||
1318 | /* | 1400 | /* |
1319 | * paging_init() sets up the page tables, initialises the zone memory | 1401 | * paging_init() sets up the page tables, initialises the zone memory |
1320 | * maps, and sets up the zero page, bad page and bad page tables. | 1402 | * maps, and sets up the zero page, bad page and bad page tables. |