diff options
Diffstat (limited to 'arch/powerpc/mm/pgtable.c')
-rw-r--r-- | arch/powerpc/mm/pgtable.c | 179 |
1 files changed, 128 insertions, 51 deletions
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 627767d6169b..83f1551ec2c9 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c | |||
@@ -30,6 +30,16 @@ | |||
30 | #include <asm/tlbflush.h> | 30 | #include <asm/tlbflush.h> |
31 | #include <asm/tlb.h> | 31 | #include <asm/tlb.h> |
32 | 32 | ||
33 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | ||
34 | |||
35 | #ifdef CONFIG_SMP | ||
36 | |||
37 | /* | ||
38 | * Handle batching of page table freeing on SMP. Page tables are | ||
39 | * queued up and send to be freed later by RCU in order to avoid | ||
40 | * freeing a page table page that is being walked without locks | ||
41 | */ | ||
42 | |||
33 | static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); | 43 | static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); |
34 | static unsigned long pte_freelist_forced_free; | 44 | static unsigned long pte_freelist_forced_free; |
35 | 45 | ||
@@ -116,27 +126,7 @@ void pte_free_finish(void) | |||
116 | *batchp = NULL; | 126 | *batchp = NULL; |
117 | } | 127 | } |
118 | 128 | ||
119 | /* | 129 | #endif /* CONFIG_SMP */ |
120 | * Handle i/d cache flushing, called from set_pte_at() or ptep_set_access_flags() | ||
121 | */ | ||
122 | static pte_t do_dcache_icache_coherency(pte_t pte) | ||
123 | { | ||
124 | unsigned long pfn = pte_pfn(pte); | ||
125 | struct page *page; | ||
126 | |||
127 | if (unlikely(!pfn_valid(pfn))) | ||
128 | return pte; | ||
129 | page = pfn_to_page(pfn); | ||
130 | |||
131 | if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) { | ||
132 | pr_devel("do_dcache_icache_coherency... flushing\n"); | ||
133 | flush_dcache_icache_page(page); | ||
134 | set_bit(PG_arch_1, &page->flags); | ||
135 | } | ||
136 | else | ||
137 | pr_devel("do_dcache_icache_coherency... already clean\n"); | ||
138 | return __pte(pte_val(pte) | _PAGE_HWEXEC); | ||
139 | } | ||
140 | 130 | ||
141 | static inline int is_exec_fault(void) | 131 | static inline int is_exec_fault(void) |
142 | { | 132 | { |
@@ -145,49 +135,139 @@ static inline int is_exec_fault(void) | |||
145 | 135 | ||
146 | /* We only try to do i/d cache coherency on stuff that looks like | 136 | /* We only try to do i/d cache coherency on stuff that looks like |
147 | * reasonably "normal" PTEs. We currently require a PTE to be present | 137 | * reasonably "normal" PTEs. We currently require a PTE to be present |
148 | * and we avoid _PAGE_SPECIAL and _PAGE_NO_CACHE | 138 | * and we avoid _PAGE_SPECIAL and _PAGE_NO_CACHE. We also only do that |
139 | * on userspace PTEs | ||
149 | */ | 140 | */ |
150 | static inline int pte_looks_normal(pte_t pte) | 141 | static inline int pte_looks_normal(pte_t pte) |
151 | { | 142 | { |
152 | return (pte_val(pte) & | 143 | return (pte_val(pte) & |
153 | (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE)) == | 144 | (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE | _PAGE_USER)) == |
154 | (_PAGE_PRESENT); | 145 | (_PAGE_PRESENT | _PAGE_USER); |
155 | } | 146 | } |
156 | 147 | ||
157 | #if defined(CONFIG_PPC_STD_MMU) | 148 | struct page * maybe_pte_to_page(pte_t pte) |
149 | { | ||
150 | unsigned long pfn = pte_pfn(pte); | ||
151 | struct page *page; | ||
152 | |||
153 | if (unlikely(!pfn_valid(pfn))) | ||
154 | return NULL; | ||
155 | page = pfn_to_page(pfn); | ||
156 | if (PageReserved(page)) | ||
157 | return NULL; | ||
158 | return page; | ||
159 | } | ||
160 | |||
161 | #if defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0 | ||
162 | |||
158 | /* Server-style MMU handles coherency when hashing if HW exec permission | 163 | /* Server-style MMU handles coherency when hashing if HW exec permission |
159 | * is supposed per page (currently 64-bit only). Else, we always flush | 164 | * is supposed per page (currently 64-bit only). If not, then, we always |
160 | * valid PTEs in set_pte. | 165 | * flush the cache for valid PTEs in set_pte. Embedded CPU without HW exec |
166 | * support falls into the same category. | ||
161 | */ | 167 | */ |
162 | static inline int pte_need_exec_flush(pte_t pte, int set_pte) | 168 | |
169 | static pte_t set_pte_filter(pte_t pte) | ||
163 | { | 170 | { |
164 | return set_pte && pte_looks_normal(pte) && | 171 | pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); |
165 | !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) || | 172 | if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) || |
166 | cpu_has_feature(CPU_FTR_NOEXECUTE)); | 173 | cpu_has_feature(CPU_FTR_NOEXECUTE))) { |
174 | struct page *pg = maybe_pte_to_page(pte); | ||
175 | if (!pg) | ||
176 | return pte; | ||
177 | if (!test_bit(PG_arch_1, &pg->flags)) { | ||
178 | flush_dcache_icache_page(pg); | ||
179 | set_bit(PG_arch_1, &pg->flags); | ||
180 | } | ||
181 | } | ||
182 | return pte; | ||
167 | } | 183 | } |
168 | #elif _PAGE_HWEXEC == 0 | 184 | |
169 | /* Embedded type MMU without HW exec support (8xx only so far), we flush | 185 | static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, |
170 | * the cache for any present PTE | 186 | int dirty) |
171 | */ | ||
172 | static inline int pte_need_exec_flush(pte_t pte, int set_pte) | ||
173 | { | 187 | { |
174 | return set_pte && pte_looks_normal(pte); | 188 | return pte; |
175 | } | 189 | } |
176 | #else | 190 | |
177 | /* Other embedded CPUs with HW exec support per-page, we flush on exec | 191 | #else /* defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0 */ |
178 | * fault if HWEXEC is not set | 192 | |
193 | /* Embedded type MMU with HW exec support. This is a bit more complicated | ||
194 | * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so | ||
195 | * instead we "filter out" the exec permission for non clean pages. | ||
179 | */ | 196 | */ |
180 | static inline int pte_need_exec_flush(pte_t pte, int set_pte) | 197 | static pte_t set_pte_filter(pte_t pte) |
181 | { | 198 | { |
182 | return pte_looks_normal(pte) && is_exec_fault() && | 199 | struct page *pg; |
183 | !(pte_val(pte) & _PAGE_HWEXEC); | 200 | |
201 | /* No exec permission in the first place, move on */ | ||
202 | if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte)) | ||
203 | return pte; | ||
204 | |||
205 | /* If you set _PAGE_EXEC on weird pages you're on your own */ | ||
206 | pg = maybe_pte_to_page(pte); | ||
207 | if (unlikely(!pg)) | ||
208 | return pte; | ||
209 | |||
210 | /* If the page clean, we move on */ | ||
211 | if (test_bit(PG_arch_1, &pg->flags)) | ||
212 | return pte; | ||
213 | |||
214 | /* If it's an exec fault, we flush the cache and make it clean */ | ||
215 | if (is_exec_fault()) { | ||
216 | flush_dcache_icache_page(pg); | ||
217 | set_bit(PG_arch_1, &pg->flags); | ||
218 | return pte; | ||
219 | } | ||
220 | |||
221 | /* Else, we filter out _PAGE_EXEC */ | ||
222 | return __pte(pte_val(pte) & ~_PAGE_EXEC); | ||
184 | } | 223 | } |
185 | #endif | 224 | |
225 | static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, | ||
226 | int dirty) | ||
227 | { | ||
228 | struct page *pg; | ||
229 | |||
230 | /* So here, we only care about exec faults, as we use them | ||
231 | * to recover lost _PAGE_EXEC and perform I$/D$ coherency | ||
232 | * if necessary. Also if _PAGE_EXEC is already set, same deal, | ||
233 | * we just bail out | ||
234 | */ | ||
235 | if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault()) | ||
236 | return pte; | ||
237 | |||
238 | #ifdef CONFIG_DEBUG_VM | ||
239 | /* So this is an exec fault, _PAGE_EXEC is not set. If it was | ||
240 | * an error we would have bailed out earlier in do_page_fault() | ||
241 | * but let's make sure of it | ||
242 | */ | ||
243 | if (WARN_ON(!(vma->vm_flags & VM_EXEC))) | ||
244 | return pte; | ||
245 | #endif /* CONFIG_DEBUG_VM */ | ||
246 | |||
247 | /* If you set _PAGE_EXEC on weird pages you're on your own */ | ||
248 | pg = maybe_pte_to_page(pte); | ||
249 | if (unlikely(!pg)) | ||
250 | goto bail; | ||
251 | |||
252 | /* If the page is already clean, we move on */ | ||
253 | if (test_bit(PG_arch_1, &pg->flags)) | ||
254 | goto bail; | ||
255 | |||
256 | /* Clean the page and set PG_arch_1 */ | ||
257 | flush_dcache_icache_page(pg); | ||
258 | set_bit(PG_arch_1, &pg->flags); | ||
259 | |||
260 | bail: | ||
261 | return __pte(pte_val(pte) | _PAGE_EXEC); | ||
262 | } | ||
263 | |||
264 | #endif /* !(defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0) */ | ||
186 | 265 | ||
187 | /* | 266 | /* |
188 | * set_pte stores a linux PTE into the linux page table. | 267 | * set_pte stores a linux PTE into the linux page table. |
189 | */ | 268 | */ |
190 | void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) | 269 | void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, |
270 | pte_t pte) | ||
191 | { | 271 | { |
192 | #ifdef CONFIG_DEBUG_VM | 272 | #ifdef CONFIG_DEBUG_VM |
193 | WARN_ON(pte_present(*ptep)); | 273 | WARN_ON(pte_present(*ptep)); |
@@ -196,9 +276,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte | |||
196 | * this context might not have been activated yet when this | 276 | * this context might not have been activated yet when this |
197 | * is called. | 277 | * is called. |
198 | */ | 278 | */ |
199 | pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); | 279 | pte = set_pte_filter(pte); |
200 | if (pte_need_exec_flush(pte, 1)) | ||
201 | pte = do_dcache_icache_coherency(pte); | ||
202 | 280 | ||
203 | /* Perform the setting of the PTE */ | 281 | /* Perform the setting of the PTE */ |
204 | __set_pte_at(mm, addr, ptep, pte, 0); | 282 | __set_pte_at(mm, addr, ptep, pte, 0); |
@@ -215,8 +293,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, | |||
215 | pte_t *ptep, pte_t entry, int dirty) | 293 | pte_t *ptep, pte_t entry, int dirty) |
216 | { | 294 | { |
217 | int changed; | 295 | int changed; |
218 | if (!dirty && pte_need_exec_flush(entry, 0)) | 296 | entry = set_access_flags_filter(entry, vma, dirty); |
219 | entry = do_dcache_icache_coherency(entry); | ||
220 | changed = !pte_same(*(ptep), entry); | 297 | changed = !pte_same(*(ptep), entry); |
221 | if (changed) { | 298 | if (changed) { |
222 | if (!(vma->vm_flags & VM_HUGETLB)) | 299 | if (!(vma->vm_flags & VM_HUGETLB)) |
@@ -242,7 +319,7 @@ void assert_pte_locked(struct mm_struct *mm, unsigned long addr) | |||
242 | BUG_ON(pud_none(*pud)); | 319 | BUG_ON(pud_none(*pud)); |
243 | pmd = pmd_offset(pud, addr); | 320 | pmd = pmd_offset(pud, addr); |
244 | BUG_ON(!pmd_present(*pmd)); | 321 | BUG_ON(!pmd_present(*pmd)); |
245 | BUG_ON(!spin_is_locked(pte_lockptr(mm, pmd))); | 322 | assert_spin_locked(pte_lockptr(mm, pmd)); |
246 | } | 323 | } |
247 | #endif /* CONFIG_DEBUG_VM */ | 324 | #endif /* CONFIG_DEBUG_VM */ |
248 | 325 | ||