diff options
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/smp.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index cefeee81c52e..be35ffae10f0 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -76,6 +76,8 @@ void smp_call_function_interrupt(void); | |||
76 | 76 | ||
77 | int smt_enabled_at_boot = 1; | 77 | int smt_enabled_at_boot = 1; |
78 | 78 | ||
79 | static int ipi_fail_ok; | ||
80 | |||
79 | static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; | 81 | static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; |
80 | 82 | ||
81 | #ifdef CONFIG_PPC64 | 83 | #ifdef CONFIG_PPC64 |
@@ -204,8 +206,6 @@ static int __smp_call_function_map(void (*func) (void *info), void *info, | |||
204 | if (wait) | 206 | if (wait) |
205 | atomic_set(&data.finished, 0); | 207 | atomic_set(&data.finished, 0); |
206 | 208 | ||
207 | spin_lock(&call_lock); | ||
208 | |||
209 | /* remove 'self' from the map */ | 209 | /* remove 'self' from the map */ |
210 | if (cpu_isset(smp_processor_id(), map)) | 210 | if (cpu_isset(smp_processor_id(), map)) |
211 | cpu_clear(smp_processor_id(), map); | 211 | cpu_clear(smp_processor_id(), map); |
@@ -232,7 +232,8 @@ static int __smp_call_function_map(void (*func) (void *info), void *info, | |||
232 | printk("smp_call_function on cpu %d: other cpus not " | 232 | printk("smp_call_function on cpu %d: other cpus not " |
233 | "responding (%d)\n", smp_processor_id(), | 233 | "responding (%d)\n", smp_processor_id(), |
234 | atomic_read(&data.started)); | 234 | atomic_read(&data.started)); |
235 | debugger(NULL); | 235 | if (!ipi_fail_ok) |
236 | debugger(NULL); | ||
236 | goto out; | 237 | goto out; |
237 | } | 238 | } |
238 | } | 239 | } |
@@ -259,15 +260,18 @@ static int __smp_call_function_map(void (*func) (void *info), void *info, | |||
259 | out: | 260 | out: |
260 | call_data = NULL; | 261 | call_data = NULL; |
261 | HMT_medium(); | 262 | HMT_medium(); |
262 | spin_unlock(&call_lock); | ||
263 | return ret; | 263 | return ret; |
264 | } | 264 | } |
265 | 265 | ||
266 | static int __smp_call_function(void (*func)(void *info), void *info, | 266 | static int __smp_call_function(void (*func)(void *info), void *info, |
267 | int nonatomic, int wait) | 267 | int nonatomic, int wait) |
268 | { | 268 | { |
269 | return __smp_call_function_map(func, info, nonatomic, wait, | 269 | int ret; |
270 | spin_lock(&call_lock); | ||
271 | ret =__smp_call_function_map(func, info, nonatomic, wait, | ||
270 | cpu_online_map); | 272 | cpu_online_map); |
273 | spin_unlock(&call_lock); | ||
274 | return ret; | ||
271 | } | 275 | } |
272 | 276 | ||
273 | int smp_call_function(void (*func) (void *info), void *info, int nonatomic, | 277 | int smp_call_function(void (*func) (void *info), void *info, int nonatomic, |
@@ -293,9 +297,11 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | |||
293 | return -EINVAL; | 297 | return -EINVAL; |
294 | 298 | ||
295 | cpu_set(cpu, map); | 299 | cpu_set(cpu, map); |
296 | if (cpu != get_cpu()) | 300 | if (cpu != get_cpu()) { |
301 | spin_lock(&call_lock); | ||
297 | ret = __smp_call_function_map(func, info, nonatomic, wait, map); | 302 | ret = __smp_call_function_map(func, info, nonatomic, wait, map); |
298 | else { | 303 | spin_unlock(&call_lock); |
304 | } else { | ||
299 | local_irq_disable(); | 305 | local_irq_disable(); |
300 | func(info); | 306 | func(info); |
301 | local_irq_enable(); | 307 | local_irq_enable(); |
@@ -307,7 +313,22 @@ EXPORT_SYMBOL(smp_call_function_single); | |||
307 | 313 | ||
308 | void smp_send_stop(void) | 314 | void smp_send_stop(void) |
309 | { | 315 | { |
310 | __smp_call_function(stop_this_cpu, NULL, 1, 0); | 316 | int nolock; |
317 | |||
318 | /* It's OK to fail sending the IPI, since the alternative is to | ||
319 | * be stuck forever waiting on the other CPU to take the interrupt. | ||
320 | * | ||
321 | * It's better to at least continue and go through reboot, since this | ||
322 | * function is usually called at panic or reboot time in the first | ||
323 | * place. | ||
324 | */ | ||
325 | ipi_fail_ok = 1; | ||
326 | |||
327 | /* Don't deadlock in case we got called through panic */ | ||
328 | nolock = !spin_trylock(&call_lock); | ||
329 | __smp_call_function_map(stop_this_cpu, NULL, 1, 0, cpu_online_map); | ||
330 | if (!nolock) | ||
331 | spin_unlock(&call_lock); | ||
311 | } | 332 | } |
312 | 333 | ||
313 | void smp_call_function_interrupt(void) | 334 | void smp_call_function_interrupt(void) |