aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/oprofile
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/oprofile')
-rw-r--r--arch/i386/oprofile/nmi_int.c47
-rw-r--r--arch/i386/oprofile/nmi_timer_int.c33
2 files changed, 55 insertions, 25 deletions
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 8710ca081b1e..b3610188bcf0 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -17,14 +17,15 @@
17#include <asm/nmi.h> 17#include <asm/nmi.h>
18#include <asm/msr.h> 18#include <asm/msr.h>
19#include <asm/apic.h> 19#include <asm/apic.h>
20#include <asm/kdebug.h>
20 21
21#include "op_counter.h" 22#include "op_counter.h"
22#include "op_x86_model.h" 23#include "op_x86_model.h"
23 24
24static struct op_x86_model_spec const * model; 25static struct op_x86_model_spec const * model;
25static struct op_msrs cpu_msrs[NR_CPUS]; 26static struct op_msrs cpu_msrs[NR_CPUS];
26static unsigned long saved_lvtpc[NR_CPUS]; 27static unsigned long saved_lvtpc[NR_CPUS];
27 28
28static int nmi_start(void); 29static int nmi_start(void);
29static void nmi_stop(void); 30static void nmi_stop(void);
30 31
@@ -82,13 +83,24 @@ static void exit_driverfs(void)
82#define exit_driverfs() do { } while (0) 83#define exit_driverfs() do { } while (0)
83#endif /* CONFIG_PM */ 84#endif /* CONFIG_PM */
84 85
85 86int profile_exceptions_notify(struct notifier_block *self,
86static int nmi_callback(struct pt_regs * regs, int cpu) 87 unsigned long val, void *data)
87{ 88{
88 return model->check_ctrs(regs, &cpu_msrs[cpu]); 89 struct die_args *args = (struct die_args *)data;
90 int ret = NOTIFY_DONE;
91 int cpu = smp_processor_id();
92
93 switch(val) {
94 case DIE_NMI:
95 if (model->check_ctrs(args->regs, &cpu_msrs[cpu]))
96 ret = NOTIFY_STOP;
97 break;
98 default:
99 break;
100 }
101 return ret;
89} 102}
90 103
91
92static void nmi_cpu_save_registers(struct op_msrs * msrs) 104static void nmi_cpu_save_registers(struct op_msrs * msrs)
93{ 105{
94 unsigned int const nr_ctrs = model->num_counters; 106 unsigned int const nr_ctrs = model->num_counters;
@@ -174,27 +186,29 @@ static void nmi_cpu_setup(void * dummy)
174 apic_write(APIC_LVTPC, APIC_DM_NMI); 186 apic_write(APIC_LVTPC, APIC_DM_NMI);
175} 187}
176 188
189static struct notifier_block profile_exceptions_nb = {
190 .notifier_call = profile_exceptions_notify,
191 .next = NULL,
192 .priority = 0
193};
177 194
178static int nmi_setup(void) 195static int nmi_setup(void)
179{ 196{
197 int err=0;
198
180 if (!allocate_msrs()) 199 if (!allocate_msrs())
181 return -ENOMEM; 200 return -ENOMEM;
182 201
183 /* We walk a thin line between law and rape here. 202 if ((err = register_die_notifier(&profile_exceptions_nb))){
184 * We need to be careful to install our NMI handler
185 * without actually triggering any NMIs as this will
186 * break the core code horrifically.
187 */
188 if (reserve_lapic_nmi() < 0) {
189 free_msrs(); 203 free_msrs();
190 return -EBUSY; 204 return err;
191 } 205 }
206
192 /* We need to serialize save and setup for HT because the subset 207 /* We need to serialize save and setup for HT because the subset
193 * of msrs are distinct for save and setup operations 208 * of msrs are distinct for save and setup operations
194 */ 209 */
195 on_each_cpu(nmi_save_registers, NULL, 0, 1); 210 on_each_cpu(nmi_save_registers, NULL, 0, 1);
196 on_each_cpu(nmi_cpu_setup, NULL, 0, 1); 211 on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
197 set_nmi_callback(nmi_callback);
198 nmi_enabled = 1; 212 nmi_enabled = 1;
199 return 0; 213 return 0;
200} 214}
@@ -250,8 +264,7 @@ static void nmi_shutdown(void)
250{ 264{
251 nmi_enabled = 0; 265 nmi_enabled = 0;
252 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1); 266 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
253 unset_nmi_callback(); 267 unregister_die_notifier(&profile_exceptions_nb);
254 release_lapic_nmi();
255 free_msrs(); 268 free_msrs();
256} 269}
257 270
diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
index a33a73bb502d..93ca48f804ac 100644
--- a/arch/i386/oprofile/nmi_timer_int.c
+++ b/arch/i386/oprofile/nmi_timer_int.c
@@ -17,32 +17,49 @@
17#include <asm/nmi.h> 17#include <asm/nmi.h>
18#include <asm/apic.h> 18#include <asm/apic.h>
19#include <asm/ptrace.h> 19#include <asm/ptrace.h>
20#include <asm/kdebug.h>
20 21
21static int nmi_timer_callback(struct pt_regs * regs, int cpu) 22int profile_timer_exceptions_notify(struct notifier_block *self,
23 unsigned long val, void *data)
22{ 24{
23 oprofile_add_sample(regs, 0); 25 struct die_args *args = (struct die_args *)data;
24 return 1; 26 int ret = NOTIFY_DONE;
27
28 switch(val) {
29 case DIE_NMI:
30 oprofile_add_sample(args->regs, 0);
31 ret = NOTIFY_STOP;
32 break;
33 default:
34 break;
35 }
36 return ret;
25} 37}
26 38
39static struct notifier_block profile_timer_exceptions_nb = {
40 .notifier_call = profile_timer_exceptions_notify,
41 .next = NULL,
42 .priority = 0
43};
44
27static int timer_start(void) 45static int timer_start(void)
28{ 46{
29 disable_timer_nmi_watchdog(); 47 if (register_die_notifier(&profile_timer_exceptions_nb))
30 set_nmi_callback(nmi_timer_callback); 48 return 1;
31 return 0; 49 return 0;
32} 50}
33 51
34 52
35static void timer_stop(void) 53static void timer_stop(void)
36{ 54{
37 enable_timer_nmi_watchdog(); 55 unregister_die_notifier(&profile_timer_exceptions_nb);
38 unset_nmi_callback();
39 synchronize_sched(); /* Allow already-started NMIs to complete. */ 56 synchronize_sched(); /* Allow already-started NMIs to complete. */
40} 57}
41 58
42 59
43int __init op_nmi_timer_init(struct oprofile_operations * ops) 60int __init op_nmi_timer_init(struct oprofile_operations * ops)
44{ 61{
45 if (atomic_read(&nmi_active) <= 0) 62 if ((nmi_watchdog != NMI_IO_APIC) || (atomic_read(&nmi_active) <= 0))
46 return -ENODEV; 63 return -ENODEV;
47 64
48 ops->start = timer_start; 65 ops->start = timer_start;