diff options
Diffstat (limited to 'arch/powerpc/mm/tlb_64.c')
-rw-r--r-- | arch/powerpc/mm/tlb_64.c | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c index 2bfc4d7e1aa2..cbd34fc813ee 100644 --- a/arch/powerpc/mm/tlb_64.c +++ b/arch/powerpc/mm/tlb_64.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) | 8 | * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) |
9 | * and Cort Dougan (PReP) (cort@cs.nmt.edu) | 9 | * and Cort Dougan (PReP) (cort@cs.nmt.edu) |
10 | * Copyright (C) 1996 Paul Mackerras | 10 | * Copyright (C) 1996 Paul Mackerras |
11 | * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). | ||
12 | * | 11 | * |
13 | * Derived from "arch/i386/mm/init.c" | 12 | * Derived from "arch/i386/mm/init.c" |
14 | * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds | 13 | * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds |
@@ -239,3 +238,59 @@ void pte_free_finish(void) | |||
239 | pte_free_submit(*batchp); | 238 | pte_free_submit(*batchp); |
240 | *batchp = NULL; | 239 | *batchp = NULL; |
241 | } | 240 | } |
241 | |||
242 | /** | ||
243 | * __flush_hash_table_range - Flush all HPTEs for a given address range | ||
244 | * from the hash table (and the TLB). But keeps | ||
245 | * the linux PTEs intact. | ||
246 | * | ||
247 | * @mm : mm_struct of the target address space (generally init_mm) | ||
248 | * @start : starting address | ||
249 | * @end : ending address (not included in the flush) | ||
250 | * | ||
251 | * This function is mostly to be used by some IO hotplug code in order | ||
252 | * to remove all hash entries from a given address range used to map IO | ||
253 | * space on a removed PCI-PCI bidge without tearing down the full mapping | ||
254 | * since 64K pages may overlap with other bridges when using 64K pages | ||
255 | * with 4K HW pages on IO space. | ||
256 | * | ||
257 | * Because of that usage pattern, it's only available with CONFIG_HOTPLUG | ||
258 | * and is implemented for small size rather than speed. | ||
259 | */ | ||
260 | #ifdef CONFIG_HOTPLUG | ||
261 | |||
262 | void __flush_hash_table_range(struct mm_struct *mm, unsigned long start, | ||
263 | unsigned long end) | ||
264 | { | ||
265 | unsigned long flags; | ||
266 | |||
267 | start = _ALIGN_DOWN(start, PAGE_SIZE); | ||
268 | end = _ALIGN_UP(end, PAGE_SIZE); | ||
269 | |||
270 | BUG_ON(!mm->pgd); | ||
271 | |||
272 | /* Note: Normally, we should only ever use a batch within a | ||
273 | * PTE locked section. This violates the rule, but will work | ||
274 | * since we don't actually modify the PTEs, we just flush the | ||
275 | * hash while leaving the PTEs intact (including their reference | ||
276 | * to being hashed). This is not the most performance oriented | ||
277 | * way to do things but is fine for our needs here. | ||
278 | */ | ||
279 | local_irq_save(flags); | ||
280 | arch_enter_lazy_mmu_mode(); | ||
281 | for (; start < end; start += PAGE_SIZE) { | ||
282 | pte_t *ptep = find_linux_pte(mm->pgd, start); | ||
283 | unsigned long pte; | ||
284 | |||
285 | if (ptep == NULL) | ||
286 | continue; | ||
287 | pte = pte_val(*ptep); | ||
288 | if (!(pte & _PAGE_HASHPTE)) | ||
289 | continue; | ||
290 | hpte_need_flush(mm, start, ptep, pte, 0); | ||
291 | } | ||
292 | arch_leave_lazy_mmu_mode(); | ||
293 | local_irq_restore(flags); | ||
294 | } | ||
295 | |||
296 | #endif /* CONFIG_HOTPLUG */ | ||