Commit 80a8c9ff authored by Andi Kleen's avatar Andi Kleen Committed by Ingo Molnar

x86: fix oprofile + hibernation badness

Vegard Nossum reported oprofile + hibernation problems:

> Now some warnings:
>
> ------------[ cut here ]------------
> WARNING: at /uio/arkimedes/s29/vegardno/git-working/linux-2.6/kernel/smp.c:328 s
> mp_call_function_mask+0x194/0x1a0()

The usual problem: the suspend function when interrupts are
already disabled calls smp_call_function which is not allowed with
interrupt off. But at this point all the other CPUs should be already
down anyways, so it should be enough to just drop that.

This patch should fix that problem at least by fixing cpu hotplug&
suspend support.

[ mingo@elte.hu: fixed 5 coding style errors. ]
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Tested-by: default avatarVegard Nossum <vegard.nossum@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 99dd8713
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/cpu.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/apic.h> #include <asm/apic.h>
...@@ -28,23 +29,48 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); ...@@ -28,23 +29,48 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
static int nmi_start(void); static int nmi_start(void);
static void nmi_stop(void); static void nmi_stop(void);
static void nmi_cpu_start(void *dummy);
static void nmi_cpu_stop(void *dummy);
/* 0 == registered but off, 1 == registered and on */ /* 0 == registered but off, 1 == registered and on */
static int nmi_enabled = 0; static int nmi_enabled = 0;
#ifdef CONFIG_SMP
static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action,
void *data)
{
int cpu = (unsigned long)data;
switch (action) {
case CPU_DOWN_FAILED:
case CPU_ONLINE:
smp_call_function_single(cpu, nmi_cpu_start, NULL, 0);
break;
case CPU_DOWN_PREPARE:
smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1);
break;
}
return NOTIFY_DONE;
}
static struct notifier_block oprofile_cpu_nb = {
.notifier_call = oprofile_cpu_notifier
};
#endif
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int nmi_suspend(struct sys_device *dev, pm_message_t state) static int nmi_suspend(struct sys_device *dev, pm_message_t state)
{ {
/* Only one CPU left, just stop that one */
if (nmi_enabled == 1) if (nmi_enabled == 1)
nmi_stop(); nmi_cpu_stop(NULL);
return 0; return 0;
} }
static int nmi_resume(struct sys_device *dev) static int nmi_resume(struct sys_device *dev)
{ {
if (nmi_enabled == 1) if (nmi_enabled == 1)
nmi_start(); nmi_cpu_start(NULL);
return 0; return 0;
} }
...@@ -463,6 +489,9 @@ int __init op_nmi_init(struct oprofile_operations *ops) ...@@ -463,6 +489,9 @@ int __init op_nmi_init(struct oprofile_operations *ops)
} }
init_sysfs(); init_sysfs();
#ifdef CONFIG_SMP
register_cpu_notifier(&oprofile_cpu_nb);
#endif
using_nmi = 1; using_nmi = 1;
ops->create_files = nmi_create_files; ops->create_files = nmi_create_files;
ops->setup = nmi_setup; ops->setup = nmi_setup;
...@@ -476,6 +505,10 @@ int __init op_nmi_init(struct oprofile_operations *ops) ...@@ -476,6 +505,10 @@ int __init op_nmi_init(struct oprofile_operations *ops)
void op_nmi_exit(void) void op_nmi_exit(void)
{ {
if (using_nmi) if (using_nmi) {
exit_sysfs(); exit_sysfs();
#ifdef CONFIG_SMP
unregister_cpu_notifier(&oprofile_cpu_nb);
#endif
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment