Commit 31a6b11fed6ceec07ec4bdfefae56b8252d450cf
Committed by
Tony Luck
1 parent
96651896b8
Exists in
master
and in
7 other branches
[IA64] Implement smp_call_function_mask for ia64
This interface provides more flexible functionality for smp infrastructure ... e.g. KVM frequently needs to operate on a subset of cpus. Signed-off-by: Xiantao Zhang <xiantao.zhang@intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Showing 2 changed files with 85 additions and 0 deletions Inline Diff
arch/ia64/kernel/smp.c
1 | /* | 1 | /* |
2 | * SMP Support | 2 | * SMP Support |
3 | * | 3 | * |
4 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> | 4 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> |
5 | * Copyright (C) 1999, 2001, 2003 David Mosberger-Tang <davidm@hpl.hp.com> | 5 | * Copyright (C) 1999, 2001, 2003 David Mosberger-Tang <davidm@hpl.hp.com> |
6 | * | 6 | * |
7 | * Lots of stuff stolen from arch/alpha/kernel/smp.c | 7 | * Lots of stuff stolen from arch/alpha/kernel/smp.c |
8 | * | 8 | * |
9 | * 01/05/16 Rohit Seth <rohit.seth@intel.com> IA64-SMP functions. Reorganized | 9 | * 01/05/16 Rohit Seth <rohit.seth@intel.com> IA64-SMP functions. Reorganized |
10 | * the existing code (on the lines of x86 port). | 10 | * the existing code (on the lines of x86 port). |
11 | * 00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_jiffy | 11 | * 00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_jiffy |
12 | * calibration on each CPU. | 12 | * calibration on each CPU. |
13 | * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> fixed logical processor id | 13 | * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> fixed logical processor id |
14 | * 00/03/31 Rohit Seth <rohit.seth@intel.com> Fixes for Bootstrap Processor | 14 | * 00/03/31 Rohit Seth <rohit.seth@intel.com> Fixes for Bootstrap Processor |
15 | * & cpu_online_map now gets done here (instead of setup.c) | 15 | * & cpu_online_map now gets done here (instead of setup.c) |
16 | * 99/10/05 davidm Update to bring it in sync with new command-line processing | 16 | * 99/10/05 davidm Update to bring it in sync with new command-line processing |
17 | * scheme. | 17 | * scheme. |
18 | * 10/13/00 Goutham Rao <goutham.rao@intel.com> Updated smp_call_function and | 18 | * 10/13/00 Goutham Rao <goutham.rao@intel.com> Updated smp_call_function and |
19 | * smp_call_function_single to resend IPI on timeouts | 19 | * smp_call_function_single to resend IPI on timeouts |
20 | */ | 20 | */ |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/smp.h> | 26 | #include <linux/smp.h> |
27 | #include <linux/kernel_stat.h> | 27 | #include <linux/kernel_stat.h> |
28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
29 | #include <linux/cache.h> | 29 | #include <linux/cache.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/efi.h> | 31 | #include <linux/efi.h> |
32 | #include <linux/bitops.h> | 32 | #include <linux/bitops.h> |
33 | #include <linux/kexec.h> | 33 | #include <linux/kexec.h> |
34 | 34 | ||
35 | #include <asm/atomic.h> | 35 | #include <asm/atomic.h> |
36 | #include <asm/current.h> | 36 | #include <asm/current.h> |
37 | #include <asm/delay.h> | 37 | #include <asm/delay.h> |
38 | #include <asm/machvec.h> | 38 | #include <asm/machvec.h> |
39 | #include <asm/io.h> | 39 | #include <asm/io.h> |
40 | #include <asm/irq.h> | 40 | #include <asm/irq.h> |
41 | #include <asm/page.h> | 41 | #include <asm/page.h> |
42 | #include <asm/pgalloc.h> | 42 | #include <asm/pgalloc.h> |
43 | #include <asm/pgtable.h> | 43 | #include <asm/pgtable.h> |
44 | #include <asm/processor.h> | 44 | #include <asm/processor.h> |
45 | #include <asm/ptrace.h> | 45 | #include <asm/ptrace.h> |
46 | #include <asm/sal.h> | 46 | #include <asm/sal.h> |
47 | #include <asm/system.h> | 47 | #include <asm/system.h> |
48 | #include <asm/tlbflush.h> | 48 | #include <asm/tlbflush.h> |
49 | #include <asm/unistd.h> | 49 | #include <asm/unistd.h> |
50 | #include <asm/mca.h> | 50 | #include <asm/mca.h> |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * Note: alignment of 4 entries/cacheline was empirically determined | 53 | * Note: alignment of 4 entries/cacheline was empirically determined |
54 | * to be a good tradeoff between hot cachelines & spreading the array | 54 | * to be a good tradeoff between hot cachelines & spreading the array |
55 | * across too many cacheline. | 55 | * across too many cacheline. |
56 | */ | 56 | */ |
57 | static struct local_tlb_flush_counts { | 57 | static struct local_tlb_flush_counts { |
58 | unsigned int count; | 58 | unsigned int count; |
59 | } __attribute__((__aligned__(32))) local_tlb_flush_counts[NR_CPUS]; | 59 | } __attribute__((__aligned__(32))) local_tlb_flush_counts[NR_CPUS]; |
60 | 60 | ||
61 | static DEFINE_PER_CPU(unsigned int, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned; | 61 | static DEFINE_PER_CPU(unsigned int, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned; |
62 | 62 | ||
63 | 63 | ||
64 | /* | 64 | /* |
65 | * Structure and data for smp_call_function(). This is designed to minimise static memory | 65 | * Structure and data for smp_call_function(). This is designed to minimise static memory |
66 | * requirements. It also looks cleaner. | 66 | * requirements. It also looks cleaner. |
67 | */ | 67 | */ |
68 | static __cacheline_aligned DEFINE_SPINLOCK(call_lock); | 68 | static __cacheline_aligned DEFINE_SPINLOCK(call_lock); |
69 | 69 | ||
70 | struct call_data_struct { | 70 | struct call_data_struct { |
71 | void (*func) (void *info); | 71 | void (*func) (void *info); |
72 | void *info; | 72 | void *info; |
73 | long wait; | 73 | long wait; |
74 | atomic_t started; | 74 | atomic_t started; |
75 | atomic_t finished; | 75 | atomic_t finished; |
76 | }; | 76 | }; |
77 | 77 | ||
78 | static volatile struct call_data_struct *call_data; | 78 | static volatile struct call_data_struct *call_data; |
79 | 79 | ||
80 | #define IPI_CALL_FUNC 0 | 80 | #define IPI_CALL_FUNC 0 |
81 | #define IPI_CPU_STOP 1 | 81 | #define IPI_CPU_STOP 1 |
82 | #define IPI_KDUMP_CPU_STOP 3 | 82 | #define IPI_KDUMP_CPU_STOP 3 |
83 | 83 | ||
84 | /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ | 84 | /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ |
85 | static DEFINE_PER_CPU_SHARED_ALIGNED(u64, ipi_operation); | 85 | static DEFINE_PER_CPU_SHARED_ALIGNED(u64, ipi_operation); |
86 | 86 | ||
87 | extern void cpu_halt (void); | 87 | extern void cpu_halt (void); |
88 | 88 | ||
89 | void | 89 | void |
90 | lock_ipi_calllock(void) | 90 | lock_ipi_calllock(void) |
91 | { | 91 | { |
92 | spin_lock_irq(&call_lock); | 92 | spin_lock_irq(&call_lock); |
93 | } | 93 | } |
94 | 94 | ||
95 | void | 95 | void |
96 | unlock_ipi_calllock(void) | 96 | unlock_ipi_calllock(void) |
97 | { | 97 | { |
98 | spin_unlock_irq(&call_lock); | 98 | spin_unlock_irq(&call_lock); |
99 | } | 99 | } |
100 | 100 | ||
101 | static void | 101 | static void |
102 | stop_this_cpu (void) | 102 | stop_this_cpu (void) |
103 | { | 103 | { |
104 | /* | 104 | /* |
105 | * Remove this CPU: | 105 | * Remove this CPU: |
106 | */ | 106 | */ |
107 | cpu_clear(smp_processor_id(), cpu_online_map); | 107 | cpu_clear(smp_processor_id(), cpu_online_map); |
108 | max_xtp(); | 108 | max_xtp(); |
109 | local_irq_disable(); | 109 | local_irq_disable(); |
110 | cpu_halt(); | 110 | cpu_halt(); |
111 | } | 111 | } |
112 | 112 | ||
113 | void | 113 | void |
114 | cpu_die(void) | 114 | cpu_die(void) |
115 | { | 115 | { |
116 | max_xtp(); | 116 | max_xtp(); |
117 | local_irq_disable(); | 117 | local_irq_disable(); |
118 | cpu_halt(); | 118 | cpu_halt(); |
119 | /* Should never be here */ | 119 | /* Should never be here */ |
120 | BUG(); | 120 | BUG(); |
121 | for (;;); | 121 | for (;;); |
122 | } | 122 | } |
123 | 123 | ||
124 | irqreturn_t | 124 | irqreturn_t |
125 | handle_IPI (int irq, void *dev_id) | 125 | handle_IPI (int irq, void *dev_id) |
126 | { | 126 | { |
127 | int this_cpu = get_cpu(); | 127 | int this_cpu = get_cpu(); |
128 | unsigned long *pending_ipis = &__ia64_per_cpu_var(ipi_operation); | 128 | unsigned long *pending_ipis = &__ia64_per_cpu_var(ipi_operation); |
129 | unsigned long ops; | 129 | unsigned long ops; |
130 | 130 | ||
131 | mb(); /* Order interrupt and bit testing. */ | 131 | mb(); /* Order interrupt and bit testing. */ |
132 | while ((ops = xchg(pending_ipis, 0)) != 0) { | 132 | while ((ops = xchg(pending_ipis, 0)) != 0) { |
133 | mb(); /* Order bit clearing and data access. */ | 133 | mb(); /* Order bit clearing and data access. */ |
134 | do { | 134 | do { |
135 | unsigned long which; | 135 | unsigned long which; |
136 | 136 | ||
137 | which = ffz(~ops); | 137 | which = ffz(~ops); |
138 | ops &= ~(1 << which); | 138 | ops &= ~(1 << which); |
139 | 139 | ||
140 | switch (which) { | 140 | switch (which) { |
141 | case IPI_CALL_FUNC: | 141 | case IPI_CALL_FUNC: |
142 | { | 142 | { |
143 | struct call_data_struct *data; | 143 | struct call_data_struct *data; |
144 | void (*func)(void *info); | 144 | void (*func)(void *info); |
145 | void *info; | 145 | void *info; |
146 | int wait; | 146 | int wait; |
147 | 147 | ||
148 | /* release the 'pointer lock' */ | 148 | /* release the 'pointer lock' */ |
149 | data = (struct call_data_struct *) call_data; | 149 | data = (struct call_data_struct *) call_data; |
150 | func = data->func; | 150 | func = data->func; |
151 | info = data->info; | 151 | info = data->info; |
152 | wait = data->wait; | 152 | wait = data->wait; |
153 | 153 | ||
154 | mb(); | 154 | mb(); |
155 | atomic_inc(&data->started); | 155 | atomic_inc(&data->started); |
156 | /* | 156 | /* |
157 | * At this point the structure may be gone unless | 157 | * At this point the structure may be gone unless |
158 | * wait is true. | 158 | * wait is true. |
159 | */ | 159 | */ |
160 | (*func)(info); | 160 | (*func)(info); |
161 | 161 | ||
162 | /* Notify the sending CPU that the task is done. */ | 162 | /* Notify the sending CPU that the task is done. */ |
163 | mb(); | 163 | mb(); |
164 | if (wait) | 164 | if (wait) |
165 | atomic_inc(&data->finished); | 165 | atomic_inc(&data->finished); |
166 | } | 166 | } |
167 | break; | 167 | break; |
168 | 168 | ||
169 | case IPI_CPU_STOP: | 169 | case IPI_CPU_STOP: |
170 | stop_this_cpu(); | 170 | stop_this_cpu(); |
171 | break; | 171 | break; |
172 | #ifdef CONFIG_KEXEC | 172 | #ifdef CONFIG_KEXEC |
173 | case IPI_KDUMP_CPU_STOP: | 173 | case IPI_KDUMP_CPU_STOP: |
174 | unw_init_running(kdump_cpu_freeze, NULL); | 174 | unw_init_running(kdump_cpu_freeze, NULL); |
175 | break; | 175 | break; |
176 | #endif | 176 | #endif |
177 | default: | 177 | default: |
178 | printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); | 178 | printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); |
179 | break; | 179 | break; |
180 | } | 180 | } |
181 | } while (ops); | 181 | } while (ops); |
182 | mb(); /* Order data access and bit testing. */ | 182 | mb(); /* Order data access and bit testing. */ |
183 | } | 183 | } |
184 | put_cpu(); | 184 | put_cpu(); |
185 | return IRQ_HANDLED; | 185 | return IRQ_HANDLED; |
186 | } | 186 | } |
187 | 187 | ||
188 | /* | 188 | /* |
189 | * Called with preemption disabled. | 189 | * Called with preemption disabled. |
190 | */ | 190 | */ |
191 | static inline void | 191 | static inline void |
192 | send_IPI_single (int dest_cpu, int op) | 192 | send_IPI_single (int dest_cpu, int op) |
193 | { | 193 | { |
194 | set_bit(op, &per_cpu(ipi_operation, dest_cpu)); | 194 | set_bit(op, &per_cpu(ipi_operation, dest_cpu)); |
195 | platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); | 195 | platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); |
196 | } | 196 | } |
197 | 197 | ||
198 | /* | 198 | /* |
199 | * Called with preemption disabled. | 199 | * Called with preemption disabled. |
200 | */ | 200 | */ |
201 | static inline void | 201 | static inline void |
202 | send_IPI_allbutself (int op) | 202 | send_IPI_allbutself (int op) |
203 | { | 203 | { |
204 | unsigned int i; | 204 | unsigned int i; |
205 | 205 | ||
206 | for_each_online_cpu(i) { | 206 | for_each_online_cpu(i) { |
207 | if (i != smp_processor_id()) | 207 | if (i != smp_processor_id()) |
208 | send_IPI_single(i, op); | 208 | send_IPI_single(i, op); |
209 | } | 209 | } |
210 | } | 210 | } |
211 | 211 | ||
212 | /* | 212 | /* |
213 | * Called with preemption disabled. | 213 | * Called with preemption disabled. |
214 | */ | 214 | */ |
215 | static inline void | 215 | static inline void |
216 | send_IPI_mask(cpumask_t mask, int op) | ||
217 | { | ||
218 | unsigned int cpu; | ||
219 | |||
220 | for_each_cpu_mask(cpu, mask) { | ||
221 | send_IPI_single(cpu, op); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Called with preemption disabled. | ||
227 | */ | ||
228 | static inline void | ||
216 | send_IPI_all (int op) | 229 | send_IPI_all (int op) |
217 | { | 230 | { |
218 | int i; | 231 | int i; |
219 | 232 | ||
220 | for_each_online_cpu(i) { | 233 | for_each_online_cpu(i) { |
221 | send_IPI_single(i, op); | 234 | send_IPI_single(i, op); |
222 | } | 235 | } |
223 | } | 236 | } |
224 | 237 | ||
225 | /* | 238 | /* |
226 | * Called with preemption disabled. | 239 | * Called with preemption disabled. |
227 | */ | 240 | */ |
228 | static inline void | 241 | static inline void |
229 | send_IPI_self (int op) | 242 | send_IPI_self (int op) |
230 | { | 243 | { |
231 | send_IPI_single(smp_processor_id(), op); | 244 | send_IPI_single(smp_processor_id(), op); |
232 | } | 245 | } |
233 | 246 | ||
234 | #ifdef CONFIG_KEXEC | 247 | #ifdef CONFIG_KEXEC |
235 | void | 248 | void |
236 | kdump_smp_send_stop(void) | 249 | kdump_smp_send_stop(void) |
237 | { | 250 | { |
238 | send_IPI_allbutself(IPI_KDUMP_CPU_STOP); | 251 | send_IPI_allbutself(IPI_KDUMP_CPU_STOP); |
239 | } | 252 | } |
240 | 253 | ||
241 | void | 254 | void |
242 | kdump_smp_send_init(void) | 255 | kdump_smp_send_init(void) |
243 | { | 256 | { |
244 | unsigned int cpu, self_cpu; | 257 | unsigned int cpu, self_cpu; |
245 | self_cpu = smp_processor_id(); | 258 | self_cpu = smp_processor_id(); |
246 | for_each_online_cpu(cpu) { | 259 | for_each_online_cpu(cpu) { |
247 | if (cpu != self_cpu) { | 260 | if (cpu != self_cpu) { |
248 | if(kdump_status[cpu] == 0) | 261 | if(kdump_status[cpu] == 0) |
249 | platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); | 262 | platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); |
250 | } | 263 | } |
251 | } | 264 | } |
252 | } | 265 | } |
253 | #endif | 266 | #endif |
254 | /* | 267 | /* |
255 | * Called with preemption disabled. | 268 | * Called with preemption disabled. |
256 | */ | 269 | */ |
257 | void | 270 | void |
258 | smp_send_reschedule (int cpu) | 271 | smp_send_reschedule (int cpu) |
259 | { | 272 | { |
260 | platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); | 273 | platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); |
261 | } | 274 | } |
262 | 275 | ||
263 | /* | 276 | /* |
264 | * Called with preemption disabled. | 277 | * Called with preemption disabled. |
265 | */ | 278 | */ |
266 | static void | 279 | static void |
267 | smp_send_local_flush_tlb (int cpu) | 280 | smp_send_local_flush_tlb (int cpu) |
268 | { | 281 | { |
269 | platform_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0); | 282 | platform_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0); |
270 | } | 283 | } |
271 | 284 | ||
272 | void | 285 | void |
273 | smp_local_flush_tlb(void) | 286 | smp_local_flush_tlb(void) |
274 | { | 287 | { |
275 | /* | 288 | /* |
276 | * Use atomic ops. Otherwise, the load/increment/store sequence from | 289 | * Use atomic ops. Otherwise, the load/increment/store sequence from |
277 | * a "++" operation can have the line stolen between the load & store. | 290 | * a "++" operation can have the line stolen between the load & store. |
278 | * The overhead of the atomic op in negligible in this case & offers | 291 | * The overhead of the atomic op in negligible in this case & offers |
279 | * significant benefit for the brief periods where lots of cpus | 292 | * significant benefit for the brief periods where lots of cpus |
280 | * are simultaneously flushing TLBs. | 293 | * are simultaneously flushing TLBs. |
281 | */ | 294 | */ |
282 | ia64_fetchadd(1, &local_tlb_flush_counts[smp_processor_id()].count, acq); | 295 | ia64_fetchadd(1, &local_tlb_flush_counts[smp_processor_id()].count, acq); |
283 | local_flush_tlb_all(); | 296 | local_flush_tlb_all(); |
284 | } | 297 | } |
285 | 298 | ||
286 | #define FLUSH_DELAY 5 /* Usec backoff to eliminate excessive cacheline bouncing */ | 299 | #define FLUSH_DELAY 5 /* Usec backoff to eliminate excessive cacheline bouncing */ |
287 | 300 | ||
288 | void | 301 | void |
289 | smp_flush_tlb_cpumask(cpumask_t xcpumask) | 302 | smp_flush_tlb_cpumask(cpumask_t xcpumask) |
290 | { | 303 | { |
291 | unsigned int *counts = __ia64_per_cpu_var(shadow_flush_counts); | 304 | unsigned int *counts = __ia64_per_cpu_var(shadow_flush_counts); |
292 | cpumask_t cpumask = xcpumask; | 305 | cpumask_t cpumask = xcpumask; |
293 | int mycpu, cpu, flush_mycpu = 0; | 306 | int mycpu, cpu, flush_mycpu = 0; |
294 | 307 | ||
295 | preempt_disable(); | 308 | preempt_disable(); |
296 | mycpu = smp_processor_id(); | 309 | mycpu = smp_processor_id(); |
297 | 310 | ||
298 | for_each_cpu_mask(cpu, cpumask) | 311 | for_each_cpu_mask(cpu, cpumask) |
299 | counts[cpu] = local_tlb_flush_counts[cpu].count; | 312 | counts[cpu] = local_tlb_flush_counts[cpu].count; |
300 | 313 | ||
301 | mb(); | 314 | mb(); |
302 | for_each_cpu_mask(cpu, cpumask) { | 315 | for_each_cpu_mask(cpu, cpumask) { |
303 | if (cpu == mycpu) | 316 | if (cpu == mycpu) |
304 | flush_mycpu = 1; | 317 | flush_mycpu = 1; |
305 | else | 318 | else |
306 | smp_send_local_flush_tlb(cpu); | 319 | smp_send_local_flush_tlb(cpu); |
307 | } | 320 | } |
308 | 321 | ||
309 | if (flush_mycpu) | 322 | if (flush_mycpu) |
310 | smp_local_flush_tlb(); | 323 | smp_local_flush_tlb(); |
311 | 324 | ||
312 | for_each_cpu_mask(cpu, cpumask) | 325 | for_each_cpu_mask(cpu, cpumask) |
313 | while(counts[cpu] == local_tlb_flush_counts[cpu].count) | 326 | while(counts[cpu] == local_tlb_flush_counts[cpu].count) |
314 | udelay(FLUSH_DELAY); | 327 | udelay(FLUSH_DELAY); |
315 | 328 | ||
316 | preempt_enable(); | 329 | preempt_enable(); |
317 | } | 330 | } |
318 | 331 | ||
319 | void | 332 | void |
320 | smp_flush_tlb_all (void) | 333 | smp_flush_tlb_all (void) |
321 | { | 334 | { |
322 | on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1); | 335 | on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1); |
323 | } | 336 | } |
324 | 337 | ||
325 | void | 338 | void |
326 | smp_flush_tlb_mm (struct mm_struct *mm) | 339 | smp_flush_tlb_mm (struct mm_struct *mm) |
327 | { | 340 | { |
328 | preempt_disable(); | 341 | preempt_disable(); |
329 | /* this happens for the common case of a single-threaded fork(): */ | 342 | /* this happens for the common case of a single-threaded fork(): */ |
330 | if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1)) | 343 | if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1)) |
331 | { | 344 | { |
332 | local_finish_flush_tlb_mm(mm); | 345 | local_finish_flush_tlb_mm(mm); |
333 | preempt_enable(); | 346 | preempt_enable(); |
334 | return; | 347 | return; |
335 | } | 348 | } |
336 | 349 | ||
337 | preempt_enable(); | 350 | preempt_enable(); |
338 | /* | 351 | /* |
339 | * We could optimize this further by using mm->cpu_vm_mask to track which CPUs | 352 | * We could optimize this further by using mm->cpu_vm_mask to track which CPUs |
340 | * have been running in the address space. It's not clear that this is worth the | 353 | * have been running in the address space. It's not clear that this is worth the |
341 | * trouble though: to avoid races, we have to raise the IPI on the target CPU | 354 | * trouble though: to avoid races, we have to raise the IPI on the target CPU |
342 | * anyhow, and once a CPU is interrupted, the cost of local_flush_tlb_all() is | 355 | * anyhow, and once a CPU is interrupted, the cost of local_flush_tlb_all() is |
343 | * rather trivial. | 356 | * rather trivial. |
344 | */ | 357 | */ |
345 | on_each_cpu((void (*)(void *))local_finish_flush_tlb_mm, mm, 1, 1); | 358 | on_each_cpu((void (*)(void *))local_finish_flush_tlb_mm, mm, 1, 1); |
346 | } | 359 | } |
347 | 360 | ||
348 | /* | 361 | /* |
349 | * Run a function on a specific CPU | 362 | * Run a function on a specific CPU |
350 | * <func> The function to run. This must be fast and non-blocking. | 363 | * <func> The function to run. This must be fast and non-blocking. |
351 | * <info> An arbitrary pointer to pass to the function. | 364 | * <info> An arbitrary pointer to pass to the function. |
352 | * <nonatomic> Currently unused. | 365 | * <nonatomic> Currently unused. |
353 | * <wait> If true, wait until function has completed on other CPUs. | 366 | * <wait> If true, wait until function has completed on other CPUs. |
354 | * [RETURNS] 0 on success, else a negative status code. | 367 | * [RETURNS] 0 on success, else a negative status code. |
355 | * | 368 | * |
356 | * Does not return until the remote CPU is nearly ready to execute <func> | 369 | * Does not return until the remote CPU is nearly ready to execute <func> |
357 | * or is or has executed. | 370 | * or is or has executed. |
358 | */ | 371 | */ |
359 | 372 | ||
360 | int | 373 | int |
361 | smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int nonatomic, | 374 | smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int nonatomic, |
362 | int wait) | 375 | int wait) |
363 | { | 376 | { |
364 | struct call_data_struct data; | 377 | struct call_data_struct data; |
365 | int cpus = 1; | 378 | int cpus = 1; |
366 | int me = get_cpu(); /* prevent preemption and reschedule on another processor */ | 379 | int me = get_cpu(); /* prevent preemption and reschedule on another processor */ |
367 | 380 | ||
368 | if (cpuid == me) { | 381 | if (cpuid == me) { |
369 | local_irq_disable(); | 382 | local_irq_disable(); |
370 | func(info); | 383 | func(info); |
371 | local_irq_enable(); | 384 | local_irq_enable(); |
372 | put_cpu(); | 385 | put_cpu(); |
373 | return 0; | 386 | return 0; |
374 | } | 387 | } |
375 | 388 | ||
376 | data.func = func; | 389 | data.func = func; |
377 | data.info = info; | 390 | data.info = info; |
378 | atomic_set(&data.started, 0); | 391 | atomic_set(&data.started, 0); |
379 | data.wait = wait; | 392 | data.wait = wait; |
380 | if (wait) | 393 | if (wait) |
381 | atomic_set(&data.finished, 0); | 394 | atomic_set(&data.finished, 0); |
382 | 395 | ||
383 | spin_lock_bh(&call_lock); | 396 | spin_lock_bh(&call_lock); |
384 | 397 | ||
385 | call_data = &data; | 398 | call_data = &data; |
386 | mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ | 399 | mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ |
387 | send_IPI_single(cpuid, IPI_CALL_FUNC); | 400 | send_IPI_single(cpuid, IPI_CALL_FUNC); |
388 | 401 | ||
389 | /* Wait for response */ | 402 | /* Wait for response */ |
390 | while (atomic_read(&data.started) != cpus) | 403 | while (atomic_read(&data.started) != cpus) |
391 | cpu_relax(); | 404 | cpu_relax(); |
392 | 405 | ||
393 | if (wait) | 406 | if (wait) |
394 | while (atomic_read(&data.finished) != cpus) | 407 | while (atomic_read(&data.finished) != cpus) |
395 | cpu_relax(); | 408 | cpu_relax(); |
396 | call_data = NULL; | 409 | call_data = NULL; |
397 | 410 | ||
398 | spin_unlock_bh(&call_lock); | 411 | spin_unlock_bh(&call_lock); |
399 | put_cpu(); | 412 | put_cpu(); |
400 | return 0; | 413 | return 0; |
401 | } | 414 | } |
402 | EXPORT_SYMBOL(smp_call_function_single); | 415 | EXPORT_SYMBOL(smp_call_function_single); |
416 | |||
417 | /** | ||
418 | * smp_call_function_mask(): Run a function on a set of other CPUs. | ||
419 | * <mask> The set of cpus to run on. Must not include the current cpu. | ||
420 | * <func> The function to run. This must be fast and non-blocking. | ||
421 | * <info> An arbitrary pointer to pass to the function. | ||
422 | * <wait> If true, wait (atomically) until function | ||
423 | * has completed on other CPUs. | ||
424 | * | ||
425 | * Returns 0 on success, else a negative status code. | ||
426 | * | ||
427 | * If @wait is true, then returns once @func has returned; otherwise | ||
428 | * it returns just before the target cpu calls @func. | ||
429 | * | ||
430 | * You must not call this function with disabled interrupts or from a | ||
431 | * hardware interrupt handler or from a bottom half handler. | ||
432 | */ | ||
433 | int smp_call_function_mask(cpumask_t mask, | ||
434 | void (*func)(void *), void *info, | ||
435 | int wait) | ||
436 | { | ||
437 | struct call_data_struct data; | ||
438 | cpumask_t allbutself; | ||
439 | int cpus; | ||
440 | |||
441 | spin_lock(&call_lock); | ||
442 | allbutself = cpu_online_map; | ||
443 | cpu_clear(smp_processor_id(), allbutself); | ||
444 | |||
445 | cpus_and(mask, mask, allbutself); | ||
446 | cpus = cpus_weight(mask); | ||
447 | if (!cpus) { | ||
448 | spin_unlock(&call_lock); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | /* Can deadlock when called with interrupts disabled */ | ||
453 | WARN_ON(irqs_disabled()); | ||
454 | |||
455 | data.func = func; | ||
456 | data.info = info; | ||
457 | atomic_set(&data.started, 0); | ||
458 | data.wait = wait; | ||
459 | if (wait) | ||
460 | atomic_set(&data.finished, 0); | ||
461 | |||
462 | call_data = &data; | ||
463 | mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC*/ | ||
464 | |||
465 | /* Send a message to other CPUs */ | ||
466 | if (cpus_equal(mask, allbutself)) | ||
467 | send_IPI_allbutself(IPI_CALL_FUNC); | ||
468 | else | ||
469 | send_IPI_mask(mask, IPI_CALL_FUNC); | ||
470 | |||
471 | /* Wait for response */ | ||
472 | while (atomic_read(&data.started) != cpus) | ||
473 | cpu_relax(); | ||
474 | |||
475 | if (wait) | ||
476 | while (atomic_read(&data.finished) != cpus) | ||
477 | cpu_relax(); | ||
478 | call_data = NULL; | ||
479 | |||
480 | spin_unlock(&call_lock); | ||
481 | return 0; | ||
482 | |||
483 | } | ||
484 | EXPORT_SYMBOL(smp_call_function_mask); | ||
403 | 485 | ||
404 | /* | 486 | /* |
405 | * this function sends a 'generic call function' IPI to all other CPUs | 487 | * this function sends a 'generic call function' IPI to all other CPUs |
406 | * in the system. | 488 | * in the system. |
407 | */ | 489 | */ |
408 | 490 | ||
409 | /* | 491 | /* |
410 | * [SUMMARY] Run a function on all other CPUs. | 492 | * [SUMMARY] Run a function on all other CPUs. |
411 | * <func> The function to run. This must be fast and non-blocking. | 493 | * <func> The function to run. This must be fast and non-blocking. |
412 | * <info> An arbitrary pointer to pass to the function. | 494 | * <info> An arbitrary pointer to pass to the function. |
413 | * <nonatomic> currently unused. | 495 | * <nonatomic> currently unused. |
414 | * <wait> If true, wait (atomically) until function has completed on other CPUs. | 496 | * <wait> If true, wait (atomically) until function has completed on other CPUs. |
415 | * [RETURNS] 0 on success, else a negative status code. | 497 | * [RETURNS] 0 on success, else a negative status code. |
416 | * | 498 | * |
417 | * Does not return until remote CPUs are nearly ready to execute <func> or are or have | 499 | * Does not return until remote CPUs are nearly ready to execute <func> or are or have |
418 | * executed. | 500 | * executed. |
419 | * | 501 | * |
420 | * You must not call this function with disabled interrupts or from a | 502 | * You must not call this function with disabled interrupts or from a |
421 | * hardware interrupt handler or from a bottom half handler. | 503 | * hardware interrupt handler or from a bottom half handler. |
422 | */ | 504 | */ |
423 | int | 505 | int |
424 | smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) | 506 | smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) |
425 | { | 507 | { |
426 | struct call_data_struct data; | 508 | struct call_data_struct data; |
427 | int cpus; | 509 | int cpus; |
428 | 510 | ||
429 | spin_lock(&call_lock); | 511 | spin_lock(&call_lock); |
430 | cpus = num_online_cpus() - 1; | 512 | cpus = num_online_cpus() - 1; |
431 | if (!cpus) { | 513 | if (!cpus) { |
432 | spin_unlock(&call_lock); | 514 | spin_unlock(&call_lock); |
433 | return 0; | 515 | return 0; |
434 | } | 516 | } |
435 | 517 | ||
436 | /* Can deadlock when called with interrupts disabled */ | 518 | /* Can deadlock when called with interrupts disabled */ |
437 | WARN_ON(irqs_disabled()); | 519 | WARN_ON(irqs_disabled()); |
438 | 520 | ||
439 | data.func = func; | 521 | data.func = func; |
440 | data.info = info; | 522 | data.info = info; |
441 | atomic_set(&data.started, 0); | 523 | atomic_set(&data.started, 0); |
442 | data.wait = wait; | 524 | data.wait = wait; |
443 | if (wait) | 525 | if (wait) |
444 | atomic_set(&data.finished, 0); | 526 | atomic_set(&data.finished, 0); |
445 | 527 | ||
446 | call_data = &data; | 528 | call_data = &data; |
447 | mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ | 529 | mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ |
448 | send_IPI_allbutself(IPI_CALL_FUNC); | 530 | send_IPI_allbutself(IPI_CALL_FUNC); |
449 | 531 | ||
450 | /* Wait for response */ | 532 | /* Wait for response */ |
451 | while (atomic_read(&data.started) != cpus) | 533 | while (atomic_read(&data.started) != cpus) |
452 | cpu_relax(); | 534 | cpu_relax(); |
453 | 535 | ||
454 | if (wait) | 536 | if (wait) |
455 | while (atomic_read(&data.finished) != cpus) | 537 | while (atomic_read(&data.finished) != cpus) |
456 | cpu_relax(); | 538 | cpu_relax(); |
457 | call_data = NULL; | 539 | call_data = NULL; |
458 | 540 | ||
459 | spin_unlock(&call_lock); | 541 | spin_unlock(&call_lock); |
460 | return 0; | 542 | return 0; |
461 | } | 543 | } |
462 | EXPORT_SYMBOL(smp_call_function); | 544 | EXPORT_SYMBOL(smp_call_function); |
463 | 545 | ||
464 | /* | 546 | /* |
465 | * this function calls the 'stop' function on all other CPUs in the system. | 547 | * this function calls the 'stop' function on all other CPUs in the system. |
466 | */ | 548 | */ |
467 | void | 549 | void |
468 | smp_send_stop (void) | 550 | smp_send_stop (void) |
469 | { | 551 | { |
470 | send_IPI_allbutself(IPI_CPU_STOP); | 552 | send_IPI_allbutself(IPI_CPU_STOP); |
471 | } | 553 | } |
472 | 554 | ||
473 | int | 555 | int |
474 | setup_profiling_timer (unsigned int multiplier) | 556 | setup_profiling_timer (unsigned int multiplier) |
475 | { | 557 | { |
476 | return -EINVAL; | 558 | return -EINVAL; |
477 | } | 559 | } |
478 | 560 |
include/asm-ia64/smp.h
1 | /* | 1 | /* |
2 | * SMP Support | 2 | * SMP Support |
3 | * | 3 | * |
4 | * Copyright (C) 1999 VA Linux Systems | 4 | * Copyright (C) 1999 VA Linux Systems |
5 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> | 5 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> |
6 | * (c) Copyright 2001-2003, 2005 Hewlett-Packard Development Company, L.P. | 6 | * (c) Copyright 2001-2003, 2005 Hewlett-Packard Development Company, L.P. |
7 | * David Mosberger-Tang <davidm@hpl.hp.com> | 7 | * David Mosberger-Tang <davidm@hpl.hp.com> |
8 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | 8 | * Bjorn Helgaas <bjorn.helgaas@hp.com> |
9 | */ | 9 | */ |
10 | #ifndef _ASM_IA64_SMP_H | 10 | #ifndef _ASM_IA64_SMP_H |
11 | #define _ASM_IA64_SMP_H | 11 | #define _ASM_IA64_SMP_H |
12 | 12 | ||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/threads.h> | 14 | #include <linux/threads.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/cpumask.h> | 16 | #include <linux/cpumask.h> |
17 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
18 | 18 | ||
19 | #include <asm/io.h> | 19 | #include <asm/io.h> |
20 | #include <asm/param.h> | 20 | #include <asm/param.h> |
21 | #include <asm/processor.h> | 21 | #include <asm/processor.h> |
22 | #include <asm/ptrace.h> | 22 | #include <asm/ptrace.h> |
23 | 23 | ||
24 | static inline unsigned int | 24 | static inline unsigned int |
25 | ia64_get_lid (void) | 25 | ia64_get_lid (void) |
26 | { | 26 | { |
27 | union { | 27 | union { |
28 | struct { | 28 | struct { |
29 | unsigned long reserved : 16; | 29 | unsigned long reserved : 16; |
30 | unsigned long eid : 8; | 30 | unsigned long eid : 8; |
31 | unsigned long id : 8; | 31 | unsigned long id : 8; |
32 | unsigned long ignored : 32; | 32 | unsigned long ignored : 32; |
33 | } f; | 33 | } f; |
34 | unsigned long bits; | 34 | unsigned long bits; |
35 | } lid; | 35 | } lid; |
36 | 36 | ||
37 | lid.bits = ia64_getreg(_IA64_REG_CR_LID); | 37 | lid.bits = ia64_getreg(_IA64_REG_CR_LID); |
38 | return lid.f.id << 8 | lid.f.eid; | 38 | return lid.f.id << 8 | lid.f.eid; |
39 | } | 39 | } |
40 | 40 | ||
41 | extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), | ||
42 | void *info, int wait); | ||
43 | |||
41 | #define hard_smp_processor_id() ia64_get_lid() | 44 | #define hard_smp_processor_id() ia64_get_lid() |
42 | 45 | ||
43 | #ifdef CONFIG_SMP | 46 | #ifdef CONFIG_SMP |
44 | 47 | ||
45 | #define XTP_OFFSET 0x1e0008 | 48 | #define XTP_OFFSET 0x1e0008 |
46 | 49 | ||
47 | #define SMP_IRQ_REDIRECTION (1 << 0) | 50 | #define SMP_IRQ_REDIRECTION (1 << 0) |
48 | #define SMP_IPI_REDIRECTION (1 << 1) | 51 | #define SMP_IPI_REDIRECTION (1 << 1) |
49 | 52 | ||
50 | #define raw_smp_processor_id() (current_thread_info()->cpu) | 53 | #define raw_smp_processor_id() (current_thread_info()->cpu) |
51 | 54 | ||
52 | extern struct smp_boot_data { | 55 | extern struct smp_boot_data { |
53 | int cpu_count; | 56 | int cpu_count; |
54 | int cpu_phys_id[NR_CPUS]; | 57 | int cpu_phys_id[NR_CPUS]; |
55 | } smp_boot_data __initdata; | 58 | } smp_boot_data __initdata; |
56 | 59 | ||
57 | extern char no_int_routing __devinitdata; | 60 | extern char no_int_routing __devinitdata; |
58 | 61 | ||
59 | extern cpumask_t cpu_online_map; | 62 | extern cpumask_t cpu_online_map; |
60 | extern cpumask_t cpu_core_map[NR_CPUS]; | 63 | extern cpumask_t cpu_core_map[NR_CPUS]; |
61 | DECLARE_PER_CPU(cpumask_t, cpu_sibling_map); | 64 | DECLARE_PER_CPU(cpumask_t, cpu_sibling_map); |
62 | extern int smp_num_siblings; | 65 | extern int smp_num_siblings; |
63 | extern void __iomem *ipi_base_addr; | 66 | extern void __iomem *ipi_base_addr; |
64 | extern unsigned char smp_int_redirect; | 67 | extern unsigned char smp_int_redirect; |
65 | 68 | ||
66 | extern volatile int ia64_cpu_to_sapicid[]; | 69 | extern volatile int ia64_cpu_to_sapicid[]; |
67 | #define cpu_physical_id(i) ia64_cpu_to_sapicid[i] | 70 | #define cpu_physical_id(i) ia64_cpu_to_sapicid[i] |
68 | 71 | ||
69 | extern unsigned long ap_wakeup_vector; | 72 | extern unsigned long ap_wakeup_vector; |
70 | 73 | ||
71 | /* | 74 | /* |
72 | * Function to map hard smp processor id to logical id. Slow, so don't use this in | 75 | * Function to map hard smp processor id to logical id. Slow, so don't use this in |
73 | * performance-critical code. | 76 | * performance-critical code. |
74 | */ | 77 | */ |
75 | static inline int | 78 | static inline int |
76 | cpu_logical_id (int cpuid) | 79 | cpu_logical_id (int cpuid) |
77 | { | 80 | { |
78 | int i; | 81 | int i; |
79 | 82 | ||
80 | for (i = 0; i < NR_CPUS; ++i) | 83 | for (i = 0; i < NR_CPUS; ++i) |
81 | if (cpu_physical_id(i) == cpuid) | 84 | if (cpu_physical_id(i) == cpuid) |
82 | break; | 85 | break; |
83 | return i; | 86 | return i; |
84 | } | 87 | } |
85 | 88 | ||
86 | /* | 89 | /* |
87 | * XTP control functions: | 90 | * XTP control functions: |
88 | * min_xtp : route all interrupts to this CPU | 91 | * min_xtp : route all interrupts to this CPU |
89 | * normal_xtp: nominal XTP value | 92 | * normal_xtp: nominal XTP value |
90 | * max_xtp : never deliver interrupts to this CPU. | 93 | * max_xtp : never deliver interrupts to this CPU. |
91 | */ | 94 | */ |
92 | 95 | ||
93 | static inline void | 96 | static inline void |
94 | min_xtp (void) | 97 | min_xtp (void) |
95 | { | 98 | { |
96 | if (smp_int_redirect & SMP_IRQ_REDIRECTION) | 99 | if (smp_int_redirect & SMP_IRQ_REDIRECTION) |
97 | writeb(0x00, ipi_base_addr + XTP_OFFSET); /* XTP to min */ | 100 | writeb(0x00, ipi_base_addr + XTP_OFFSET); /* XTP to min */ |
98 | } | 101 | } |
99 | 102 | ||
100 | static inline void | 103 | static inline void |
101 | normal_xtp (void) | 104 | normal_xtp (void) |
102 | { | 105 | { |
103 | if (smp_int_redirect & SMP_IRQ_REDIRECTION) | 106 | if (smp_int_redirect & SMP_IRQ_REDIRECTION) |
104 | writeb(0x08, ipi_base_addr + XTP_OFFSET); /* XTP normal */ | 107 | writeb(0x08, ipi_base_addr + XTP_OFFSET); /* XTP normal */ |
105 | } | 108 | } |
106 | 109 | ||
107 | static inline void | 110 | static inline void |
108 | max_xtp (void) | 111 | max_xtp (void) |
109 | { | 112 | { |
110 | if (smp_int_redirect & SMP_IRQ_REDIRECTION) | 113 | if (smp_int_redirect & SMP_IRQ_REDIRECTION) |
111 | writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */ | 114 | writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */ |
112 | } | 115 | } |
113 | 116 | ||
114 | /* Upping and downing of CPUs */ | 117 | /* Upping and downing of CPUs */ |
115 | extern int __cpu_disable (void); | 118 | extern int __cpu_disable (void); |
116 | extern void __cpu_die (unsigned int cpu); | 119 | extern void __cpu_die (unsigned int cpu); |
117 | extern void cpu_die (void) __attribute__ ((noreturn)); | 120 | extern void cpu_die (void) __attribute__ ((noreturn)); |
118 | extern void __init smp_build_cpu_map(void); | 121 | extern void __init smp_build_cpu_map(void); |
119 | 122 | ||
120 | extern void __init init_smp_config (void); | 123 | extern void __init init_smp_config (void); |
121 | extern void smp_do_timer (struct pt_regs *regs); | 124 | extern void smp_do_timer (struct pt_regs *regs); |
122 | 125 | ||
123 | extern void smp_send_reschedule (int cpu); | 126 | extern void smp_send_reschedule (int cpu); |
124 | extern void lock_ipi_calllock(void); | 127 | extern void lock_ipi_calllock(void); |
125 | extern void unlock_ipi_calllock(void); | 128 | extern void unlock_ipi_calllock(void); |
126 | extern void identify_siblings (struct cpuinfo_ia64 *); | 129 | extern void identify_siblings (struct cpuinfo_ia64 *); |
127 | extern int is_multithreading_enabled(void); | 130 | extern int is_multithreading_enabled(void); |
128 | 131 | ||
129 | #else /* CONFIG_SMP */ | 132 | #else /* CONFIG_SMP */ |
130 | 133 | ||
131 | #define cpu_logical_id(i) 0 | 134 | #define cpu_logical_id(i) 0 |
132 | #define cpu_physical_id(i) ia64_get_lid() | 135 | #define cpu_physical_id(i) ia64_get_lid() |
133 | 136 | ||
134 | #endif /* CONFIG_SMP */ | 137 | #endif /* CONFIG_SMP */ |
135 | #endif /* _ASM_IA64_SMP_H */ | 138 | #endif /* _ASM_IA64_SMP_H */ |
136 | 139 |