aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/tlb_nohash.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm/tlb_nohash.c')
-rw-r--r--arch/powerpc/mm/tlb_nohash.c268
1 files changed, 253 insertions, 15 deletions
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index ad2eb4d34dd4..2fbc680c2c71 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -7,8 +7,8 @@
7 * 7 *
8 * -- BenH 8 * -- BenH
9 * 9 *
10 * Copyright 2008 Ben Herrenschmidt <benh@kernel.crashing.org> 10 * Copyright 2008,2009 Ben Herrenschmidt <benh@kernel.crashing.org>
11 * IBM Corp. 11 * IBM Corp.
12 * 12 *
13 * Derived from arch/ppc/mm/init.c: 13 * Derived from arch/ppc/mm/init.c:
14 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 14 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -34,12 +34,71 @@
34#include <linux/pagemap.h> 34#include <linux/pagemap.h>
35#include <linux/preempt.h> 35#include <linux/preempt.h>
36#include <linux/spinlock.h> 36#include <linux/spinlock.h>
37#include <linux/lmb.h>
37 38
38#include <asm/tlbflush.h> 39#include <asm/tlbflush.h>
39#include <asm/tlb.h> 40#include <asm/tlb.h>
41#include <asm/code-patching.h>
40 42
41#include "mmu_decl.h" 43#include "mmu_decl.h"
42 44
45#ifdef CONFIG_PPC_BOOK3E
46struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
47 [MMU_PAGE_4K] = {
48 .shift = 12,
49 .enc = BOOK3E_PAGESZ_4K,
50 },
51 [MMU_PAGE_16K] = {
52 .shift = 14,
53 .enc = BOOK3E_PAGESZ_16K,
54 },
55 [MMU_PAGE_64K] = {
56 .shift = 16,
57 .enc = BOOK3E_PAGESZ_64K,
58 },
59 [MMU_PAGE_1M] = {
60 .shift = 20,
61 .enc = BOOK3E_PAGESZ_1M,
62 },
63 [MMU_PAGE_16M] = {
64 .shift = 24,
65 .enc = BOOK3E_PAGESZ_16M,
66 },
67 [MMU_PAGE_256M] = {
68 .shift = 28,
69 .enc = BOOK3E_PAGESZ_256M,
70 },
71 [MMU_PAGE_1G] = {
72 .shift = 30,
73 .enc = BOOK3E_PAGESZ_1GB,
74 },
75};
76static inline int mmu_get_tsize(int psize)
77{
78 return mmu_psize_defs[psize].enc;
79}
80#else
81static inline int mmu_get_tsize(int psize)
82{
83 /* This isn't used on !Book3E for now */
84 return 0;
85}
86#endif
87
88/* The variables below are currently only used on 64-bit Book3E
89 * though this will probably be made common with other nohash
90 * implementations at some point
91 */
92#ifdef CONFIG_PPC64
93
94int mmu_linear_psize; /* Page size used for the linear mapping */
95int mmu_pte_psize; /* Page size used for PTE pages */
96int mmu_vmemmap_psize; /* Page size used for the virtual mem map */
97int book3e_htw_enabled; /* Is HW tablewalk enabled ? */
98unsigned long linear_map_top; /* Top of linear mapping */
99
100#endif /* CONFIG_PPC64 */
101
43/* 102/*
44 * Base TLB flushing operations: 103 * Base TLB flushing operations:
45 * 104 *
@@ -67,18 +126,24 @@ void local_flush_tlb_mm(struct mm_struct *mm)
67} 126}
68EXPORT_SYMBOL(local_flush_tlb_mm); 127EXPORT_SYMBOL(local_flush_tlb_mm);
69 128
70void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) 129void __local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
130 int tsize, int ind)
71{ 131{
72 unsigned int pid; 132 unsigned int pid;
73 133
74 preempt_disable(); 134 preempt_disable();
75 pid = vma ? vma->vm_mm->context.id : 0; 135 pid = mm ? mm->context.id : 0;
76 if (pid != MMU_NO_CONTEXT) 136 if (pid != MMU_NO_CONTEXT)
77 _tlbil_va(vmaddr, pid); 137 _tlbil_va(vmaddr, pid, tsize, ind);
78 preempt_enable(); 138 preempt_enable();
79} 139}
80EXPORT_SYMBOL(local_flush_tlb_page);
81 140
141void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
142{
143 __local_flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
144 mmu_get_tsize(mmu_virtual_psize), 0);
145}
146EXPORT_SYMBOL(local_flush_tlb_page);
82 147
83/* 148/*
84 * And here are the SMP non-local implementations 149 * And here are the SMP non-local implementations
@@ -87,9 +152,17 @@ EXPORT_SYMBOL(local_flush_tlb_page);
87 152
88static DEFINE_SPINLOCK(tlbivax_lock); 153static DEFINE_SPINLOCK(tlbivax_lock);
89 154
155static int mm_is_core_local(struct mm_struct *mm)
156{
157 return cpumask_subset(mm_cpumask(mm),
158 topology_thread_cpumask(smp_processor_id()));
159}
160
90struct tlb_flush_param { 161struct tlb_flush_param {
91 unsigned long addr; 162 unsigned long addr;
92 unsigned int pid; 163 unsigned int pid;
164 unsigned int tsize;
165 unsigned int ind;
93}; 166};
94 167
95static void do_flush_tlb_mm_ipi(void *param) 168static void do_flush_tlb_mm_ipi(void *param)
@@ -103,7 +176,7 @@ static void do_flush_tlb_page_ipi(void *param)
103{ 176{
104 struct tlb_flush_param *p = param; 177 struct tlb_flush_param *p = param;
105 178
106 _tlbil_va(p->addr, p->pid); 179 _tlbil_va(p->addr, p->pid, p->tsize, p->ind);
107} 180}
108 181
109 182
@@ -131,7 +204,7 @@ void flush_tlb_mm(struct mm_struct *mm)
131 pid = mm->context.id; 204 pid = mm->context.id;
132 if (unlikely(pid == MMU_NO_CONTEXT)) 205 if (unlikely(pid == MMU_NO_CONTEXT))
133 goto no_context; 206 goto no_context;
134 if (!cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { 207 if (!mm_is_core_local(mm)) {
135 struct tlb_flush_param p = { .pid = pid }; 208 struct tlb_flush_param p = { .pid = pid };
136 /* Ignores smp_processor_id() even if set. */ 209 /* Ignores smp_processor_id() even if set. */
137 smp_call_function_many(mm_cpumask(mm), 210 smp_call_function_many(mm_cpumask(mm),
@@ -143,37 +216,49 @@ void flush_tlb_mm(struct mm_struct *mm)
143} 216}
144EXPORT_SYMBOL(flush_tlb_mm); 217EXPORT_SYMBOL(flush_tlb_mm);
145 218
146void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) 219void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
220 int tsize, int ind)
147{ 221{
148 struct cpumask *cpu_mask; 222 struct cpumask *cpu_mask;
149 unsigned int pid; 223 unsigned int pid;
150 224
151 preempt_disable(); 225 preempt_disable();
152 pid = vma ? vma->vm_mm->context.id : 0; 226 pid = mm ? mm->context.id : 0;
153 if (unlikely(pid == MMU_NO_CONTEXT)) 227 if (unlikely(pid == MMU_NO_CONTEXT))
154 goto bail; 228 goto bail;
155 cpu_mask = mm_cpumask(vma->vm_mm); 229 cpu_mask = mm_cpumask(mm);
156 if (!cpumask_equal(cpu_mask, cpumask_of(smp_processor_id()))) { 230 if (!mm_is_core_local(mm)) {
157 /* If broadcast tlbivax is supported, use it */ 231 /* If broadcast tlbivax is supported, use it */
158 if (mmu_has_feature(MMU_FTR_USE_TLBIVAX_BCAST)) { 232 if (mmu_has_feature(MMU_FTR_USE_TLBIVAX_BCAST)) {
159 int lock = mmu_has_feature(MMU_FTR_LOCK_BCAST_INVAL); 233 int lock = mmu_has_feature(MMU_FTR_LOCK_BCAST_INVAL);
160 if (lock) 234 if (lock)
161 spin_lock(&tlbivax_lock); 235 spin_lock(&tlbivax_lock);
162 _tlbivax_bcast(vmaddr, pid); 236 _tlbivax_bcast(vmaddr, pid, tsize, ind);
163 if (lock) 237 if (lock)
164 spin_unlock(&tlbivax_lock); 238 spin_unlock(&tlbivax_lock);
165 goto bail; 239 goto bail;
166 } else { 240 } else {
167 struct tlb_flush_param p = { .pid = pid, .addr = vmaddr }; 241 struct tlb_flush_param p = {
242 .pid = pid,
243 .addr = vmaddr,
244 .tsize = tsize,
245 .ind = ind,
246 };
168 /* Ignores smp_processor_id() even if set in cpu_mask */ 247 /* Ignores smp_processor_id() even if set in cpu_mask */
169 smp_call_function_many(cpu_mask, 248 smp_call_function_many(cpu_mask,
170 do_flush_tlb_page_ipi, &p, 1); 249 do_flush_tlb_page_ipi, &p, 1);
171 } 250 }
172 } 251 }
173 _tlbil_va(vmaddr, pid); 252 _tlbil_va(vmaddr, pid, tsize, ind);
174 bail: 253 bail:
175 preempt_enable(); 254 preempt_enable();
176} 255}
256
257void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
258{
259 __flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
260 mmu_get_tsize(mmu_virtual_psize), 0);
261}
177EXPORT_SYMBOL(flush_tlb_page); 262EXPORT_SYMBOL(flush_tlb_page);
178 263
179#endif /* CONFIG_SMP */ 264#endif /* CONFIG_SMP */
@@ -207,3 +292,156 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
207 flush_tlb_mm(vma->vm_mm); 292 flush_tlb_mm(vma->vm_mm);
208} 293}
209EXPORT_SYMBOL(flush_tlb_range); 294EXPORT_SYMBOL(flush_tlb_range);
295
296void tlb_flush(struct mmu_gather *tlb)
297{
298 flush_tlb_mm(tlb->mm);
299
300 /* Push out batch of freed page tables */
301 pte_free_finish();
302}
303
304/*
305 * Below are functions specific to the 64-bit variant of Book3E though that
306 * may change in the future
307 */
308
309#ifdef CONFIG_PPC64
310
311/*
312 * Handling of virtual linear page tables or indirect TLB entries
313 * flushing when PTE pages are freed
314 */
315void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
316{
317 int tsize = mmu_psize_defs[mmu_pte_psize].enc;
318
319 if (book3e_htw_enabled) {
320 unsigned long start = address & PMD_MASK;
321 unsigned long end = address + PMD_SIZE;
322 unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift;
323
324 /* This isn't the most optimal, ideally we would factor out the
325 * while preempt & CPU mask mucking around, or even the IPI but
326 * it will do for now
327 */
328 while (start < end) {
329 __flush_tlb_page(tlb->mm, start, tsize, 1);
330 start += size;
331 }
332 } else {
333 unsigned long rmask = 0xf000000000000000ul;
334 unsigned long rid = (address & rmask) | 0x1000000000000000ul;
335 unsigned long vpte = address & ~rmask;
336
337#ifdef CONFIG_PPC_64K_PAGES
338 vpte = (vpte >> (PAGE_SHIFT - 4)) & ~0xfffful;
339#else
340 vpte = (vpte >> (PAGE_SHIFT - 3)) & ~0xffful;
341#endif
342 vpte |= rid;
343 __flush_tlb_page(tlb->mm, vpte, tsize, 0);
344 }
345}
346
347/*
348 * Early initialization of the MMU TLB code
349 */
350static void __early_init_mmu(int boot_cpu)
351{
352 extern unsigned int interrupt_base_book3e;
353 extern unsigned int exc_data_tlb_miss_htw_book3e;
354 extern unsigned int exc_instruction_tlb_miss_htw_book3e;
355
356 unsigned int *ibase = &interrupt_base_book3e;
357 unsigned int mas4;
358
359 /* XXX This will have to be decided at runtime, but right
360 * now our boot and TLB miss code hard wires it. Ideally
361 * we should find out a suitable page size and patch the
362 * TLB miss code (either that or use the PACA to store
363 * the value we want)
364 */
365 mmu_linear_psize = MMU_PAGE_1G;
366
367 /* XXX This should be decided at runtime based on supported
368 * page sizes in the TLB, but for now let's assume 16M is
369 * always there and a good fit (which it probably is)
370 */
371 mmu_vmemmap_psize = MMU_PAGE_16M;
372
373 /* Check if HW tablewalk is present, and if yes, enable it by:
374 *
375 * - patching the TLB miss handlers to branch to the
376 * one dedicates to it
377 *
378 * - setting the global book3e_htw_enabled
379 *
380 * - Set MAS4:INDD and default page size
381 */
382
383 /* XXX This code only checks for TLB 0 capabilities and doesn't
384 * check what page size combos are supported by the HW. It
385 * also doesn't handle the case where a separate array holds
386 * the IND entries from the array loaded by the PT.
387 */
388 if (boot_cpu) {
389 unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
390
391 /* Check if HW loader is supported */
392 if ((tlb0cfg & TLBnCFG_IND) &&
393 (tlb0cfg & TLBnCFG_PT)) {
394 patch_branch(ibase + (0x1c0 / 4),
395 (unsigned long)&exc_data_tlb_miss_htw_book3e, 0);
396 patch_branch(ibase + (0x1e0 / 4),
397 (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0);
398 book3e_htw_enabled = 1;
399 }
400 pr_info("MMU: Book3E Page Tables %s\n",
401 book3e_htw_enabled ? "Enabled" : "Disabled");
402 }
403
404 /* Set MAS4 based on page table setting */
405
406 mas4 = 0x4 << MAS4_WIMGED_SHIFT;
407 if (book3e_htw_enabled) {
408 mas4 |= mas4 | MAS4_INDD;
409#ifdef CONFIG_PPC_64K_PAGES
410 mas4 |= BOOK3E_PAGESZ_256M << MAS4_TSIZED_SHIFT;
411 mmu_pte_psize = MMU_PAGE_256M;
412#else
413 mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT;
414 mmu_pte_psize = MMU_PAGE_1M;
415#endif
416 } else {
417#ifdef CONFIG_PPC_64K_PAGES
418 mas4 |= BOOK3E_PAGESZ_64K << MAS4_TSIZED_SHIFT;
419#else
420 mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT;
421#endif
422 mmu_pte_psize = mmu_virtual_psize;
423 }
424 mtspr(SPRN_MAS4, mas4);
425
426 /* Set the global containing the top of the linear mapping
427 * for use by the TLB miss code
428 */
429 linear_map_top = lmb_end_of_DRAM();
430
431 /* A sync won't hurt us after mucking around with
432 * the MMU configuration
433 */
434 mb();
435}
436
437void __init early_init_mmu(void)
438{
439 __early_init_mmu(1);
440}
441
442void __cpuinit early_init_mmu_secondary(void)
443{
444 __early_init_mmu(0);
445}
446
447#endif /* CONFIG_PPC64 */