Blame view

arch/x86/oprofile/nmi_int.c 17 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /**
   * @file nmi_int.c
   *
4d4036e0e   Jason Yeh   oprofile: Impleme...
4
   * @remark Copyright 2002-2009 OProfile authors
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
   * @remark Read the file COPYING
   *
   * @author John Levon <levon@movementarian.org>
adf5ec0bc   Robert Richter   x86/oprofile: int...
8
   * @author Robert Richter <robert.richter@amd.com>
4d4036e0e   Jason Yeh   oprofile: Impleme...
9
10
11
   * @author Barry Kasindorf <barry.kasindorf@amd.com>
   * @author Jason Yeh <jason.yeh@amd.com>
   * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
   */
  
  #include <linux/init.h>
  #include <linux/notifier.h>
  #include <linux/smp.h>
  #include <linux/oprofile.h>
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
18
  #include <linux/syscore_ops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/slab.h>
1cfcea1b2   Andi Kleen   [PATCH] x86_64: A...
20
  #include <linux/moduleparam.h>
1eeb66a1b   Christoph Hellwig   move die notifier...
21
  #include <linux/kdebug.h>
80a8c9fff   Andi Kleen   x86: fix oprofile...
22
  #include <linux/cpu.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  #include <asm/nmi.h>
  #include <asm/msr.h>
  #include <asm/apic.h>
b75f53dba   Carlos R. Mafra   x86: fix style er...
26

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  #include "op_counter.h"
  #include "op_x86_model.h"
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
29

259a83a8a   Robert Richter   x86/oprofile: Rem...
30
  static struct op_x86_model_spec *model;
d18d00f5d   Mike Travis   x86: oprofile: re...
31
32
  static DEFINE_PER_CPU(struct op_msrs, cpu_msrs);
  static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
33

6ae56b55b   Robert Richter   oprofile/x86: pro...
34
35
36
  /* must be protected with get_online_cpus()/put_online_cpus(): */
  static int nmi_enabled;
  static int ctr_running;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

4d4036e0e   Jason Yeh   oprofile: Impleme...
38
  struct op_counter_config counter_config[OP_MAX_COUNTER];
3370d3585   Robert Richter   x86/oprofile: rep...
39
40
41
42
43
44
45
46
47
48
49
50
  /* common functions */
  
  u64 op_x86_get_ctrl(struct op_x86_model_spec const *model,
  		    struct op_counter_config *counter_config)
  {
  	u64 val = 0;
  	u16 event = (u16)counter_config->event;
  
  	val |= ARCH_PERFMON_EVENTSEL_INT;
  	val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0;
  	val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0;
  	val |= (counter_config->unit_mask & 0xFF) << 8;
914a76ca5   Andi Kleen   oprofile, x86: Al...
51
52
53
54
  	counter_config->extra &= (ARCH_PERFMON_EVENTSEL_INV |
  				  ARCH_PERFMON_EVENTSEL_EDGE |
  				  ARCH_PERFMON_EVENTSEL_CMASK);
  	val |= counter_config->extra;
3370d3585   Robert Richter   x86/oprofile: rep...
55
56
57
58
59
60
  	event &= model->event_mask ? model->event_mask : 0xFF;
  	val |= event & 0xFF;
  	val |= (event & 0x0F00) << 24;
  
  	return val;
  }
c7c19f8e5   Adrian Bunk   [PATCH] i386: mak...
61
62
  static int profile_exceptions_notify(struct notifier_block *self,
  				     unsigned long val, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  {
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
64
65
  	struct die_args *args = (struct die_args *)data;
  	int ret = NOTIFY_DONE;
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
66

b75f53dba   Carlos R. Mafra   x86: fix style er...
67
  	switch (val) {
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
68
  	case DIE_NMI:
de6546497   Robert Richter   oprofile/x86: sto...
69
70
71
72
73
74
  		if (ctr_running)
  			model->check_ctrs(args->regs, &__get_cpu_var(cpu_msrs));
  		else if (!nmi_enabled)
  			break;
  		else
  			model->stop(&__get_cpu_var(cpu_msrs));
5b75af0a0   Mike Galbraith   perfcounters: fix...
75
  		ret = NOTIFY_STOP;
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
76
77
78
79
80
  		break;
  	default:
  		break;
  	}
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  }
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
82

b75f53dba   Carlos R. Mafra   x86: fix style er...
83
  static void nmi_cpu_save_registers(struct op_msrs *msrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
b75f53dba   Carlos R. Mafra   x86: fix style er...
85
86
  	struct op_msr *counters = msrs->counters;
  	struct op_msr *controls = msrs->controls;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  	unsigned int i;
1a245c453   Robert Richter   x86/oprofile: rem...
88
  	for (i = 0; i < model->num_counters; ++i) {
95e74e62c   Robert Richter   x86/oprofile: use...
89
90
  		if (counters[i].addr)
  			rdmsrl(counters[i].addr, counters[i].saved);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  	}
b75f53dba   Carlos R. Mafra   x86: fix style er...
92

1a245c453   Robert Richter   x86/oprofile: rem...
93
  	for (i = 0; i < model->num_controls; ++i) {
95e74e62c   Robert Richter   x86/oprofile: use...
94
95
  		if (controls[i].addr)
  			rdmsrl(controls[i].addr, controls[i].saved);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
  	}
  }
b28d1b923   Robert Richter   x86/oprofile: Mov...
98
99
100
  static void nmi_cpu_start(void *dummy)
  {
  	struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
2623a1d55   Robert Richter   oprofile/x86: fix...
101
102
103
104
  	if (!msrs->controls)
  		WARN_ON_ONCE(1);
  	else
  		model->start(msrs);
b28d1b923   Robert Richter   x86/oprofile: Mov...
105
106
107
108
  }
  
  static int nmi_start(void)
  {
6ae56b55b   Robert Richter   oprofile/x86: pro...
109
  	get_online_cpus();
6ae56b55b   Robert Richter   oprofile/x86: pro...
110
  	ctr_running = 1;
8fe7e94eb   Robert Richter   oprofile, x86: Fi...
111
112
113
  	/* make ctr_running visible to the nmi handler: */
  	smp_mb();
  	on_each_cpu(nmi_cpu_start, NULL, 1);
6ae56b55b   Robert Richter   oprofile/x86: pro...
114
  	put_online_cpus();
b28d1b923   Robert Richter   x86/oprofile: Mov...
115
116
117
118
119
120
  	return 0;
  }
  
  static void nmi_cpu_stop(void *dummy)
  {
  	struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
2623a1d55   Robert Richter   oprofile/x86: fix...
121
122
123
124
  	if (!msrs->controls)
  		WARN_ON_ONCE(1);
  	else
  		model->stop(msrs);
b28d1b923   Robert Richter   x86/oprofile: Mov...
125
126
127
128
  }
  
  static void nmi_stop(void)
  {
6ae56b55b   Robert Richter   oprofile/x86: pro...
129
  	get_online_cpus();
b28d1b923   Robert Richter   x86/oprofile: Mov...
130
  	on_each_cpu(nmi_cpu_stop, NULL, 1);
6ae56b55b   Robert Richter   oprofile/x86: pro...
131
132
  	ctr_running = 0;
  	put_online_cpus();
b28d1b923   Robert Richter   x86/oprofile: Mov...
133
  }
d8471ad3a   Robert Richter   oprofile: Introdu...
134
135
136
  #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  
  static DEFINE_PER_CPU(int, switch_index);
39e97f40c   Robert Richter   x86/oprofile: Add...
137
138
139
140
  static inline int has_mux(void)
  {
  	return !!model->switch_ctrl;
  }
d8471ad3a   Robert Richter   oprofile: Introdu...
141
142
  inline int op_x86_phys_to_virt(int phys)
  {
0a3aee0da   Tejun Heo   x86: Use this_cpu...
143
  	return __this_cpu_read(switch_index) + phys;
d8471ad3a   Robert Richter   oprofile: Introdu...
144
  }
61d149d52   Robert Richter   x86/oprofile: Imp...
145
146
147
148
  inline int op_x86_virt_to_phys(int virt)
  {
  	return virt % model->num_counters;
  }
6ab82f958   Robert Richter   x86/oprofile: Imp...
149
150
151
  static void nmi_shutdown_mux(void)
  {
  	int i;
39e97f40c   Robert Richter   x86/oprofile: Add...
152
153
154
  
  	if (!has_mux())
  		return;
6ab82f958   Robert Richter   x86/oprofile: Imp...
155
156
157
158
159
160
161
162
163
164
165
166
  	for_each_possible_cpu(i) {
  		kfree(per_cpu(cpu_msrs, i).multiplex);
  		per_cpu(cpu_msrs, i).multiplex = NULL;
  		per_cpu(switch_index, i) = 0;
  	}
  }
  
  static int nmi_setup_mux(void)
  {
  	size_t multiplex_size =
  		sizeof(struct op_msr) * model->num_virt_counters;
  	int i;
39e97f40c   Robert Richter   x86/oprofile: Add...
167
168
169
  
  	if (!has_mux())
  		return 1;
6ab82f958   Robert Richter   x86/oprofile: Imp...
170
171
  	for_each_possible_cpu(i) {
  		per_cpu(cpu_msrs, i).multiplex =
c17c8fbf3   Robert Richter   oprofile/x86: use...
172
  			kzalloc(multiplex_size, GFP_KERNEL);
6ab82f958   Robert Richter   x86/oprofile: Imp...
173
174
175
  		if (!per_cpu(cpu_msrs, i).multiplex)
  			return 0;
  	}
39e97f40c   Robert Richter   x86/oprofile: Add...
176

6ab82f958   Robert Richter   x86/oprofile: Imp...
177
178
  	return 1;
  }
48fb4b467   Robert Richter   x86/oprofile: Mov...
179
180
181
182
  static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs)
  {
  	int i;
  	struct op_msr *multiplex = msrs->multiplex;
39e97f40c   Robert Richter   x86/oprofile: Add...
183
184
  	if (!has_mux())
  		return;
48fb4b467   Robert Richter   x86/oprofile: Mov...
185
186
187
188
  	for (i = 0; i < model->num_virt_counters; ++i) {
  		if (counter_config[i].enabled) {
  			multiplex[i].saved = -(u64)counter_config[i].count;
  		} else {
48fb4b467   Robert Richter   x86/oprofile: Mov...
189
190
191
192
193
194
  			multiplex[i].saved = 0;
  		}
  	}
  
  	per_cpu(switch_index, cpu) = 0;
  }
