aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
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