aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/oprofile/nmi_int.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/oprofile/nmi_int.c')
-rw-r--r--arch/i386/oprofile/nmi_int.c88
1 files changed, 59 insertions, 29 deletions
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 5f8dc8a21bd7..3700eef78743 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 86static int 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;
@@ -98,15 +110,19 @@ static void nmi_cpu_save_registers(struct op_msrs * msrs)
98 unsigned int i; 110 unsigned int i;
99 111
100 for (i = 0; i < nr_ctrs; ++i) { 112 for (i = 0; i < nr_ctrs; ++i) {
101 rdmsr(counters[i].addr, 113 if (counters[i].addr){
102 counters[i].saved.low, 114 rdmsr(counters[i].addr,
103 counters[i].saved.high); 115 counters[i].saved.low,
116 counters[i].saved.high);
117 }
104 } 118 }
105 119
106 for (i = 0; i < nr_ctrls; ++i) { 120 for (i = 0; i < nr_ctrls; ++i) {
107 rdmsr(controls[i].addr, 121 if (controls[i].addr){
108 controls[i].saved.low, 122 rdmsr(controls[i].addr,
109 controls[i].saved.high); 123 controls[i].saved.low,
124 controls[i].saved.high);
125 }
110 } 126 }
111} 127}
112 128
@@ -170,27 +186,29 @@ static void nmi_cpu_setup(void * dummy)
170 apic_write(APIC_LVTPC, APIC_DM_NMI); 186 apic_write(APIC_LVTPC, APIC_DM_NMI);
171} 187}
172 188
189static struct notifier_block profile_exceptions_nb = {
190 .notifier_call = profile_exceptions_notify,
191 .next = NULL,
192 .priority = 0
193};
173 194
174static int nmi_setup(void) 195static int nmi_setup(void)
175{ 196{
197 int err=0;
198
176 if (!allocate_msrs()) 199 if (!allocate_msrs())
177 return -ENOMEM; 200 return -ENOMEM;
178 201
179 /* We walk a thin line between law and rape here. 202 if ((err = register_die_notifier(&profile_exceptions_nb))){
180 * We need to be careful to install our NMI handler
181 * without actually triggering any NMIs as this will
182 * break the core code horrifically.
183 */
184 if (reserve_lapic_nmi() < 0) {
185 free_msrs(); 203 free_msrs();
186 return -EBUSY; 204 return err;
187 } 205 }
206
188 /* 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
189 * of msrs are distinct for save and setup operations 208 * of msrs are distinct for save and setup operations
190 */ 209 */
191 on_each_cpu(nmi_save_registers, NULL, 0, 1); 210 on_each_cpu(nmi_save_registers, NULL, 0, 1);
192 on_each_cpu(nmi_cpu_setup, NULL, 0, 1); 211 on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
193 set_nmi_callback(nmi_callback);
194 nmi_enabled = 1; 212 nmi_enabled = 1;
195 return 0; 213 return 0;
196} 214}
@@ -205,15 +223,19 @@ static void nmi_restore_registers(struct op_msrs * msrs)
205 unsigned int i; 223 unsigned int i;
206 224
207 for (i = 0; i < nr_ctrls; ++i) { 225 for (i = 0; i < nr_ctrls; ++i) {
208 wrmsr(controls[i].addr, 226 if (controls[i].addr){
209 controls[i].saved.low, 227 wrmsr(controls[i].addr,
210 controls[i].saved.high); 228 controls[i].saved.low,
229 controls[i].saved.high);
230 }
211 } 231 }
212 232
213 for (i = 0; i < nr_ctrs; ++i) { 233 for (i = 0; i < nr_ctrs; ++i) {
214 wrmsr(counters[i].addr, 234 if (counters[i].addr){
215 counters[i].saved.low, 235 wrmsr(counters[i].addr,
216 counters[i].saved.high); 236 counters[i].saved.low,
237 counters[i].saved.high);
238 }
217 } 239 }
218} 240}
219 241
@@ -234,6 +256,7 @@ static void nmi_cpu_shutdown(void * dummy)
234 apic_write(APIC_LVTPC, saved_lvtpc[cpu]); 256 apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
235 apic_write(APIC_LVTERR, v); 257 apic_write(APIC_LVTERR, v);
236 nmi_restore_registers(msrs); 258 nmi_restore_registers(msrs);
259 model->shutdown(msrs);
237} 260}
238 261
239 262
@@ -241,8 +264,7 @@ static void nmi_shutdown(void)
241{ 264{
242 nmi_enabled = 0; 265 nmi_enabled = 0;
243 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1); 266 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
244 unset_nmi_callback(); 267 unregister_die_notifier(&profile_exceptions_nb);
245 release_lapic_nmi();
246 free_msrs(); 268 free_msrs();
247} 269}
248 270
@@ -284,6 +306,14 @@ static int nmi_create_files(struct super_block * sb, struct dentry * root)
284 struct dentry * dir; 306 struct dentry * dir;
285 char buf[4]; 307 char buf[4];
286 308
309 /* quick little hack to _not_ expose a counter if it is not
310 * available for use. This should protect userspace app.
311 * NOTE: assumes 1:1 mapping here (that counters are organized
312 * sequentially in their struct assignment).
313 */
314 if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i)))
315 continue;
316
287 snprintf(buf, sizeof(buf), "%d", i); 317 snprintf(buf, sizeof(buf), "%d", i);
288 dir = oprofilefs_mkdir(sb, root, buf); 318 dir = oprofilefs_mkdir(sb, root, buf);
289 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); 319 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);