d0f585dd2   Robert Richter   x86/oprofile: Mov...
195
196
  static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs)
  {
68dc819ce   Robert Richter   oprofile/x86: fix...
197
  	struct op_msr *counters = msrs->counters;
d0f585dd2   Robert Richter   x86/oprofile: Mov...
198
199
200
201
202
  	struct op_msr *multiplex = msrs->multiplex;
  	int i;
  
  	for (i = 0; i < model->num_counters; ++i) {
  		int virt = op_x86_phys_to_virt(i);
68dc819ce   Robert Richter   oprofile/x86: fix...
203
204
  		if (counters[i].addr)
  			rdmsrl(counters[i].addr, multiplex[virt].saved);
d0f585dd2   Robert Richter   x86/oprofile: Mov...
205
206
207
208
209
  	}
  }
  
  static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs)
  {
68dc819ce   Robert Richter   oprofile/x86: fix...
210
  	struct op_msr *counters = msrs->counters;
d0f585dd2   Robert Richter   x86/oprofile: Mov...
211
212
213
214
215
  	struct op_msr *multiplex = msrs->multiplex;
  	int i;
  
  	for (i = 0; i < model->num_counters; ++i) {
  		int virt = op_x86_phys_to_virt(i);
68dc819ce   Robert Richter   oprofile/x86: fix...
216
217
  		if (counters[i].addr)
  			wrmsrl(counters[i].addr, multiplex[virt].saved);
d0f585dd2   Robert Richter   x86/oprofile: Mov...
218
219
  	}
  }
b28d1b923   Robert Richter   x86/oprofile: Mov...
220
221
222
223
224
225
226
227
228
229
230
  static void nmi_cpu_switch(void *dummy)
  {
  	int cpu = smp_processor_id();
  	int si = per_cpu(switch_index, cpu);
  	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
  
  	nmi_cpu_stop(NULL);
  	nmi_cpu_save_mpx_registers(msrs);
  
  	/* move to next set */
  	si += model->num_counters;
d8cc108f4   Suravee Suthikulpanit   oprofile/x86: fix...
231
  	if ((si >= model->num_virt_counters) || (counter_config[si].count == 0))
b28d1b923   Robert Richter   x86/oprofile: Mov...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  		per_cpu(switch_index, cpu) = 0;
  	else
  		per_cpu(switch_index, cpu) = si;
  
  	model->switch_ctrl(model, msrs);
  	nmi_cpu_restore_mpx_registers(msrs);
  
  	nmi_cpu_start(NULL);
  }
  
  
  /*
   * Quick check to see if multiplexing is necessary.
   * The check should be sufficient since counters are used
   * in ordre.
   */
  static int nmi_multiplex_on(void)
  {
  	return counter_config[model->num_counters].count ? 0 : -EINVAL;
  }
  
  static int nmi_switch_event(void)
  {
39e97f40c   Robert Richter   x86/oprofile: Add...
255
  	if (!has_mux())
b28d1b923   Robert Richter   x86/oprofile: Mov...
256
257
258
  		return -ENOSYS;		/* not implemented */
  	if (nmi_multiplex_on() < 0)
  		return -EINVAL;		/* not necessary */
6ae56b55b   Robert Richter   oprofile/x86: pro...
259
260
261
262
  	get_online_cpus();
  	if (ctr_running)
  		on_each_cpu(nmi_cpu_switch, NULL, 1);
  	put_online_cpus();
b28d1b923   Robert Richter   x86/oprofile: Mov...
263

b28d1b923   Robert Richter   x86/oprofile: Mov...
264
265
  	return 0;
  }
528051447   Robert Richter   x86/oprofile: Ena...
266
267
268
269
270
  static inline void mux_init(struct oprofile_operations *ops)
  {
  	if (has_mux())
  		ops->switch_events = nmi_switch_event;
  }
4d015f79e   Robert Richter   x86/oprofile: Imp...
271
272
273
274
275
276
277
278
279
  static void mux_clone(int cpu)
  {
  	if (!has_mux())
  		return;
  
  	memcpy(per_cpu(cpu_msrs, cpu).multiplex,
  	       per_cpu(cpu_msrs, 0).multiplex,
  	       sizeof(struct op_msr) * model->num_virt_counters);
  }
d8471ad3a   Robert Richter   oprofile: Introdu...
280
281
282
  #else
  
  inline int op_x86_phys_to_virt(int phys) { return phys; }
61d149d52   Robert Richter   x86/oprofile: Imp...
283
  inline int op_x86_virt_to_phys(int virt) { return virt; }
6ab82f958   Robert Richter   x86/oprofile: Imp...
284
285
  static inline void nmi_shutdown_mux(void) { }
  static inline int nmi_setup_mux(void) { return 1; }
