aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/tlb_64.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2009-01-11 00:58:09 -0500
committerIngo Molnar <mingo@elte.hu>2009-01-11 13:13:06 -0500
commit4595f9620cda8a1e973588e743cf5f8436dd20c6 (patch)
tree98a47cff17f58262979c7d04590cb3ffc0deead9 /arch/x86/kernel/tlb_64.c
parent802bf931f2688ad125b73db597ce63cc842fb27a (diff)
x86: change flush_tlb_others to take a const struct cpumask
Impact: reduce stack usage, use new cpumask API. This is made a little more tricky by uv_flush_tlb_others which actually alters its argument, for an IPI to be sent to the remaining cpus in the mask. I solve this by allocating a cpumask_var_t for this case and falling back to IPI should this fail. To eliminate temporaries in the caller, all flush_tlb_others implementations now do the this-cpu-elimination step themselves. Note also the curious "cpus_or(f->flush_cpumask, cpumask, f->flush_cpumask)" which has been there since pre-git and yet f->flush_cpumask is always zero at this point. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Mike Travis <travis@sgi.com>
Diffstat (limited to 'arch/x86/kernel/tlb_64.c')
-rw-r--r--arch/x86/kernel/tlb_64.c61
1 files changed, 33 insertions, 28 deletions
diff --git a/arch/x86/kernel/tlb_64.c b/arch/x86/kernel/tlb_64.c
index f8be6f1d2e48..38836aef51b4 100644
--- a/arch/x86/kernel/tlb_64.c
+++ b/arch/x86/kernel/tlb_64.c
@@ -43,10 +43,10 @@
43 43
44union smp_flush_state { 44union smp_flush_state {
45 struct { 45 struct {
46 cpumask_t flush_cpumask;
47 struct mm_struct *flush_mm; 46 struct mm_struct *flush_mm;
48 unsigned long flush_va; 47 unsigned long flush_va;
49 spinlock_t tlbstate_lock; 48 spinlock_t tlbstate_lock;
49 DECLARE_BITMAP(flush_cpumask, NR_CPUS);
50 }; 50 };
51 char pad[SMP_CACHE_BYTES]; 51 char pad[SMP_CACHE_BYTES];
52} ____cacheline_aligned; 52} ____cacheline_aligned;
@@ -131,7 +131,7 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs)
131 sender = ~regs->orig_ax - INVALIDATE_TLB_VECTOR_START; 131 sender = ~regs->orig_ax - INVALIDATE_TLB_VECTOR_START;
132 f = &per_cpu(flush_state, sender); 132 f = &per_cpu(flush_state, sender);
133 133
134 if (!cpu_isset(cpu, f->flush_cpumask)) 134 if (!cpumask_test_cpu(cpu, to_cpumask(f->flush_cpumask)))
135 goto out; 135 goto out;
136 /* 136 /*
137 * This was a BUG() but until someone can quote me the 137 * This was a BUG() but until someone can quote me the
@@ -153,19 +153,15 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs)
153 } 153 }
154out: 154out:
155 ack_APIC_irq(); 155 ack_APIC_irq();
156 cpu_clear(cpu, f->flush_cpumask); 156 cpumask_clear_cpu(cpu, to_cpumask(f->flush_cpumask));
157 inc_irq_stat(irq_tlb_count); 157 inc_irq_stat(irq_tlb_count);
158} 158}
159 159
160void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, 160static void flush_tlb_others_ipi(const struct cpumask *cpumask,
161 unsigned long va) 161 struct mm_struct *mm, unsigned long va)
162{ 162{
163 int sender; 163 int sender;
164 union smp_flush_state *f; 164 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 165
170 /* Caller has disabled preemption */ 166 /* Caller has disabled preemption */
171 sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS; 167 sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS;
@@ -180,7 +176,8 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
180 176
181 f->flush_mm = mm; 177 f->flush_mm = mm;
182 f->flush_va = va; 178 f->flush_va = va;
183 cpus_or(f->flush_cpumask, cpumask, f->flush_cpumask); 179 cpumask_andnot(to_cpumask(f->flush_cpumask),
180 cpumask, cpumask_of(smp_processor_id()));
184 181
185 /* 182 /*
186 * Make the above memory operations globally visible before 183 * Make the above memory operations globally visible before
@@ -191,9 +188,9 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
191 * We have to send the IPI only to 188 * We have to send the IPI only to
192 * CPUs affected. 189 * CPUs affected.
193 */ 190 */
194 send_IPI_mask(&cpumask, INVALIDATE_TLB_VECTOR_START + sender); 191 send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR_START + sender);
195 192
196 while (!cpus_empty(f->flush_cpumask)) 193 while (!cpumask_empty(to_cpumask(f->flush_cpumask)))
197 cpu_relax(); 194 cpu_relax();
198 195
199 f->flush_mm = NULL; 196 f->flush_mm = NULL;
@@ -201,6 +198,24 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
201 spin_unlock(&f->tlbstate_lock); 198 spin_unlock(&f->tlbstate_lock);
202} 199}
203 200
201void native_flush_tlb_others(const struct cpumask *cpumask,
202 struct mm_struct *mm, unsigned long va)
203{
204 if (is_uv_system()) {
205 cpumask_var_t after_uv_flush;
206
207 if (alloc_cpumask_var(&after_uv_flush, GFP_ATOMIC)) {
208 cpumask_andnot(after_uv_flush,
209 cpumask, cpumask_of(smp_processor_id()));
210 if (!uv_flush_tlb_others(after_uv_flush, mm, va))
211 flush_tlb_others_ipi(after_uv_flush, mm, va);
212 free_cpumask_var(after_uv_flush);
213 return;
214 }
215 }
216 flush_tlb_others_ipi(cpumask, mm, va);
217}
218
204static int __cpuinit init_smp_flush(void) 219static int __cpuinit init_smp_flush(void)
205{ 220{
206 int i; 221 int i;
@@ -215,25 +230,18 @@ core_initcall(init_smp_flush);
215void flush_tlb_current_task(void) 230void flush_tlb_current_task(void)
216{ 231{
217 struct mm_struct *mm = current->mm; 232 struct mm_struct *mm = current->mm;
218 cpumask_t cpu_mask;
219 233
220 preempt_disable(); 234 preempt_disable();
221 cpu_mask = mm->cpu_vm_mask;
222 cpu_clear(smp_processor_id(), cpu_mask);
223 235
224 local_flush_tlb(); 236 local_flush_tlb();
225 if (!cpus_empty(cpu_mask)) 237 if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids)
226 flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); 238 flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL);
227 preempt_enable(); 239 preempt_enable();
228} 240}
229 241
230void flush_tlb_mm(struct mm_struct *mm) 242void flush_tlb_mm(struct mm_struct *mm)
231{ 243{
232 cpumask_t cpu_mask;
233
234 preempt_disable(); 244 preempt_disable();
235 cpu_mask = mm->cpu_vm_mask;
236 cpu_clear(smp_processor_id(), cpu_mask);
237 245
238 if (current->active_mm == mm) { 246 if (current->active_mm == mm) {
239 if (current->mm) 247 if (current->mm)
@@ -241,8 +249,8 @@ void flush_tlb_mm(struct mm_struct *mm)
241 else 249 else
242 leave_mm(smp_processor_id()); 250 leave_mm(smp_processor_id());
243 } 251 }
244 if (!cpus_empty(cpu_mask)) 252 if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids)
245 flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); 253 flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL);
246 254
247 preempt_enable(); 255 preempt_enable();
248} 256}
@@ -250,11 +258,8 @@ void flush_tlb_mm(struct mm_struct *mm)
250void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) 258void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
251{ 259{
252 struct mm_struct *mm = vma->vm_mm; 260 struct mm_struct *mm = vma->vm_mm;
253 cpumask_t cpu_mask;
254 261
255 preempt_disable(); 262 preempt_disable();
256 cpu_mask = mm->cpu_vm_mask;
257 cpu_clear(smp_processor_id(), cpu_mask);
258 263
259 if (current->active_mm == mm) { 264 if (current->active_mm == mm) {
260 if (current->mm) 265 if (current->mm)
@@ -263,8 +268,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
263 leave_mm(smp_processor_id()); 268 leave_mm(smp_processor_id());
264 } 269 }
265 270
266 if (!cpus_empty(cpu_mask)) 271 if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids)
267 flush_tlb_others(cpu_mask, mm, va); 272 flush_tlb_others(&mm->cpu_vm_mask, mm, va);
268 273
269 preempt_enable(); 274 preempt_enable();
270} 275}