diff options
Diffstat (limited to 'arch/x86/kernel/tlb_64.c')
-rw-r--r-- | arch/x86/kernel/tlb_64.c | 76 |
1 files changed, 43 insertions, 33 deletions
diff --git a/arch/x86/kernel/tlb_64.c b/arch/x86/kernel/tlb_64.c index f8be6f1d2e48..e64a32c48825 100644 --- a/arch/x86/kernel/tlb_64.c +++ b/arch/x86/kernel/tlb_64.c | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <asm/uv/uv_hub.h> | 18 | #include <asm/uv/uv_hub.h> |
19 | #include <asm/uv/uv_bau.h> | 19 | #include <asm/uv/uv_bau.h> |
20 | 20 | ||
21 | DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) | ||
22 | = { &init_mm, 0, }; | ||
23 | |||
21 | #include <mach_ipi.h> | 24 | #include <mach_ipi.h> |
22 | /* | 25 | /* |
23 | * Smarter SMP flushing macros. | 26 | * Smarter SMP flushing macros. |
@@ -43,10 +46,10 @@ | |||
43 | 46 | ||
44 | union smp_flush_state { | 47 | union smp_flush_state { |
45 | struct { | 48 | struct { |
46 | cpumask_t flush_cpumask; | ||
47 | struct mm_struct *flush_mm; | 49 | struct mm_struct *flush_mm; |
48 | unsigned long flush_va; | 50 | unsigned long flush_va; |
49 | spinlock_t tlbstate_lock; | 51 | spinlock_t tlbstate_lock; |
52 | DECLARE_BITMAP(flush_cpumask, NR_CPUS); | ||
50 | }; | 53 | }; |
51 | char pad[SMP_CACHE_BYTES]; | 54 | char pad[SMP_CACHE_BYTES]; |
52 | } ____cacheline_aligned; | 55 | } ____cacheline_aligned; |
@@ -62,9 +65,9 @@ static DEFINE_PER_CPU(union smp_flush_state, flush_state); | |||
62 | */ | 65 | */ |
63 | void leave_mm(int cpu) | 66 | void leave_mm(int cpu) |
64 | { | 67 | { |
65 | if (read_pda(mmu_state) == TLBSTATE_OK) | 68 | if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK) |
66 | BUG(); | 69 | BUG(); |
67 | cpu_clear(cpu, read_pda(active_mm)->cpu_vm_mask); | 70 | cpu_clear(cpu, percpu_read(cpu_tlbstate.active_mm)->cpu_vm_mask); |
68 | load_cr3(swapper_pg_dir); | 71 | load_cr3(swapper_pg_dir); |
69 | } | 72 | } |
70 | EXPORT_SYMBOL_GPL(leave_mm); | 73 | EXPORT_SYMBOL_GPL(leave_mm); |
@@ -131,7 +134,7 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs) | |||
131 | sender = ~regs->orig_ax - INVALIDATE_TLB_VECTOR_START; | 134 | sender = ~regs->orig_ax - INVALIDATE_TLB_VECTOR_START; |
132 | f = &per_cpu(flush_state, sender); | 135 | f = &per_cpu(flush_state, sender); |
133 | 136 | ||
134 | if (!cpu_isset(cpu, f->flush_cpumask)) | 137 | if (!cpumask_test_cpu(cpu, to_cpumask(f->flush_cpumask))) |
135 | goto out; | 138 | goto out; |
136 | /* | 139 | /* |
137 | * This was a BUG() but until someone can quote me the | 140 | * This was a BUG() but until someone can quote me the |
@@ -142,8 +145,8 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs) | |||
142 | * BUG(); | 145 | * BUG(); |
143 | */ | 146 | */ |
144 | 147 | ||
145 | if (f->flush_mm == read_pda(active_mm)) { | 148 | if (f->flush_mm == percpu_read(cpu_tlbstate.active_mm)) { |
146 | if (read_pda(mmu_state) == TLBSTATE_OK) { | 149 | if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK) { |
147 | if (f->flush_va == TLB_FLUSH_ALL) | 150 | if (f->flush_va == TLB_FLUSH_ALL) |
148 | local_flush_tlb(); | 151 | local_flush_tlb(); |
149 | else | 152 | else |
@@ -153,19 +156,15 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs) | |||
153 | } | 156 | } |
154 | out: | 157 | out: |
155 | ack_APIC_irq(); | 158 | ack_APIC_irq(); |
156 | cpu_clear(cpu, f->flush_cpumask); | 159 | cpumask_clear_cpu(cpu, to_cpumask(f->flush_cpumask)); |
157 | inc_irq_stat(irq_tlb_count); | 160 | inc_irq_stat(irq_tlb_count); |
158 | } | 161 | } |
159 | 162 | ||
160 | void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, | 163 | static void flush_tlb_others_ipi(const struct cpumask *cpumask, |
161 | unsigned long va) | 164 | struct mm_struct *mm, unsigned long va) |
162 | { | 165 | { |
163 | int sender; | 166 | int sender; |
164 | union smp_flush_state *f; | 167 | union smp_flush_state *f; |
165 | cpumask_t cpumask = *cpumaskp; | ||
166 | |||
167 | if (is_uv_system() && uv_flush_tlb_others(&cpumask, mm, va)) | ||
168 | return; | ||
169 | 168 | ||
170 | /* Caller has disabled preemption */ | 169 | /* Caller has disabled preemption */ |
171 | sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS; | 170 | sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS; |
@@ -180,7 +179,8 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, | |||
180 | 179 | ||
181 | f->flush_mm = mm; | 180 | f->flush_mm = mm; |
182 | f->flush_va = va; | 181 | f->flush_va = va; |
183 | cpus_or(f->flush_cpumask, cpumask, f->flush_cpumask); | 182 | cpumask_andnot(to_cpumask(f->flush_cpumask), |
183 | cpumask, cpumask_of(smp_processor_id())); | ||
184 | 184 | ||
185 | /* | 185 | /* |
186 | * Make the above memory operations globally visible before | 186 | * Make the above memory operations globally visible before |
@@ -191,9 +191,10 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, | |||
191 | * We have to send the IPI only to | 191 | * We have to send the IPI only to |
192 | * CPUs affected. | 192 | * CPUs affected. |
193 | */ | 193 | */ |
194 | send_IPI_mask(&cpumask, INVALIDATE_TLB_VECTOR_START + sender); | 194 | send_IPI_mask(to_cpumask(f->flush_cpumask), |
195 | INVALIDATE_TLB_VECTOR_START + sender); | ||
195 | 196 | ||
196 | while (!cpus_empty(f->flush_cpumask)) | 197 | while (!cpumask_empty(to_cpumask(f->flush_cpumask))) |
197 | cpu_relax(); | 198 | cpu_relax(); |
198 | 199 | ||
199 | f->flush_mm = NULL; | 200 | f->flush_mm = NULL; |
@@ -201,6 +202,25 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, | |||
201 | spin_unlock(&f->tlbstate_lock); | 202 | spin_unlock(&f->tlbstate_lock); |
202 | } | 203 | } |
203 | 204 | ||
205 | void native_flush_tlb_others(const struct cpumask *cpumask, | ||
206 | struct mm_struct *mm, unsigned long va) | ||
207 | { | ||
208 | if (is_uv_system()) { | ||
209 | /* FIXME: could be an percpu_alloc'd thing */ | ||
210 | static DEFINE_PER_CPU(cpumask_t, flush_tlb_mask); | ||
211 | struct cpumask *after_uv_flush = &get_cpu_var(flush_tlb_mask); | ||
212 | |||
213 | cpumask_andnot(after_uv_flush, cpumask, | ||
214 | cpumask_of(smp_processor_id())); | ||
215 | if (!uv_flush_tlb_others(after_uv_flush, mm, va)) | ||
216 | flush_tlb_others_ipi(after_uv_flush, mm, va); | ||
217 | |||
218 | put_cpu_var(flush_tlb_uv_cpumask); | ||
219 | return; | ||
220 | } | ||
221 | flush_tlb_others_ipi(cpumask, mm, va); | ||
222 | } | ||
223 | |||
204 | static int __cpuinit init_smp_flush(void) | 224 | static int __cpuinit init_smp_flush(void) |
205 | { | 225 | { |
206 | int i; | 226 | int i; |
@@ -215,25 +235,18 @@ core_initcall(init_smp_flush); | |||
215 | void flush_tlb_current_task(void) | 235 | void flush_tlb_current_task(void) |
216 | { | 236 | { |
217 | struct mm_struct *mm = current->mm; | 237 | struct mm_struct *mm = current->mm; |
218 | cpumask_t cpu_mask; | ||
219 | 238 | ||
220 | preempt_disable(); | 239 | preempt_disable(); |
221 | cpu_mask = mm->cpu_vm_mask; | ||
222 | cpu_clear(smp_processor_id(), cpu_mask); | ||
223 | 240 | ||
224 | local_flush_tlb(); | 241 | local_flush_tlb(); |
225 | if (!cpus_empty(cpu_mask)) | 242 | if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids) |
226 | flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); | 243 | flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL); |
227 | preempt_enable(); | 244 | preempt_enable(); |
228 | } | 245 | } |
229 | 246 | ||
230 | void flush_tlb_mm(struct mm_struct *mm) | 247 | void flush_tlb_mm(struct mm_struct *mm) |
231 | { | 248 | { |
232 | cpumask_t cpu_mask; | ||
233 | |||
234 | preempt_disable(); | 249 | preempt_disable(); |
235 | cpu_mask = mm->cpu_vm_mask; | ||
236 | cpu_clear(smp_processor_id(), cpu_mask); | ||
237 | 250 | ||
238 | if (current->active_mm == mm) { | 251 | if (current->active_mm == mm) { |
239 | if (current->mm) | 252 | if (current->mm) |
@@ -241,8 +254,8 @@ void flush_tlb_mm(struct mm_struct *mm) | |||
241 | else | 254 | else |
242 | leave_mm(smp_processor_id()); | 255 | leave_mm(smp_processor_id()); |
243 | } | 256 | } |
244 | if (!cpus_empty(cpu_mask)) | 257 | if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids) |
245 | flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); | 258 | flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL); |
246 | 259 | ||
247 | preempt_enable(); | 260 | preempt_enable(); |
248 | } | 261 | } |
@@ -250,11 +263,8 @@ void flush_tlb_mm(struct mm_struct *mm) | |||
250 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) | 263 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) |
251 | { | 264 | { |
252 | struct mm_struct *mm = vma->vm_mm; | 265 | struct mm_struct *mm = vma->vm_mm; |
253 | cpumask_t cpu_mask; | ||
254 | 266 | ||
255 | preempt_disable(); | 267 | preempt_disable(); |
256 | cpu_mask = mm->cpu_vm_mask; | ||
257 | cpu_clear(smp_processor_id(), cpu_mask); | ||
258 | 268 | ||
259 | if (current->active_mm == mm) { | 269 | if (current->active_mm == mm) { |
260 | if (current->mm) | 270 | if (current->mm) |
@@ -263,8 +273,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) | |||
263 | leave_mm(smp_processor_id()); | 273 | leave_mm(smp_processor_id()); |
264 | } | 274 | } |
265 | 275 | ||
266 | if (!cpus_empty(cpu_mask)) | 276 | if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids) |
267 | flush_tlb_others(cpu_mask, mm, va); | 277 | flush_tlb_others(&mm->cpu_vm_mask, mm, va); |
268 | 278 | ||
269 | preempt_enable(); | 279 | preempt_enable(); |
270 | } | 280 | } |
@@ -274,7 +284,7 @@ static void do_flush_tlb_all(void *info) | |||
274 | unsigned long cpu = smp_processor_id(); | 284 | unsigned long cpu = smp_processor_id(); |
275 | 285 | ||
276 | __flush_tlb_all(); | 286 | __flush_tlb_all(); |
277 | if (read_pda(mmu_state) == TLBSTATE_LAZY) | 287 | if (percpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY) |
278 | leave_mm(cpu); | 288 | leave_mm(cpu); |
279 | } | 289 | } |
280 | 290 | ||