aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/include
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-12-18 14:13:38 -0500
committerPaul Mackerras <paulus@samba.org>2008-12-20 22:21:16 -0500
commitf048aace29e007f2b642097e2da8231e0e9cce2d (patch)
tree5e99b1d1d37817703132e97388994386a7bee8da /arch/powerpc/include
parent7c03d653cd257793dc40520c94e229b5fd0578e7 (diff)
powerpc/mm: Add SMP support to no-hash TLB handling
This commit moves the whole no-hash TLB handling out of line into a new tlb_nohash.c file, and implements some basic SMP support using IPIs and/or broadcast tlbivax instructions. Note that I'm using local invalidations for D->I cache coherency. At worst, if another processor is trying to execute the same and has the old entry in its TLB, it will just take a fault and re-do the TLB flush locally (it won't re-do the cache flush in any case). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Kumar Gala <galak@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/include')
-rw-r--r--arch/powerpc/include/asm/highmem.h4
-rw-r--r--arch/powerpc/include/asm/mmu.h16
-rw-r--r--arch/powerpc/include/asm/tlbflush.h84
3 files changed, 56 insertions, 48 deletions
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
index 7dc52eca8b67..fd97e501aa6a 100644
--- a/arch/powerpc/include/asm/highmem.h
+++ b/arch/powerpc/include/asm/highmem.h
@@ -85,7 +85,7 @@ static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgpro
85 BUG_ON(!pte_none(*(kmap_pte-idx))); 85 BUG_ON(!pte_none(*(kmap_pte-idx)));
86#endif 86#endif
87 __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); 87 __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
88 local_flush_tlb_page(vaddr); 88 local_flush_tlb_page(NULL, vaddr);
89 89
90 return (void*) vaddr; 90 return (void*) vaddr;
91} 91}
@@ -113,7 +113,7 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type)
113 * this pte without first remap it 113 * this pte without first remap it
114 */ 114 */
115 pte_clear(&init_mm, vaddr, kmap_pte-idx); 115 pte_clear(&init_mm, vaddr, kmap_pte-idx);
116 local_flush_tlb_page(vaddr); 116 local_flush_tlb_page(NULL, vaddr);
117#endif 117#endif
118 pagefault_enable(); 118 pagefault_enable();
119} 119}
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index dc8c0aef5e6c..6e7639911318 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -30,6 +30,22 @@
30 */ 30 */
31#define MMU_FTR_BIG_PHYS ASM_CONST(0x00020000) 31#define MMU_FTR_BIG_PHYS ASM_CONST(0x00020000)
32 32
33/* Enable use of broadcast TLB invalidations. We don't always set it
34 * on processors that support it due to other constraints with the
35 * use of such invalidations
36 */
37#define MMU_FTR_USE_TLBIVAX_BCAST ASM_CONST(0x00040000)
38
39/* Enable use of tlbilx invalidate-by-PID variant.
40 */
41#define MMU_FTR_USE_TLBILX_PID ASM_CONST(0x00080000)
42
43/* This indicates that the processor cannot handle multiple outstanding
44 * broadcast tlbivax or tlbsync. This makes the code use a spinlock
45 * around such invalidate forms.
46 */
47#define MMU_FTR_LOCK_BCAST_INVAL ASM_CONST(0x00100000)
48
33#ifndef __ASSEMBLY__ 49#ifndef __ASSEMBLY__
34#include <asm/cputable.h> 50#include <asm/cputable.h>
35 51
diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h
index 9ed363d3de44..8c39b27c1ed7 100644
--- a/arch/powerpc/include/asm/tlbflush.h
+++ b/arch/powerpc/include/asm/tlbflush.h
@@ -6,7 +6,9 @@
6 * 6 *
7 * - flush_tlb_mm(mm) flushes the specified mm context TLB's 7 * - flush_tlb_mm(mm) flushes the specified mm context TLB's
8 * - flush_tlb_page(vma, vmaddr) flushes one page 8 * - flush_tlb_page(vma, vmaddr) flushes one page
9 * - local_flush_tlb_page(vmaddr) flushes one page on the local processor 9 * - local_flush_tlb_mm(mm) flushes the specified mm context on
10 * the local processor
11 * - local_flush_tlb_page(vma, vmaddr) flushes one page on the local processor
10 * - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB 12 * - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB
11 * - flush_tlb_range(vma, start, end) flushes a range of pages 13 * - flush_tlb_range(vma, start, end) flushes a range of pages
12 * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages 14 * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
@@ -18,7 +20,7 @@
18 */ 20 */
19#ifdef __KERNEL__ 21#ifdef __KERNEL__
20 22
21#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE) 23#ifdef CONFIG_PPC_MMU_NOHASH
22/* 24/*
23 * TLB flushing for software loaded TLB chips 25 * TLB flushing for software loaded TLB chips
24 * 26 *
@@ -31,10 +33,10 @@
31 33
32#define MMU_NO_CONTEXT ((unsigned int)-1) 34#define MMU_NO_CONTEXT ((unsigned int)-1)
33 35
34extern void _tlbie(unsigned long address, unsigned int pid);
35extern void _tlbil_all(void); 36extern void _tlbil_all(void);
36extern void _tlbil_pid(unsigned int pid); 37extern void _tlbil_pid(unsigned int pid);
37extern void _tlbil_va(unsigned long address, unsigned int pid); 38extern void _tlbil_va(unsigned long address, unsigned int pid);
39extern void _tlbivax_bcast(unsigned long address, unsigned int pid);
38 40
39#if defined(CONFIG_40x) || defined(CONFIG_8xx) 41#if defined(CONFIG_40x) || defined(CONFIG_8xx)
40#define _tlbia() asm volatile ("tlbia; sync" : : : "memory") 42#define _tlbia() asm volatile ("tlbia; sync" : : : "memory")
@@ -42,48 +44,26 @@ extern void _tlbil_va(unsigned long address, unsigned int pid);
42extern void _tlbia(void); 44extern void _tlbia(void);
43#endif 45#endif
44 46
45static inline void local_flush_tlb_mm(struct mm_struct *mm) 47extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
46{ 48 unsigned long end);
47 _tlbil_pid(mm->context.id); 49extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
48}
49
50static inline void flush_tlb_mm(struct mm_struct *mm)
51{
52 _tlbil_pid(mm->context.id);
53}
54
55static inline void local_flush_tlb_page(unsigned long vmaddr)
56{
57 _tlbil_va(vmaddr, 0);
58}
59
60static inline void flush_tlb_page(struct vm_area_struct *vma,
61 unsigned long vmaddr)
62{
63 _tlbil_va(vmaddr, vma ? vma->vm_mm->context.id : 0);
64}
65 50
66static inline void flush_tlb_page_nohash(struct vm_area_struct *vma, 51extern void local_flush_tlb_mm(struct mm_struct *mm);
67 unsigned long vmaddr) 52extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
68{
69 flush_tlb_page(vma, vmaddr);
70}
71 53
72static inline void flush_tlb_range(struct vm_area_struct *vma, 54#ifdef CONFIG_SMP
73 unsigned long start, unsigned long end) 55extern void flush_tlb_mm(struct mm_struct *mm);
74{ 56extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
75 _tlbil_pid(vma->vm_mm->context.id); 57#else
76} 58#define flush_tlb_mm(mm) local_flush_tlb_mm(mm)
59#define flush_tlb_page(vma,addr) local_flush_tlb_page(vma,addr)
60#endif
61#define flush_tlb_page_nohash(vma,addr) flush_tlb_page(vma,addr)
77 62
78static inline void flush_tlb_kernel_range(unsigned long start, 63#elif defined(CONFIG_PPC_STD_MMU_32)
79 unsigned long end)
80{
81 _tlbil_pid(0);
82}
83 64
84#elif defined(CONFIG_PPC32)
85/* 65/*
86 * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx 66 * TLB flushing for "classic" hash-MMU 32-bit CPUs, 6xx, 7xx, 7xxx
87 */ 67 */
88extern void _tlbie(unsigned long address); 68extern void _tlbie(unsigned long address);
89extern void _tlbia(void); 69extern void _tlbia(void);
@@ -94,14 +74,20 @@ extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr
94extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 74extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
95 unsigned long end); 75 unsigned long end);
96extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); 76extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
97static inline void local_flush_tlb_page(unsigned long vmaddr) 77static inline void local_flush_tlb_page(struct vm_area_struct *vma,
78 unsigned long vmaddr)
98{ 79{
99 flush_tlb_page(NULL, vmaddr); 80 flush_tlb_page(vma, vmaddr);
81}
82static inline void local_flush_tlb_mm(struct mm_struct *mm)
83{
84 flush_tlb_mm(mm);
100} 85}
101 86
102#else 87#elif defined(CONFIG_PPC_STD_MMU_64)
88
103/* 89/*
104 * TLB flushing for 64-bit has-MMU CPUs 90 * TLB flushing for 64-bit hash-MMU CPUs
105 */ 91 */
106 92
107#include <linux/percpu.h> 93#include <linux/percpu.h>
@@ -151,11 +137,16 @@ extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize,
151extern void flush_hash_range(unsigned long number, int local); 137extern void flush_hash_range(unsigned long number, int local);
152 138
153 139
140static inline void local_flush_tlb_mm(struct mm_struct *mm)
141{
142}
143
154static inline void flush_tlb_mm(struct mm_struct *mm) 144static inline void flush_tlb_mm(struct mm_struct *mm)
155{ 145{
156} 146}
157 147
158static inline void local_flush_tlb_page(unsigned long vmaddr) 148static inline void local_flush_tlb_page(struct vm_area_struct *vma,
149 unsigned long vmaddr)
159{ 150{
160} 151}
161 152
@@ -183,7 +174,8 @@ static inline void flush_tlb_kernel_range(unsigned long start,
183extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start, 174extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
184 unsigned long end); 175 unsigned long end);
185 176
186 177#else
178#error Unsupported MMU type
187#endif 179#endif
188 180
189#endif /*__KERNEL__ */ 181#endif /*__KERNEL__ */