aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-11-15 19:16:01 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-12-22 06:05:32 -0500
commitd30e45eeabefadc6039d7f876a59e5f5f6cb11c6 (patch)
tree9873141aac1042fe8b230aa525599135f5411e36 /arch/arm
parentf6e3354d02aa1f30672e3671098c12cb49c7da25 (diff)
ARM: pgtable: switch order of Linux vs hardware page tables
This switches the ordering of the Linux vs hardware page tables in each page, thereby eliminating some of the arithmetic in the page table walks. As we now place the Linux page table at the beginning of the page, we can deal with the offset in the pgt by simply masking it away, along with the other control bits. This also makes the arithmetic all be positive, rather than a mixture. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/include/asm/pgalloc.h39
-rw-r--r--arch/arm/include/asm/pgtable.h31
-rw-r--r--arch/arm/mm/fault.c2
-rw-r--r--arch/arm/mm/proc-macros.S10
-rw-r--r--arch/arm/mm/proc-v7.S8
5 files changed, 41 insertions, 49 deletions
diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h
index 1f1064b519c0..9763be04f77e 100644
--- a/arch/arm/include/asm/pgalloc.h
+++ b/arch/arm/include/asm/pgalloc.h
@@ -35,6 +35,11 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
35 35
36#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) 36#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
37 37
38static inline void clean_pte_table(pte_t *pte)
39{
40 clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
41}
42
38/* 43/*
39 * Allocate one PTE table. 44 * Allocate one PTE table.
40 * 45 *
@@ -42,14 +47,14 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
42 * into one table thus: 47 * into one table thus:
43 * 48 *
44 * +------------+ 49 * +------------+
45 * | h/w pt 0 |
46 * +------------+
47 * | h/w pt 1 |
48 * +------------+
49 * | Linux pt 0 | 50 * | Linux pt 0 |
50 * +------------+ 51 * +------------+
51 * | Linux pt 1 | 52 * | Linux pt 1 |
52 * +------------+ 53 * +------------+
54 * | h/w pt 0 |
55 * +------------+
56 * | h/w pt 1 |
57 * +------------+
53 */ 58 */
54static inline pte_t * 59static inline pte_t *
55pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) 60pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
@@ -57,10 +62,8 @@ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
57 pte_t *pte; 62 pte_t *pte;
58 63
59 pte = (pte_t *)__get_free_page(PGALLOC_GFP); 64 pte = (pte_t *)__get_free_page(PGALLOC_GFP);
60 if (pte) { 65 if (pte)
61 clean_dcache_area(pte, sizeof(pte_t) * PTRS_PER_PTE); 66 clean_pte_table(pte);
62 pte += PTRS_PER_PTE;
63 }
64 67
65 return pte; 68 return pte;
66} 69}
@@ -76,10 +79,8 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
76 pte = alloc_pages(PGALLOC_GFP, 0); 79 pte = alloc_pages(PGALLOC_GFP, 0);
77#endif 80#endif
78 if (pte) { 81 if (pte) {
79 if (!PageHighMem(pte)) { 82 if (!PageHighMem(pte))
80 void *page = page_address(pte); 83 clean_pte_table(page_address(pte));
81 clean_dcache_area(page, sizeof(pte_t) * PTRS_PER_PTE);
82 }
83 pgtable_page_ctor(pte); 84 pgtable_page_ctor(pte);
84 } 85 }
85 86
@@ -91,10 +92,8 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
91 */ 92 */
92static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) 93static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
93{ 94{
94 if (pte) { 95 if (pte)
95 pte -= PTRS_PER_PTE;
96 free_page((unsigned long)pte); 96 free_page((unsigned long)pte);
97 }
98} 97}
99 98
100static inline void pte_free(struct mm_struct *mm, pgtable_t pte) 99static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
@@ -106,7 +105,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
106static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, 105static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
107 unsigned long prot) 106 unsigned long prot)
108{ 107{
109 unsigned long pmdval = pte | prot; 108 unsigned long pmdval = (pte + PTE_HWTABLE_OFF) | prot;
110 pmdp[0] = __pmd(pmdval); 109 pmdp[0] = __pmd(pmdval);
111 pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t)); 110 pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
112 flush_pmd_entry(pmdp); 111 flush_pmd_entry(pmdp);
@@ -121,14 +120,10 @@ static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
121static inline void 120static inline void
122pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) 121pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
123{ 122{
124 unsigned long pte_ptr = (unsigned long)ptep;
125
126 /* 123 /*
127 * The pmd must be loaded with the physical 124 * The pmd must be loaded with the physical address of the PTE table
128 * address of the PTE table
129 */ 125 */
130 pte_ptr -= PTRS_PER_PTE * sizeof(void *); 126 __pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE);
131 __pmd_populate(pmdp, __pa(pte_ptr), _PAGE_KERNEL_TABLE);
132} 127}
133 128
134static inline void 129static inline void
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 50eb0b4278ec..e582214b00df 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -55,7 +55,7 @@
55 * Therefore, we tweak the implementation slightly - we tell Linux that we 55 * Therefore, we tweak the implementation slightly - we tell Linux that we
56 * have 2048 entries in the first level, each of which is 8 bytes (iow, two 56 * have 2048 entries in the first level, each of which is 8 bytes (iow, two
57 * hardware pointers to the second level.) The second level contains two 57 * hardware pointers to the second level.) The second level contains two
58 * hardware PTE tables arranged contiguously, followed by Linux versions 58 * hardware PTE tables arranged contiguously, preceded by Linux versions
59 * which contain the state information Linux needs. We, therefore, end up 59 * which contain the state information Linux needs. We, therefore, end up
60 * with 512 entries in the "PTE" level. 60 * with 512 entries in the "PTE" level.
61 * 61 *
@@ -63,15 +63,15 @@
63 * 63 *
64 * pgd pte 64 * pgd pte
65 * | | 65 * | |
66 * +--------+ +0 66 * +--------+
67 * | |-----> +------------+ +0 67 * | | +------------+ +0
68 * +- - - - + | Linux pt 0 |
69 * | | +------------+ +1024
70 * +--------+ +0 | Linux pt 1 |
71 * | |-----> +------------+ +2048
68 * +- - - - + +4 | h/w pt 0 | 72 * +- - - - + +4 | h/w pt 0 |
69 * | |-----> +------------+ +1024 73 * | |-----> +------------+ +3072
70 * +--------+ +8 | h/w pt 1 | 74 * +--------+ +8 | h/w pt 1 |
71 * | | +------------+ +2048
72 * +- - - - + | Linux pt 0 |
73 * | | +------------+ +3072
74 * +--------+ | Linux pt 1 |
75 * | | +------------+ +4096 75 * | | +------------+ +4096
76 * 76 *
77 * See L_PTE_xxx below for definitions of bits in the "Linux pt", and 77 * See L_PTE_xxx below for definitions of bits in the "Linux pt", and
@@ -103,6 +103,10 @@
103#define PTRS_PER_PMD 1 103#define PTRS_PER_PMD 1
104#define PTRS_PER_PGD 2048 104#define PTRS_PER_PGD 2048
105 105
106#define PTE_HWTABLE_PTRS (PTRS_PER_PTE)
107#define PTE_HWTABLE_OFF (PTE_HWTABLE_PTRS * sizeof(pte_t))
108#define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u32))
109
106/* 110/*
107 * PMD_SHIFT determines the size of the area a second-level page table can map 111 * PMD_SHIFT determines the size of the area a second-level page table can map
108 * PGDIR_SHIFT determines what a third-level page table entry can map 112 * PGDIR_SHIFT determines what a third-level page table entry can map
@@ -323,12 +327,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
323 327
324static inline pte_t *pmd_page_vaddr(pmd_t pmd) 328static inline pte_t *pmd_page_vaddr(pmd_t pmd)
325{ 329{
326 phys_addr_t ptr; 330 return __va(pmd_val(pmd) & PAGE_MASK);
327
328 ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * sizeof(void *) - 1);
329 ptr += PTRS_PER_PTE * sizeof(void *);
330
331 return __va(ptr);
332} 331}
333 332
334#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd))) 333#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
@@ -341,8 +340,8 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
341#define __pte_map(pmd) pmd_page_vaddr(*(pmd)) 340#define __pte_map(pmd) pmd_page_vaddr(*(pmd))
342#define __pte_unmap(pte) do { } while (0) 341#define __pte_unmap(pte) do { } while (0)
343#else 342#else
344#define __pte_map(pmd) ((pte_t *)kmap_atomic(pmd_page(*(pmd))) + PTRS_PER_PTE) 343#define __pte_map(pmd) (pte_t *)kmap_atomic(pmd_page(*(pmd)))
345#define __pte_unmap(pte) kunmap_atomic((pte - PTRS_PER_PTE)) 344#define __pte_unmap(pte) kunmap_atomic(pte)
346#endif 345#endif
347 346
348#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 347#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 1e21e125fe3a..f10f9bac2206 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -108,7 +108,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
108 108
109 pte = pte_offset_map(pmd, addr); 109 pte = pte_offset_map(pmd, addr);
110 printk(", *pte=%08lx", pte_val(*pte)); 110 printk(", *pte=%08lx", pte_val(*pte));
111 printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE])); 111 printk(", *ppte=%08lx", pte_val(pte[PTE_HWTABLE_PTRS]));
112 pte_unmap(pte); 112 pte_unmap(pte);
113 } while(0); 113 } while(0);
114 114
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 7d63beaf9745..cbedf9c46b9d 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -121,7 +121,7 @@
121 .endm 121 .endm
122 122
123 .macro armv6_set_pte_ext pfx 123 .macro armv6_set_pte_ext pfx
124 str r1, [r0], #-2048 @ linux version 124 str r1, [r0], #2048 @ linux version
125 125
126 bic r3, r1, #0x000003fc 126 bic r3, r1, #0x000003fc
127 bic r3, r3, #PTE_TYPE_MASK 127 bic r3, r3, #PTE_TYPE_MASK
@@ -170,7 +170,7 @@
170 * 1111 0xff r/w r/w 170 * 1111 0xff r/w r/w
171 */ 171 */
172 .macro armv3_set_pte_ext wc_disable=1 172 .macro armv3_set_pte_ext wc_disable=1
173 str r1, [r0], #-2048 @ linux version 173 str r1, [r0], #2048 @ linux version
174 174
175 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY 175 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
176 176
@@ -193,7 +193,7 @@
193 bicne r2, r2, #PTE_BUFFERABLE 193 bicne r2, r2, #PTE_BUFFERABLE
194#endif 194#endif
195 .endif 195 .endif
196 str r2, [r0] @ hardware version 196 str r2, [r0] @ hardware version
197 .endm 197 .endm
198 198
199 199
@@ -213,7 +213,7 @@
213 * 1111 11 r/w r/w 213 * 1111 11 r/w r/w
214 */ 214 */
215 .macro xscale_set_pte_ext_prologue 215 .macro xscale_set_pte_ext_prologue
216 str r1, [r0], #-2048 @ linux version 216 str r1, [r0] @ linux version
217 217
218 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY 218 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
219 219
@@ -232,7 +232,7 @@
232 tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young? 232 tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young?
233 movne r2, #0 @ no -> fault 233 movne r2, #0 @ no -> fault
234 234
235 str r2, [r0] @ hardware version 235 str r2, [r0, #2048]! @ hardware version
236 mov ip, #0 236 mov ip, #0
237 mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line 237 mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
238 mcr p15, 0, ip, c7, c10, 4 @ data write barrier 238 mcr p15, 0, ip, c7, c10, 4 @ data write barrier
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 53cbe2225153..89c31a6dae5c 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -124,15 +124,13 @@ ENDPROC(cpu_v7_switch_mm)
124 * Set a level 2 translation table entry. 124 * Set a level 2 translation table entry.
125 * 125 *
126 * - ptep - pointer to level 2 translation table entry 126 * - ptep - pointer to level 2 translation table entry
127 * (hardware version is stored at -1024 bytes) 127 * (hardware version is stored at +2048 bytes)
128 * - pte - PTE value to store 128 * - pte - PTE value to store
129 * - ext - value for extended PTE bits 129 * - ext - value for extended PTE bits
130 */ 130 */
131ENTRY(cpu_v7_set_pte_ext) 131ENTRY(cpu_v7_set_pte_ext)
132#ifdef CONFIG_MMU 132#ifdef CONFIG_MMU
133 ARM( str r1, [r0], #-2048 ) @ linux version 133 str r1, [r0] @ linux version
134 THUMB( str r1, [r0] ) @ linux version
135 THUMB( sub r0, r0, #2048 )
136 134
137 bic r3, r1, #0x000003f0 135 bic r3, r1, #0x000003f0
138 bic r3, r3, #PTE_TYPE_MASK 136 bic r3, r3, #PTE_TYPE_MASK
@@ -158,7 +156,7 @@ ENTRY(cpu_v7_set_pte_ext)
158 tstne r1, #L_PTE_PRESENT 156 tstne r1, #L_PTE_PRESENT
159 moveq r3, #0 157 moveq r3, #0
160 158
161 str r3, [r0] 159 str r3, [r0, #2048]!
162 mcr p15, 0, r0, c7, c10, 1 @ flush_pte 160 mcr p15, 0, r0, c7, c10, 1 @ flush_pte
163#endif 161#endif
164 mov pc, lr 162 mov pc, lr