aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/include/asm
diff options
context:
space:
mode:
authorJungseok Lee <jays.lee@samsung.com>2014-05-12 05:40:51 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2014-07-23 10:27:40 -0400
commitc79b954bf6c006f2d3dd9d01f231abeead13a410 (patch)
treeb7d4375c12d2b61554af0e5eb7596b22c60c643e /arch/arm64/include/asm
parent57e0139041a978c0cfa4d2366c96ea3418e7d553 (diff)
arm64: mm: Implement 4 levels of translation tables
This patch implements 4 levels of translation tables since 3 levels of page tables with 4KB pages cannot support 40-bit physical address space described in [1] due to the following issue. It is a restriction that kernel logical memory map with 4KB + 3 levels (0xffffffc000000000-0xffffffffffffffff) cannot cover RAM region from 544GB to 1024GB in [1]. Specifically, ARM64 kernel fails to create mapping for this region in map_mem function since __phys_to_virt for this region reaches to address overflow. If SoC design follows the document, [1], over 32GB RAM would be placed from 544GB. Even 64GB system is supposed to use the region from 544GB to 576GB for only 32GB RAM. Naturally, it would reach to enable 4 levels of page tables to avoid hacking __virt_to_phys and __phys_to_virt. However, it is recommended 4 levels of page table should be only enabled if memory map is too sparse or there is about 512GB RAM. References ---------- [1]: Principles of ARM Memory Maps, White Paper, Issue C Signed-off-by: Jungseok Lee <jays.lee@samsung.com> Reviewed-by: Sungjinn Chung <sungjinn.chung@samsung.com> Acked-by: Kukjin Kim <kgene.kim@samsung.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Reviewed-by: Steve Capper <steve.capper@linaro.org> [catalin.marinas@arm.com: MEMBLOCK_INITIAL_LIMIT removed, same as PUD_SIZE] [catalin.marinas@arm.com: early_ioremap_init() updated for 4 levels] [catalin.marinas@arm.com: 48-bit VA depends on BROKEN until KVM is fixed] Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Tested-by: Jungseok Lee <jungseoklee85@gmail.com>
Diffstat (limited to 'arch/arm64/include/asm')
-rw-r--r--arch/arm64/include/asm/page.h13
-rw-r--r--arch/arm64/include/asm/pgalloc.h20
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h6
-rw-r--r--arch/arm64/include/asm/pgtable.h40
-rw-r--r--arch/arm64/include/asm/tlb.h9
5 files changed, 83 insertions, 5 deletions
diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
index 1cbde2773c4f..cf9afa0366b6 100644
--- a/arch/arm64/include/asm/page.h
+++ b/arch/arm64/include/asm/page.h
@@ -33,19 +33,26 @@
33 33
34/* 34/*
35 * The idmap and swapper page tables need some space reserved in the kernel 35 * The idmap and swapper page tables need some space reserved in the kernel
36 * image. Both require a pgd and a next level table to (section) map the 36 * image. Both require pgd, pud (4 levels only) and pmd tables to (section)
37 * kernel. The the swapper also maps the FDT (see __create_page_tables for 37 * map the kernel. The swapper also maps the FDT (see __create_page_tables for
38 * more information). 38 * more information).
39 */ 39 */
40#ifdef CONFIG_ARM64_4_LEVELS
41#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE)
42#define IDMAP_DIR_SIZE (3 * PAGE_SIZE)
43#else
40#define SWAPPER_DIR_SIZE (2 * PAGE_SIZE) 44#define SWAPPER_DIR_SIZE (2 * PAGE_SIZE)
41#define IDMAP_DIR_SIZE (2 * PAGE_SIZE) 45#define IDMAP_DIR_SIZE (2 * PAGE_SIZE)
46#endif
42 47
43#ifndef __ASSEMBLY__ 48#ifndef __ASSEMBLY__
44 49
45#ifdef CONFIG_ARM64_2_LEVELS 50#ifdef CONFIG_ARM64_2_LEVELS
46#include <asm/pgtable-2level-types.h> 51#include <asm/pgtable-2level-types.h>
47#else 52#elif defined(CONFIG_ARM64_3_LEVELS)
48#include <asm/pgtable-3level-types.h> 53#include <asm/pgtable-3level-types.h>
54#else
55#include <asm/pgtable-4level-types.h>
49#endif 56#endif
50 57
51extern void __cpu_clear_user_page(void *p, unsigned long user); 58extern void __cpu_clear_user_page(void *p, unsigned long user);
diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
index 48298376e46a..7deb5750a945 100644
--- a/arch/arm64/include/asm/pgalloc.h
+++ b/arch/arm64/include/asm/pgalloc.h
@@ -46,6 +46,26 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
46 46
47#endif /* CONFIG_ARM64_2_LEVELS */ 47#endif /* CONFIG_ARM64_2_LEVELS */
48 48
49#ifdef CONFIG_ARM64_4_LEVELS
50
51static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
52{
53 return (pud_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
54}
55
56static inline void pud_free(struct mm_struct *mm, pud_t *pud)
57{
58 BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
59 free_page((unsigned long)pud);
60}
61
62static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
63{
64 set_pgd(pgd, __pgd(__pa(pud) | PUD_TYPE_TABLE));
65}
66
67#endif /* CONFIG_ARM64_4_LEVELS */
68
49extern pgd_t *pgd_alloc(struct mm_struct *mm); 69extern pgd_t *pgd_alloc(struct mm_struct *mm);
50extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); 70extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
51 71
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index c7c603b489b8..fddcc3efa569 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -18,8 +18,10 @@
18 18
19#ifdef CONFIG_ARM64_2_LEVELS 19#ifdef CONFIG_ARM64_2_LEVELS
20#include <asm/pgtable-2level-hwdef.h> 20#include <asm/pgtable-2level-hwdef.h>
21#else 21#elif defined(CONFIG_ARM64_3_LEVELS)
22#include <asm/pgtable-3level-hwdef.h> 22#include <asm/pgtable-3level-hwdef.h>
23#else
24#include <asm/pgtable-4level-hwdef.h>
23#endif 25#endif
24 26
25/* 27/*
@@ -27,7 +29,7 @@
27 * 29 *
28 * Level 1 descriptor (PUD). 30 * Level 1 descriptor (PUD).
29 */ 31 */
30 32#define PUD_TYPE_TABLE (_AT(pudval_t, 3) << 0)
31#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1) 33#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1)
32#define PUD_TYPE_MASK (_AT(pgdval_t, 3) << 0) 34#define PUD_TYPE_MASK (_AT(pgdval_t, 3) << 0)
33#define PUD_TYPE_SECT (_AT(pgdval_t, 1) << 0) 35#define PUD_TYPE_SECT (_AT(pgdval_t, 1) << 0)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 6d5854972a77..d9b23efdaded 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -35,7 +35,11 @@
35 * VMALLOC and SPARSEMEM_VMEMMAP ranges. 35 * VMALLOC and SPARSEMEM_VMEMMAP ranges.
36 */ 36 */
37#define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS) 37#define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS)
38#ifndef CONFIG_ARM64_4_LEVELS
38#define VMALLOC_END (PAGE_OFFSET - UL(0x400000000) - SZ_64K) 39#define VMALLOC_END (PAGE_OFFSET - UL(0x400000000) - SZ_64K)
40#else
41#define VMALLOC_END (PAGE_OFFSET - UL(0x40000000000) - SZ_64K)
42#endif
39 43
40#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) 44#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K))
41 45
@@ -44,12 +48,16 @@
44#ifndef __ASSEMBLY__ 48#ifndef __ASSEMBLY__
45extern void __pte_error(const char *file, int line, unsigned long val); 49extern void __pte_error(const char *file, int line, unsigned long val);
46extern void __pmd_error(const char *file, int line, unsigned long val); 50extern void __pmd_error(const char *file, int line, unsigned long val);
51extern void __pud_error(const char *file, int line, unsigned long val);
47extern void __pgd_error(const char *file, int line, unsigned long val); 52extern void __pgd_error(const char *file, int line, unsigned long val);
48 53
49#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) 54#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
50#ifndef CONFIG_ARM64_2_LEVELS 55#ifndef CONFIG_ARM64_2_LEVELS
51#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd)) 56#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
52#endif 57#endif
58#ifdef CONFIG_ARM64_4_LEVELS
59#define pud_ERROR(pud) __pud_error(__FILE__, __LINE__, pud_val(pud))
60#endif
53#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) 61#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
54 62
55#ifdef CONFIG_SMP 63#ifdef CONFIG_SMP
@@ -347,6 +355,30 @@ static inline pmd_t *pud_page_vaddr(pud_t pud)
347 355
348#endif /* CONFIG_ARM64_2_LEVELS */ 356#endif /* CONFIG_ARM64_2_LEVELS */
349 357
358#ifdef CONFIG_ARM64_4_LEVELS
359
360#define pgd_none(pgd) (!pgd_val(pgd))
361#define pgd_bad(pgd) (!(pgd_val(pgd) & 2))
362#define pgd_present(pgd) (pgd_val(pgd))
363
364static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
365{
366 *pgdp = pgd;
367 dsb(ishst);
368}
369
370static inline void pgd_clear(pgd_t *pgdp)
371{
372 set_pgd(pgdp, __pgd(0));
373}
374
375static inline pud_t *pgd_page_vaddr(pgd_t pgd)
376{
377 return __va(pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK);
378}
379
380#endif /* CONFIG_ARM64_4_LEVELS */
381
350/* to find an entry in a page-table-directory */ 382/* to find an entry in a page-table-directory */
351#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) 383#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
352 384
@@ -355,6 +387,14 @@ static inline pmd_t *pud_page_vaddr(pud_t pud)
355/* to find an entry in a kernel page-table-directory */ 387/* to find an entry in a kernel page-table-directory */
356#define pgd_offset_k(addr) pgd_offset(&init_mm, addr) 388#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
357 389
390#ifdef CONFIG_ARM64_4_LEVELS
391#define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
392static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
393{
394 return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr);
395}
396#endif
397
358/* Find an entry in the second-level page table.. */ 398/* Find an entry in the second-level page table.. */
359#ifndef CONFIG_ARM64_2_LEVELS 399#ifndef CONFIG_ARM64_2_LEVELS
360#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) 400#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index bc19101edaeb..49dc8f03362f 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -100,6 +100,15 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
100} 100}
101#endif 101#endif
102 102
103#ifdef CONFIG_ARM64_4_LEVELS
104static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp,
105 unsigned long addr)
106{
107 tlb_add_flush(tlb, addr);
108 tlb_remove_page(tlb, virt_to_page(pudp));
109}
110#endif
111
103static inline void __tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, 112static inline void __tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp,
104 unsigned long address) 113 unsigned long address)
105{ 114{