diff options
Diffstat (limited to 'arch/x86/oprofile/nmi_int.c')
-rw-r--r-- | arch/x86/oprofile/nmi_int.c | 75 |
1 files changed, 61 insertions, 14 deletions
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 7f3329b55d2e..0227694f7dab 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/moduleparam.h> | 16 | #include <linux/moduleparam.h> |
17 | #include <linux/kdebug.h> | 17 | #include <linux/kdebug.h> |
18 | #include <linux/cpu.h> | ||
18 | #include <asm/nmi.h> | 19 | #include <asm/nmi.h> |
19 | #include <asm/msr.h> | 20 | #include <asm/msr.h> |
20 | #include <asm/apic.h> | 21 | #include <asm/apic.h> |
@@ -28,23 +29,48 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); | |||
28 | 29 | ||
29 | static int nmi_start(void); | 30 | static int nmi_start(void); |
30 | static void nmi_stop(void); | 31 | static void nmi_stop(void); |
32 | static void nmi_cpu_start(void *dummy); | ||
33 | static void nmi_cpu_stop(void *dummy); | ||
31 | 34 | ||
32 | /* 0 == registered but off, 1 == registered and on */ | 35 | /* 0 == registered but off, 1 == registered and on */ |
33 | static int nmi_enabled = 0; | 36 | static int nmi_enabled = 0; |
34 | 37 | ||
38 | #ifdef CONFIG_SMP | ||
39 | static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, | ||
40 | void *data) | ||
41 | { | ||
42 | int cpu = (unsigned long)data; | ||
43 | switch (action) { | ||
44 | case CPU_DOWN_FAILED: | ||
45 | case CPU_ONLINE: | ||
46 | smp_call_function_single(cpu, nmi_cpu_start, NULL, 0); | ||
47 | break; | ||
48 | case CPU_DOWN_PREPARE: | ||
49 | smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1); | ||
50 | break; | ||
51 | } | ||
52 | return NOTIFY_DONE; | ||
53 | } | ||
54 | |||
55 | static struct notifier_block oprofile_cpu_nb = { | ||
56 | .notifier_call = oprofile_cpu_notifier | ||
57 | }; | ||
58 | #endif | ||
59 | |||
35 | #ifdef CONFIG_PM | 60 | #ifdef CONFIG_PM |
36 | 61 | ||
37 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) | 62 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) |
38 | { | 63 | { |
64 | /* Only one CPU left, just stop that one */ | ||
39 | if (nmi_enabled == 1) | 65 | if (nmi_enabled == 1) |
40 | nmi_stop(); | 66 | nmi_cpu_stop(NULL); |
41 | return 0; | 67 | return 0; |
42 | } | 68 | } |
43 | 69 | ||
44 | static int nmi_resume(struct sys_device *dev) | 70 | static int nmi_resume(struct sys_device *dev) |
45 | { | 71 | { |
46 | if (nmi_enabled == 1) | 72 | if (nmi_enabled == 1) |
47 | nmi_start(); | 73 | nmi_cpu_start(NULL); |
48 | return 0; | 74 | return 0; |
49 | } | 75 | } |
50 | 76 | ||
@@ -369,20 +395,34 @@ static int __init ppro_init(char **cpu_type) | |||
369 | { | 395 | { |
370 | __u8 cpu_model = boot_cpu_data.x86_model; | 396 | __u8 cpu_model = boot_cpu_data.x86_model; |
371 | 397 | ||
372 | if (cpu_model == 14) | 398 | switch (cpu_model) { |
399 | case 0 ... 2: | ||
400 | *cpu_type = "i386/ppro"; | ||
401 | break; | ||
402 | case 3 ... 5: | ||
403 | *cpu_type = "i386/pii"; | ||
404 | break; | ||
405 | case 6 ... 8: | ||
406 | *cpu_type = "i386/piii"; | ||
407 | break; | ||
408 | case 9: | ||
409 | *cpu_type = "i386/p6_mobile"; | ||
410 | break; | ||
411 | case 10 ... 13: | ||
412 | *cpu_type = "i386/p6"; | ||
413 | break; | ||
414 | case 14: | ||
373 | *cpu_type = "i386/core"; | 415 | *cpu_type = "i386/core"; |
374 | else if (cpu_model == 15 || cpu_model == 23) | 416 | break; |
417 | case 15: case 23: | ||
375 | *cpu_type = "i386/core_2"; | 418 | *cpu_type = "i386/core_2"; |
376 | else if (cpu_model > 0xd) | 419 | break; |
420 | case 26: | ||
421 | *cpu_type = "i386/core_2"; | ||
422 | break; | ||
423 | default: | ||
424 | /* Unknown */ | ||
377 | return 0; | 425 | return 0; |
378 | else if (cpu_model == 9) { | ||
379 | *cpu_type = "i386/p6_mobile"; | ||
380 | } else if (cpu_model > 5) { | ||
381 | *cpu_type = "i386/piii"; | ||
382 | } else if (cpu_model > 2) { | ||
383 | *cpu_type = "i386/pii"; | ||
384 | } else { | ||
385 | *cpu_type = "i386/ppro"; | ||
386 | } | 426 | } |
387 | 427 | ||
388 | model = &op_ppro_spec; | 428 | model = &op_ppro_spec; |
@@ -449,6 +489,9 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
449 | } | 489 | } |
450 | 490 | ||
451 | init_sysfs(); | 491 | init_sysfs(); |
492 | #ifdef CONFIG_SMP | ||
493 | register_cpu_notifier(&oprofile_cpu_nb); | ||
494 | #endif | ||
452 | using_nmi = 1; | 495 | using_nmi = 1; |
453 | ops->create_files = nmi_create_files; | 496 | ops->create_files = nmi_create_files; |
454 | ops->setup = nmi_setup; | 497 | ops->setup = nmi_setup; |
@@ -462,6 +505,10 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
462 | 505 | ||
463 | void op_nmi_exit(void) | 506 | void op_nmi_exit(void) |
464 | { | 507 | { |
465 | if (using_nmi) | 508 | if (using_nmi) { |
466 | exit_sysfs(); | 509 | exit_sysfs(); |
510 | #ifdef CONFIG_SMP | ||
511 | unregister_cpu_notifier(&oprofile_cpu_nb); | ||
512 | #endif | ||
513 | } | ||
467 | } | 514 | } |