aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2009-12-04 16:52:36 -0500
committerRalf Baechle <ralf@linux-mips.org>2010-02-27 06:53:03 -0500
commit325f8a0a31df567dbafafc48f8e60f3c1f101a46 (patch)
treeb36383f4d483ecc6d057cdd41ef50b6403e89b9c
parentef6c1fd662d18c0e2ed92825c8837e94b5ec3a1f (diff)
MIPS: Two-level pagetables for 64-bit kernels with 64KB pages.
For 64-bit kernels with 64KB pages and two level page tables, there are 42 bits worth of virtual address space This is larger than the 40 bits of virtual address space obtained with the default 4KB Page size and three levels, so there are no draw backs for using two level tables with this configuration. Signed-off-by: David Daney <ddaney@caviumnetworks.com> Cc: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/761/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/include/asm/page.h12
-rw-r--r--arch/mips/include/asm/pgalloc.h4
-rw-r--r--arch/mips/include/asm/pgtable-64.h36
-rw-r--r--arch/mips/include/asm/pgtable.h2
-rw-r--r--arch/mips/kernel/asm-offsets.c4
-rw-r--r--arch/mips/mm/init.c2
-rw-r--r--arch/mips/mm/pgtable-64.c44
-rw-r--r--arch/mips/mm/tlbex.c2
8 files changed, 71 insertions, 35 deletions
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index f266295cce51..ac32572430f4 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -107,18 +107,6 @@ typedef struct { unsigned long pte; } pte_t;
107typedef struct page *pgtable_t; 107typedef struct page *pgtable_t;
108 108
109/* 109/*
110 * For 3-level pagetables we defines these ourselves, for 2-level the
111 * definitions are supplied by <asm-generic/pgtable-nopmd.h>.
112 */
113#ifdef CONFIG_64BIT
114
115typedef struct { unsigned long pmd; } pmd_t;
116#define pmd_val(x) ((x).pmd)
117#define __pmd(x) ((pmd_t) { (x) } )
118
119#endif
120
121/*
122 * Right now we don't support 4-level pagetables, so all pud-related 110 * Right now we don't support 4-level pagetables, so all pud-related
123 * definitions come from <asm-generic/pgtable-nopud.h>. 111 * definitions come from <asm-generic/pgtable-nopud.h>.
124 */ 112 */
diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h
index 3738f4b48cbd..881d18b4e298 100644
--- a/arch/mips/include/asm/pgalloc.h
+++ b/arch/mips/include/asm/pgalloc.h
@@ -31,7 +31,7 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
31 */ 31 */
32extern void pmd_init(unsigned long page, unsigned long pagetable); 32extern void pmd_init(unsigned long page, unsigned long pagetable);
33 33
34#ifdef CONFIG_64BIT 34#ifndef __PAGETABLE_PMD_FOLDED
35 35
36static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) 36static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
37{ 37{
@@ -104,7 +104,7 @@ do { \
104 tlb_remove_page((tlb), pte); \ 104 tlb_remove_page((tlb), pte); \
105} while (0) 105} while (0)
106 106
107#ifdef CONFIG_64BIT 107#ifndef __PAGETABLE_PMD_FOLDED
108 108
109static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) 109static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
110{ 110{
diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h
index 8eda30b467da..24314d21a708 100644
--- a/arch/mips/include/asm/pgtable-64.h
+++ b/arch/mips/include/asm/pgtable-64.h
@@ -16,7 +16,11 @@
16#include <asm/cachectl.h> 16#include <asm/cachectl.h>
17#include <asm/fixmap.h> 17#include <asm/fixmap.h>
18 18
19#ifdef CONFIG_PAGE_SIZE_64KB
20#include <asm-generic/pgtable-nopmd.h>
21#else
19#include <asm-generic/pgtable-nopud.h> 22#include <asm-generic/pgtable-nopud.h>
23#endif
20 24
21/* 25/*
22 * Each address space has 2 4K pages as its page directory, giving 1024 26 * Each address space has 2 4K pages as its page directory, giving 1024
@@ -37,13 +41,20 @@
37 * fault address - VMALLOC_START. 41 * fault address - VMALLOC_START.
38 */ 42 */
39 43
44
45/* PGDIR_SHIFT determines what a third-level page table entry can map */
46#ifdef __PAGETABLE_PMD_FOLDED
47#define PGDIR_SHIFT (PAGE_SHIFT + PAGE_SHIFT + PTE_ORDER - 3)
48#else
49
40/* PMD_SHIFT determines the size of the area a second-level page table can map */ 50/* PMD_SHIFT determines the size of the area a second-level page table can map */
41#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT + PTE_ORDER - 3)) 51#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT + PTE_ORDER - 3))
42#define PMD_SIZE (1UL << PMD_SHIFT) 52#define PMD_SIZE (1UL << PMD_SHIFT)
43#define PMD_MASK (~(PMD_SIZE-1)) 53#define PMD_MASK (~(PMD_SIZE-1))
44 54
45/* PGDIR_SHIFT determines what a third-level page table entry can map */ 55
46#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3)) 56#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3))
57#endif
47#define PGDIR_SIZE (1UL << PGDIR_SHIFT) 58#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
48#define PGDIR_MASK (~(PGDIR_SIZE-1)) 59#define PGDIR_MASK (~(PGDIR_SIZE-1))
49 60
@@ -92,12 +103,14 @@
92#ifdef CONFIG_PAGE_SIZE_64KB 103#ifdef CONFIG_PAGE_SIZE_64KB
93#define PGD_ORDER 0 104#define PGD_ORDER 0
94#define PUD_ORDER aieeee_attempt_to_allocate_pud 105#define PUD_ORDER aieeee_attempt_to_allocate_pud
95#define PMD_ORDER 0 106#define PMD_ORDER aieeee_attempt_to_allocate_pmd
96#define PTE_ORDER 0 107#define PTE_ORDER 0
97#endif 108#endif
98 109
99#define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t)) 110#define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t))
111#ifndef __PAGETABLE_PMD_FOLDED
100#define PTRS_PER_PMD ((PAGE_SIZE << PMD_ORDER) / sizeof(pmd_t)) 112#define PTRS_PER_PMD ((PAGE_SIZE << PMD_ORDER) / sizeof(pmd_t))
113#endif
101#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t)) 114#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
102 115
103#if PGDIR_SIZE >= TASK_SIZE 116#if PGDIR_SIZE >= TASK_SIZE
@@ -122,15 +135,30 @@
122 135
123#define pte_ERROR(e) \ 136#define pte_ERROR(e) \
124 printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) 137 printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
138#ifndef __PAGETABLE_PMD_FOLDED
125#define pmd_ERROR(e) \ 139#define pmd_ERROR(e) \
126 printk("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) 140 printk("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e))
141#endif
127#define pgd_ERROR(e) \ 142#define pgd_ERROR(e) \
128 printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) 143 printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e))
129 144
130extern pte_t invalid_pte_table[PTRS_PER_PTE]; 145extern pte_t invalid_pte_table[PTRS_PER_PTE];
131extern pte_t empty_bad_page_table[PTRS_PER_PTE]; 146extern pte_t empty_bad_page_table[PTRS_PER_PTE];
147
148
149#ifndef __PAGETABLE_PMD_FOLDED
150/*
151 * For 3-level pagetables we defines these ourselves, for 2-level the
152 * definitions are supplied by <asm-generic/pgtable-nopmd.h>.
153 */
154typedef struct { unsigned long pmd; } pmd_t;
155#define pmd_val(x) ((x).pmd)
156#define __pmd(x) ((pmd_t) { (x) } )
157
158
132extern pmd_t invalid_pmd_table[PTRS_PER_PMD]; 159extern pmd_t invalid_pmd_table[PTRS_PER_PMD];
133extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; 160extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD];
161#endif
134 162
135/* 163/*
136 * Empty pgd/pmd entries point to the invalid_pte_table. 164 * Empty pgd/pmd entries point to the invalid_pte_table.
@@ -151,6 +179,7 @@ static inline void pmd_clear(pmd_t *pmdp)
151{ 179{
152 pmd_val(*pmdp) = ((unsigned long) invalid_pte_table); 180 pmd_val(*pmdp) = ((unsigned long) invalid_pte_table);
153} 181}
182#ifndef __PAGETABLE_PMD_FOLDED
154 183
155/* 184/*
156 * Empty pud entries point to the invalid_pmd_table. 185 * Empty pud entries point to the invalid_pmd_table.
@@ -174,6 +203,7 @@ static inline void pud_clear(pud_t *pudp)
174{ 203{
175 pud_val(*pudp) = ((unsigned long) invalid_pmd_table); 204 pud_val(*pudp) = ((unsigned long) invalid_pmd_table);
176} 205}
206#endif
177 207
178#define pte_page(x) pfn_to_page(pte_pfn(x)) 208#define pte_page(x) pfn_to_page(pte_pfn(x))
179 209
@@ -198,6 +228,7 @@ static inline void pud_clear(pud_t *pudp)
198/* to find an entry in a page-table-directory */ 228/* to find an entry in a page-table-directory */
199#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr)) 229#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
200 230
231#ifndef __PAGETABLE_PMD_FOLDED
201static inline unsigned long pud_page_vaddr(pud_t pud) 232static inline unsigned long pud_page_vaddr(pud_t pud)
202{ 233{
203 return pud_val(pud); 234 return pud_val(pud);
@@ -210,6 +241,7 @@ static inline pmd_t *pmd_offset(pud_t * pud, unsigned long address)
210{ 241{
211 return (pmd_t *) pud_page_vaddr(*pud) + pmd_index(address); 242 return (pmd_t *) pud_page_vaddr(*pud) + pmd_index(address);
212} 243}
244#endif
213 245
214/* Find an entry in the third-level page table.. */ 246/* Find an entry in the third-level page table.. */
215#define __pte_offset(address) \ 247#define __pte_offset(address) \
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 1854336e56a2..02335fda9e77 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -177,7 +177,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
177 */ 177 */
178#define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while(0) 178#define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while(0)
179 179
180#ifdef CONFIG_64BIT 180#ifndef __PAGETABLE_PMD_FOLDED
181/* 181/*
182 * (puds are folded into pgds so this doesn't get actually called, 182 * (puds are folded into pgds so this doesn't get actually called,
183 * but the define is needed for a generic inline function.) 183 * but the define is needed for a generic inline function.)
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 2c1e1d02338b..ca6c83218caa 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -188,11 +188,15 @@ void output_mm_defines(void)
188 DEFINE(_PTE_T_SIZE, sizeof(pte_t)); 188 DEFINE(_PTE_T_SIZE, sizeof(pte_t));
189 BLANK(); 189 BLANK();
190 DEFINE(_PGD_T_LOG2, PGD_T_LOG2); 190 DEFINE(_PGD_T_LOG2, PGD_T_LOG2);
191#ifndef __PAGETABLE_PMD_FOLDED
191 DEFINE(_PMD_T_LOG2, PMD_T_LOG2); 192 DEFINE(_PMD_T_LOG2, PMD_T_LOG2);
193#endif
192 DEFINE(_PTE_T_LOG2, PTE_T_LOG2); 194 DEFINE(_PTE_T_LOG2, PTE_T_LOG2);
193 BLANK(); 195 BLANK();
194 DEFINE(_PGD_ORDER, PGD_ORDER); 196 DEFINE(_PGD_ORDER, PGD_ORDER);
197#ifndef __PAGETABLE_PMD_FOLDED
195 DEFINE(_PMD_ORDER, PMD_ORDER); 198 DEFINE(_PMD_ORDER, PMD_ORDER);
199#endif
196 DEFINE(_PTE_ORDER, PTE_ORDER); 200 DEFINE(_PTE_ORDER, PTE_ORDER);
197 BLANK(); 201 BLANK();
198 DEFINE(_PMD_SHIFT, PMD_SHIFT); 202 DEFINE(_PMD_SHIFT, PMD_SHIFT);
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 1651942f7feb..3c5b7de10af5 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -477,7 +477,7 @@ unsigned long pgd_current[NR_CPUS];
477 * will officially be retired. 477 * will officially be retired.
478 */ 478 */
479pgd_t swapper_pg_dir[_PTRS_PER_PGD] __page_aligned(_PGD_ORDER); 479pgd_t swapper_pg_dir[_PTRS_PER_PGD] __page_aligned(_PGD_ORDER);
480#ifdef CONFIG_64BIT 480#ifndef __PAGETABLE_PMD_FOLDED
481pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER); 481pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER);
482#endif 482#endif
483pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER); 483pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
diff --git a/arch/mips/mm/pgtable-64.c b/arch/mips/mm/pgtable-64.c
index 1121019fa456..78eaa4f0b0ec 100644
--- a/arch/mips/mm/pgtable-64.c
+++ b/arch/mips/mm/pgtable-64.c
@@ -15,23 +15,31 @@
15void pgd_init(unsigned long page) 15void pgd_init(unsigned long page)
16{ 16{
17 unsigned long *p, *end; 17 unsigned long *p, *end;
18 unsigned long entry;
19
20#ifdef __PAGETABLE_PMD_FOLDED
21 entry = (unsigned long)invalid_pte_table;
22#else
23 entry = (unsigned long)invalid_pmd_table;
24#endif
18 25
19 p = (unsigned long *) page; 26 p = (unsigned long *) page;
20 end = p + PTRS_PER_PGD; 27 end = p + PTRS_PER_PGD;
21 28
22 while (p < end) { 29 while (p < end) {
23 p[0] = (unsigned long) invalid_pmd_table; 30 p[0] = entry;
24 p[1] = (unsigned long) invalid_pmd_table; 31 p[1] = entry;
25 p[2] = (unsigned long) invalid_pmd_table; 32 p[2] = entry;
26 p[3] = (unsigned long) invalid_pmd_table; 33 p[3] = entry;
27 p[4] = (unsigned long) invalid_pmd_table; 34 p[4] = entry;
28 p[5] = (unsigned long) invalid_pmd_table; 35 p[5] = entry;
29 p[6] = (unsigned long) invalid_pmd_table; 36 p[6] = entry;
30 p[7] = (unsigned long) invalid_pmd_table; 37 p[7] = entry;
31 p += 8; 38 p += 8;
32 } 39 }
33} 40}
34 41
42#ifndef __PAGETABLE_PMD_FOLDED
35void pmd_init(unsigned long addr, unsigned long pagetable) 43void pmd_init(unsigned long addr, unsigned long pagetable)
36{ 44{
37 unsigned long *p, *end; 45 unsigned long *p, *end;
@@ -40,17 +48,18 @@ void pmd_init(unsigned long addr, unsigned long pagetable)
40 end = p + PTRS_PER_PMD; 48 end = p + PTRS_PER_PMD;
41 49
42 while (p < end) { 50 while (p < end) {
43 p[0] = (unsigned long)pagetable; 51 p[0] = pagetable;
44 p[1] = (unsigned long)pagetable; 52 p[1] = pagetable;
45 p[2] = (unsigned long)pagetable; 53 p[2] = pagetable;
46 p[3] = (unsigned long)pagetable; 54 p[3] = pagetable;
47 p[4] = (unsigned long)pagetable; 55 p[4] = pagetable;
48 p[5] = (unsigned long)pagetable; 56 p[5] = pagetable;
49 p[6] = (unsigned long)pagetable; 57 p[6] = pagetable;
50 p[7] = (unsigned long)pagetable; 58 p[7] = pagetable;
51 p += 8; 59 p += 8;
52 } 60 }
53} 61}
62#endif
54 63
55void __init pagetable_init(void) 64void __init pagetable_init(void)
56{ 65{
@@ -59,8 +68,9 @@ void __init pagetable_init(void)
59 68
60 /* Initialize the entire pgd. */ 69 /* Initialize the entire pgd. */
61 pgd_init((unsigned long)swapper_pg_dir); 70 pgd_init((unsigned long)swapper_pg_dir);
71#ifndef __PAGETABLE_PMD_FOLDED
62 pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); 72 pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
63 73#endif
64 pgd_base = swapper_pg_dir; 74 pgd_base = swapper_pg_dir;
65 /* 75 /*
66 * Fixed mappings: 76 * Fixed mappings:
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index badcf5e8d695..eae45f0f9a16 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -549,11 +549,13 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
549 549
550 uasm_i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3); 550 uasm_i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
551 uasm_i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */ 551 uasm_i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
552#ifndef __PAGETABLE_PMD_FOLDED
552 uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */ 553 uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
553 uasm_i_ld(p, ptr, 0, ptr); /* get pmd pointer */ 554 uasm_i_ld(p, ptr, 0, ptr); /* get pmd pointer */
554 uasm_i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */ 555 uasm_i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
555 uasm_i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3); 556 uasm_i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
556 uasm_i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */ 557 uasm_i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
558#endif
557} 559}
558 560
559/* 561/*