48fb4b467   Robert Richter   x86/oprofile: Mov...
286
287
  static inline void
  nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { }
528051447   Robert Richter   x86/oprofile: Ena...
288
  static inline void mux_init(struct oprofile_operations *ops) { }
4d015f79e   Robert Richter   x86/oprofile: Imp...
289
  static void mux_clone(int cpu) { }
d8471ad3a   Robert Richter   oprofile: Introdu...
290
291
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
  static void free_msrs(void)
  {
  	int i;
c8912599c   KAMEZAWA Hiroyuki   [PATCH] for_each_...
295
  	for_each_possible_cpu(i) {
d18d00f5d   Mike Travis   x86: oprofile: re...
296
297
298
299
  		kfree(per_cpu(cpu_msrs, i).counters);
  		per_cpu(cpu_msrs, i).counters = NULL;
  		kfree(per_cpu(cpu_msrs, i).controls);
  		per_cpu(cpu_msrs, i).controls = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  	}
8f5a2dd83   Robert Richter   oprofile/x86: rew...
301
  	nmi_shutdown_mux();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
  static int allocate_msrs(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
  	size_t controls_size = sizeof(struct op_msr) * model->num_controls;
  	size_t counters_size = sizeof(struct op_msr) * model->num_counters;
4c168eaf7   Robert Richter   Revert "Oprofile ...
307
  	int i;
0939c17c7   Chris Wright   x86: fix oprofile...
308
  	for_each_possible_cpu(i) {
c17c8fbf3   Robert Richter   oprofile/x86: use...
309
  		per_cpu(cpu_msrs, i).counters = kzalloc(counters_size,
6ab82f958   Robert Richter   x86/oprofile: Imp...
310
311
  							GFP_KERNEL);
  		if (!per_cpu(cpu_msrs, i).counters)
8f5a2dd83   Robert Richter   oprofile/x86: rew...
312
  			goto fail;
c17c8fbf3   Robert Richter   oprofile/x86: use...
313
  		per_cpu(cpu_msrs, i).controls = kzalloc(controls_size,
6ab82f958   Robert Richter   x86/oprofile: Imp...
314
315
  							GFP_KERNEL);
  		if (!per_cpu(cpu_msrs, i).controls)
8f5a2dd83   Robert Richter   oprofile/x86: rew...
316
  			goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  	}
8f5a2dd83   Robert Richter   oprofile/x86: rew...
318
319
  	if (!nmi_setup_mux())
  		goto fail;
6ab82f958   Robert Richter   x86/oprofile: Imp...
320
  	return 1;
8f5a2dd83   Robert Richter   oprofile/x86: rew...
321
322
323
324
  
  fail:
  	free_msrs();
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  }
b75f53dba   Carlos R. Mafra   x86: fix style er...
326
  static void nmi_cpu_setup(void *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  {
  	int cpu = smp_processor_id();
d18d00f5d   Mike Travis   x86: oprofile: re...
329
  	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
44ab9a6b0   Robert Richter   x86/oprofile: Rew...
330
  	nmi_cpu_save_registers(msrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  	spin_lock(&oprofilefs_lock);
ef8828ddf   Robert Richter   x86/oprofile: pas...
332
  	model->setup_ctrs(model, msrs);
6bfccd099   Robert Richter   x86/oprofile: Fix...
333
  	nmi_cpu_setup_mux(cpu, msrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  	spin_unlock(&oprofilefs_lock);
d18d00f5d   Mike Travis   x86: oprofile: re...
335
  	per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  	apic_write(APIC_LVTPC, APIC_DM_NMI);
  }
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
338
339
340
  static struct notifier_block profile_exceptions_nb = {
  	.notifier_call = profile_exceptions_notify,
  	.next = NULL,
166d75147   Don Zickus   x86, NMI: Add pri...
341
  	.priority = NMI_LOCAL_LOW_PRIOR,
2fbe7b25c   Don Zickus   [PATCH] i386/x86-...
342
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343

44ab9a6b0   Robert Richter   x86/oprofile: Rew...
344
  static void nmi_cpu_restore_registers(struct op_msrs *msrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  {
b75f53dba   Carlos R. Mafra   x86: fix style er...
346
347
  	struct op_msr *counters = msrs->counters;
  	struct op_msr *controls = msrs->controls;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  	unsigned int i;
1a245c453   Robert Richter   x86/oprofile: rem...
349
  	for (i = 0; i < model->num_controls; ++i) {
95e74e62c   Robert Richter   x86/oprofile: use...
350
351
  		if (controls[i].addr)
  			wrmsrl(controls[i].addr, controls[i].saved);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	}
b75f53dba   Carlos R. Mafra   x86: fix style er...
353

1a245c453   Robert Richter   x86/oprofile: rem...
354
  	for (i = 0; i < model->num_counters; ++i) {
95e74e62c   Robert Richter   x86/oprofile: use...
355
356
  		if (counters[i].addr)
  			wrmsrl(counters[i].addr, counters[i].saved);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359

b75f53dba   Carlos R. Mafra   x86: fix style er...
360
  static void nmi_cpu_shutdown(void *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
  {
  	unsigned int v;
  	int cpu = smp_processor_id();
82a225283   Robert Richter   x86/oprofile: Use...
364
  	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
b75f53dba   Carlos R. Mafra   x86: fix style er...
365

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
  	/* restoring APIC_LVTPC can trigger an apic error because the delivery
  	 * mode and vector nr combination can be illegal. That's by design: on
  	 * power on apic lvt contain a zero vector nr which are legal only for
  	 * NMI delivery mode. So inhibit apic err before restoring lvtpc
  	 */
  	v = apic_read(APIC_LVTERR);
  	apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
d18d00f5d   Mike Travis   x86: oprofile: re...
373
  	apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	apic_write(APIC_LVTERR, v);
44ab9a6b0   Robert Richter   x86/oprofile: Rew...
375
  	nmi_cpu_restore_registers(msrs);
bae663bc6   Robert Richter   oprofile/x86: mak...
376
377
  	if (model->cpu_down)
  		model->cpu_down();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  }
6ae56b55b   Robert Richter   oprofile/x86: pro...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  static void nmi_cpu_up(void *dummy)
  {
  	if (nmi_enabled)
  		nmi_cpu_setup(dummy);
  	if (ctr_running)
  		nmi_cpu_start(dummy);
  }
  
  static void nmi_cpu_down(void *dummy)
  {
  	if (ctr_running)
  		nmi_cpu_stop(dummy);
  	if (nmi_enabled)
  		nmi_cpu_shutdown(dummy);
  }
b75f53dba   Carlos R. Mafra   x86: fix style er...
394
  static int nmi_create_files(struct super_block *sb, struct dentry *root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
  {
  	unsigned int i;
4d4036e0e   Jason Yeh   oprofile: Impleme...
397
  	for (i = 0; i < model->num_virt_counters; ++i) {
b75f53dba   Carlos R. Mafra   x86: fix style er...
398
  		struct dentry *dir;
0c6856f70   Markus Armbruster   [PATCH] oprofile:...
399
  		char buf[4];
b75f53dba   Carlos R. Mafra   x86: fix style er...
400
401
  
  		/* quick little hack to _not_ expose a counter if it is not
cb9c448c6   Don Zickus   [PATCH] i386: Uti...
402
403
404
405
  		 * available for use.  This should protect userspace app.
  		 * NOTE:  assumes 1:1 mapping here (that counters are organized
  		 *        sequentially in their struct assignment).
  		 */
11be1a7b5   Robert Richter   x86/oprofile: Add...
406
  		if (!avail_to_resrv_perfctr_nmi_bit(op_x86_virt_to_phys(i)))
cb9c448c6   Don Zickus   [PATCH] i386: Uti...
407
  			continue;
0c6856f70   Markus Armbruster   [PATCH] oprofile:...
408
  		snprintf(buf,  sizeof(buf), "%d", i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  		dir = oprofilefs_mkdir(sb, root, buf);
b75f53dba   Carlos R. Mafra   x86: fix style er...
410
411
412
413
414
415
  		oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
  		oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
  		oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
  		oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
  		oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
  		oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
914a76ca5   Andi Kleen   oprofile, x86: Al...
416
  		oprofilefs_create_ulong(sb, dir, "extra", &counter_config[i].extra);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
420
  	}
  
  	return 0;
  }
b75f53dba   Carlos R. Mafra   x86: fix style er...
421

69046d430   Robert Richter   x86/oprofile: reo...
422
423
424
425
426
427
428
  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:
6ae56b55b   Robert Richter   oprofile/x86: pro...
429
  		smp_call_function_single(cpu, nmi_cpu_up, NULL, 0);
69046d430   Robert Richter   x86/oprofile: reo...
430
431
  		break;
  	case CPU_DOWN_PREPARE:
6ae56b55b   Robert Richter   oprofile/x86: pro...
432
  		smp_call_function_single(cpu, nmi_cpu_down, NULL, 1);
69046d430   Robert Richter   x86/oprofile: reo...
433
434
435
436
437
438
439
440
  		break;
  	}
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block oprofile_cpu_nb = {
  	.notifier_call = oprofile_cpu_notifier
  };
69046d430   Robert Richter   x86/oprofile: reo...
441

d30d64c6d   Robert Richter   oprofile/x86: reo...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
  static int nmi_setup(void)
  {
  	int err = 0;
  	int cpu;
  
  	if (!allocate_msrs())
  		return -ENOMEM;
  
  	/* We need to serialize save and setup for HT because the subset
  	 * of msrs are distinct for save and setup operations
  	 */
  
  	/* Assume saved/restored counters are the same on all CPUs */
  	err = model->fill_in_addresses(&per_cpu(cpu_msrs, 0));
  	if (err)
  		goto fail;
  
  	for_each_possible_cpu(cpu) {
  		if (!cpu)
  			continue;
  
  		memcpy(per_cpu(cpu_msrs, cpu).counters,
  		       per_cpu(cpu_msrs, 0).counters,
  		       sizeof(struct op_msr) * model->num_counters);
  
  		memcpy(per_cpu(cpu_msrs, cpu).controls,
  		       per_cpu(cpu_msrs, 0).controls,
  		       sizeof(struct op_msr) * model->num_controls);
  
  		mux_clone(cpu);
  	}
  
  	nmi_enabled = 0;
  	ctr_running = 0;
8fe7e94eb   Robert Richter   oprofile, x86: Fi...
476
477
  	/* make variables visible to the nmi handler: */
  	smp_mb();
d30d64c6d   Robert Richter   oprofile/x86: reo...
478
479
480
481
482
  	err = register_die_notifier(&profile_exceptions_nb);
  	if (err)
  		goto fail;
  
  	get_online_cpus();
3de668ee8   Robert Richter   oprofile/x86: not...
483
  	register_cpu_notifier(&oprofile_cpu_nb);
d30d64c6d   Robert Richter   oprofile/x86: reo...
484
  	nmi_enabled = 1;
8fe7e94eb   Robert Richter   oprofile, x86: Fi...
485
486
487
  	/* make nmi_enabled visible to the nmi handler: */
  	smp_mb();
  	on_each_cpu(nmi_cpu_setup, NULL, 1);
d30d64c6d   Robert Richter   oprofile/x86: reo...
488
489
490
491
492
493
494
495
496
497
498
499
500
  	put_online_cpus();
  
  	return 0;
  fail:
  	free_msrs();
  	return err;
  }
  
  static void nmi_shutdown(void)
  {
  	struct op_msrs *msrs;
  
  	get_online_cpus();
3de668ee8   Robert Richter   oprofile/x86: not...
501
  	unregister_cpu_notifier(&oprofile_cpu_nb);
d30d64c6d   Robert Richter   oprofile/x86: reo...
502
503
504
505
  	on_each_cpu(nmi_cpu_shutdown, NULL, 1);
  	nmi_enabled = 0;
  	ctr_running = 0;
  	put_online_cpus();
8fe7e94eb   Robert Richter   oprofile, x86: Fi...
506
507
  	/* make variables visible to the nmi handler: */
  	smp_mb();
d30d64c6d   Robert Richter   oprofile/x86: reo...
508
509
510
511
512
513
  	unregister_die_notifier(&profile_exceptions_nb);
  	msrs = &get_cpu_var(cpu_msrs);
  	model->shutdown(msrs);
  	free_msrs();
  	put_cpu_var(cpu_msrs);
  }
69046d430   Robert Richter   x86/oprofile: reo...
514
  #ifdef CONFIG_PM
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
515
  static int nmi_suspend(void)
69046d430   Robert Richter   x86/oprofile: reo...
516
517
518
519
520
521
  {
  	/* Only one CPU left, just stop that one */
  	if (nmi_enabled == 1)
  		nmi_cpu_stop(NULL);
  	return 0;
  }
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
522
  static void nmi_resume(void)
69046d430   Robert Richter   x86/oprofile: reo...
523
524
525
  {
  	if (nmi_enabled == 1)
  		nmi_cpu_start(NULL);
69046d430   Robert Richter   x86/oprofile: reo...
526
  }
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
527
  static struct syscore_ops oprofile_syscore_ops = {
69046d430   Robert Richter   x86/oprofile: reo...
528
529
530
  	.resume		= nmi_resume,
  	.suspend	= nmi_suspend,
  };
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
531
  static void __init init_suspend_resume(void)
69046d430   Robert Richter   x86/oprofile: reo...
532
  {
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
533
  	register_syscore_ops(&oprofile_syscore_ops);
69046d430   Robert Richter   x86/oprofile: reo...
534
  }
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
535
  static void exit_suspend_resume(void)
69046d430   Robert Richter   x86/oprofile: reo...
536
  {
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
537
  	unregister_syscore_ops(&oprofile_syscore_ops);
69046d430   Robert Richter   x86/oprofile: reo...
538
539
540
  }
  
  #else
269f45c25   Robert Richter   oprofile, x86: fi...
541

f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
542
543
  static inline void init_suspend_resume(void) { }
  static inline void exit_suspend_resume(void) { }
269f45c25   Robert Richter   oprofile, x86: fi...
544

69046d430   Robert Richter   x86/oprofile: reo...
545
  #endif /* CONFIG_PM */
b75f53dba   Carlos R. Mafra   x86: fix style er...
546
  static int __init p4_init(char **cpu_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
  {
  	__u8 cpu_model = boot_cpu_data.x86_model;
1f3d7b606   Andi Kleen   oprofile: remove ...
549
  	if (cpu_model > 6 || cpu_model == 5)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
556
557
  		return 0;
  
  #ifndef CONFIG_SMP
  	*cpu_type = "i386/p4";
  	model = &op_p4_spec;
  	return 1;
  #else
  	switch (smp_num_siblings) {
b75f53dba   Carlos R. Mafra   x86: fix style er...
558
559
560
561
562
563
564
565
566
  	case 1:
  		*cpu_type = "i386/p4";
  		model = &op_p4_spec;
  		return 1;
  
  	case 2:
  		*cpu_type = "i386/p4-ht";
  		model = &op_p4_ht2_spec;
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
570
571
572
573
574
575
  	}
  #endif
  
  	printk(KERN_INFO "oprofile: P4 HyperThreading detected with > 2 threads
  ");
  	printk(KERN_INFO "oprofile: Reverting to timer mode.
  ");
  	return 0;
  }
7e4e0bd50   Robert Richter   oprofile: introdu...
576
577
578
  static int force_arch_perfmon;
  static int force_cpu_type(const char *str, struct kernel_param *kp)
  {
8d7ff4f2a   Robert Richter   x86/oprofile: ren...
579
  	if (!strcmp(str, "arch_perfmon")) {
7e4e0bd50   Robert Richter   oprofile: introdu...
580
581
582
583
584
585
586
587
  		force_arch_perfmon = 1;
  		printk(KERN_INFO "oprofile: forcing architectural perfmon
  ");
  	}
  
  	return 0;
  }
  module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0);
1dcdb5a9e   Andi Kleen   oprofile: re-add ...
588

b75f53dba   Carlos R. Mafra   x86: fix style er...
589
  static int __init ppro_init(char **cpu_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
  {
  	__u8 cpu_model = boot_cpu_data.x86_model;
259a83a8a   Robert Richter   x86/oprofile: Rem...
592
  	struct op_x86_model_spec *spec = &op_ppro_spec;	/* default */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593

1dcdb5a9e   Andi Kleen   oprofile: re-add ...
594
595
  	if (force_arch_perfmon && cpu_has_arch_perfmon)
  		return 0;
45c34e05c   John Villalovos   Oprofile: Change ...
596
597
598
599
600
601
602
603
604
605
606
607
  	/*
  	 * Documentation on identifying Intel processors by CPU family
  	 * and model can be found in the Intel Software Developer's
  	 * Manuals (SDM):
  	 *
  	 *  http://www.intel.com/products/processor/manuals/
  	 *
  	 * As of May 2010 the documentation for this was in the:
  	 * "Intel 64 and IA-32 Architectures Software Developer's
  	 * Manual Volume 3B: System Programming Guide", "Table B-1
  	 * CPUID Signature Values of DisplayFamily_DisplayModel".
  	 */
4b9f12a37   Linus Torvalds   x86/oprofile/nmi_...
608
609
610
611
612
613
614
615
  	switch (cpu_model) {
  	case 0 ... 2:
  		*cpu_type = "i386/ppro";
  		break;
  	case 3 ... 5:
  		*cpu_type = "i386/pii";
  		break;
  	case 6 ... 8:
3d337c653   William Cohen   x86/oprofile: fix...
616
  	case 10 ... 11:
4b9f12a37   Linus Torvalds   x86/oprofile/nmi_...
617
618
619
  		*cpu_type = "i386/piii";
  		break;
  	case 9:
3d337c653   William Cohen   x86/oprofile: fix...
620
  	case 13:
4b9f12a37   Linus Torvalds   x86/oprofile/nmi_...
621
622
  		*cpu_type = "i386/p6_mobile";
  		break;
4b9f12a37   Linus Torvalds   x86/oprofile/nmi_...
623
  	case 14:
64471ebe5   Benjamin LaHaise   [PATCH] Add Core ...
624
  		*cpu_type = "i386/core";
4b9f12a37   Linus Torvalds   x86/oprofile/nmi_...
625
  		break;
c33f543d3   Patrick Simmons   oprofile: Add Sup...
626
627
628
  	case 0x0f:
  	case 0x16:
  	case 0x17:
bb7ab785a   Jiri Olsa   oprofile: Add Sup...
629
  	case 0x1d:
4b9f12a37   Linus Torvalds   x86/oprofile/nmi_...
630
631
  		*cpu_type = "i386/core_2";
  		break;
45c34e05c   John Villalovos   Oprofile: Change ...
632
  	case 0x1a:
a7c55cbee   Josh Hunt   oprofile: add sup...
633
  	case 0x1e:
e83e452b0   Andi Kleen   oprofile/x86: add...
634
  	case 0x2e:
802070f54   Robert Richter   x86/oprofile: fix...
635
  		spec = &op_arch_perfmon_spec;
6adf406f0   Andi Kleen   oprofile: add sup...
636
637
  		*cpu_type = "i386/core_i7";
  		break;
45c34e05c   John Villalovos   Oprofile: Change ...
638
  	case 0x1c:
6adf406f0   Andi Kleen   oprofile: add sup...
639
640
  		*cpu_type = "i386/atom";
  		break;
4b9f12a37   Linus Torvalds   x86/oprofile/nmi_...
641
642
  	default:
  		/* Unknown */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  	}
802070f54   Robert Richter   x86/oprofile: fix...
645
  	model = spec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
  	return 1;
  }
96d0821ca   David Gibson   [PATCH] Fix funct...
648
  int __init op_nmi_init(struct oprofile_operations *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
  {
  	__u8 vendor = boot_cpu_data.x86_vendor;
  	__u8 family = boot_cpu_data.x86;
b99170288   Andi Kleen   oprofile: Impleme...
652
  	char *cpu_type = NULL;
adf5ec0bc   Robert Richter   x86/oprofile: int...
653
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
  
  	if (!cpu_has_apic)
  		return -ENODEV;
b75f53dba   Carlos R. Mafra   x86: fix style er...
657

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  	switch (vendor) {
b75f53dba   Carlos R. Mafra   x86: fix style er...
659
660
  	case X86_VENDOR_AMD:
  		/* Needs to be at least an Athlon (or hammer in 32bit mode) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661

b75f53dba   Carlos R. Mafra   x86: fix style er...
662
  		switch (family) {
b75f53dba   Carlos R. Mafra   x86: fix style er...
663
  		case 6:
b75f53dba   Carlos R. Mafra   x86: fix style er...
664
665
666
  			cpu_type = "i386/athlon";
  			break;
  		case 0xf:
d20f24c66   Robert Richter   x86/oprofile: sim...
667
668
669
670
  			/*
  			 * Actually it could be i386/hammer too, but
  			 * give user space an consistent name.
  			 */
b75f53dba   Carlos R. Mafra   x86: fix style er...
671
672
673
  			cpu_type = "x86-64/hammer";
  			break;
  		case 0x10:
b75f53dba   Carlos R. Mafra   x86: fix style er...
674
675
  			cpu_type = "x86-64/family10";
  			break;
12f2b2610   Barry Kasindorf   oprofile: Add sup...
676
  		case 0x11:
12f2b2610   Barry Kasindorf   oprofile: Add sup...
677
678
  			cpu_type = "x86-64/family11h";
  			break;
3acbf0849   Robert Richter   oprofile, x86: Ad...
679
680
681
  		case 0x12:
  			cpu_type = "x86-64/family12h";
  			break;
e63414740   Robert Richter   oprofile, x86: Ad...
682
683
684
  		case 0x14:
  			cpu_type = "x86-64/family14h";
  			break;
30570bced   Robert Richter   oprofile, x86: Ad...
685
686
687
  		case 0x15:
  			cpu_type = "x86-64/family15h";
  			break;
d20f24c66   Robert Richter   x86/oprofile: sim...
688
689
  		default:
  			return -ENODEV;
b75f53dba   Carlos R. Mafra   x86: fix style er...
690
  		}
d20f24c66   Robert Richter   x86/oprofile: sim...
691
  		model = &op_amd_spec;
b75f53dba   Carlos R. Mafra   x86: fix style er...
692
693
694
695
696
697
  		break;
  
  	case X86_VENDOR_INTEL:
  		switch (family) {
  			/* Pentium IV */
  		case 0xf:
b99170288   Andi Kleen   oprofile: Impleme...
698
  			p4_init(&cpu_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
  			break;
b75f53dba   Carlos R. Mafra   x86: fix style er...
700
701
702
  
  			/* A P6-class processor */
  		case 6:
b99170288   Andi Kleen   oprofile: Impleme...
703
  			ppro_init(&cpu_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
  			break;
  
  		default:
b99170288   Andi Kleen   oprofile: Impleme...
707
  			break;
b75f53dba   Carlos R. Mafra   x86: fix style er...
708
  		}
b99170288   Andi Kleen   oprofile: Impleme...
709

e419294ed   Robert Richter   x86/oprofile: mov...
710
711
712
713
  		if (cpu_type)
  			break;
  
  		if (!cpu_has_arch_perfmon)
b99170288   Andi Kleen   oprofile: Impleme...
714
  			return -ENODEV;
e419294ed   Robert Richter   x86/oprofile: mov...
715
716
717
718
  
  		/* use arch perfmon as fallback */
  		cpu_type = "i386/arch_perfmon";
  		model = &op_arch_perfmon_spec;
b75f53dba   Carlos R. Mafra   x86: fix style er...
719
720
721
722
  		break;
  
  	default:
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
  	}
270d3e1a1   Robert Richter   OProfile: enable ...
724
  	/* default values, can be overwritten by model */
6e63ea4b0   Robert Richter   x86/oprofile: Whi...
725
726
727
728
729
730
  	ops->create_files	= nmi_create_files;
  	ops->setup		= nmi_setup;
  	ops->shutdown		= nmi_shutdown;
  	ops->start		= nmi_start;
  	ops->stop		= nmi_stop;
  	ops->cpu_type		= cpu_type;
270d3e1a1   Robert Richter   OProfile: enable ...
731

adf5ec0bc   Robert Richter   x86/oprofile: int...
732
733
734
735
  	if (model->init)
  		ret = model->init(ops);
  	if (ret)
  		return ret;
52471c67e   Robert Richter   x86/oprofile: Mod...
736
737
  	if (!model->num_virt_counters)
  		model->num_virt_counters = model->num_counters;
528051447   Robert Richter   x86/oprofile: Ena...
738
  	mux_init(ops);
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
739
  	init_suspend_resume();
10f0412f5   Robert Richter   oprofile, x86: fi...
740

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
744
  	printk(KERN_INFO "oprofile: using NMI interrupt.
  ");
  	return 0;
  }
96d0821ca   David Gibson   [PATCH] Fix funct...
745
  void op_nmi_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  {
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
747
  	exit_suspend_resume();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  }