diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2009-01-11 00:58:09 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-11 13:13:06 -0500 |
commit | 4595f9620cda8a1e973588e743cf5f8436dd20c6 (patch) | |
tree | 98a47cff17f58262979c7d04590cb3ffc0deead9 /arch/x86/kernel/tlb_64.c | |
parent | 802bf931f2688ad125b73db597ce63cc842fb27a (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.c | 61 |
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 | ||
44 | union smp_flush_state { | 44 | union 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 | } |
154 | out: | 154 | out: |
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 | ||
160 | void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, | 160 | static 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 | ||
201 | void 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 | |||
204 | static int __cpuinit init_smp_flush(void) | 219 | static int __cpuinit init_smp_flush(void) |
205 | { | 220 | { |
206 | int i; | 221 | int i; |
@@ -215,25 +230,18 @@ core_initcall(init_smp_flush); | |||
215 | void flush_tlb_current_task(void) | 230 | void 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 | ||
230 | void flush_tlb_mm(struct mm_struct *mm) | 242 | void 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) | |||
250 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) | 258 | void 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 | } |