aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/oprofile
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/oprofile
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/i386/oprofile')
-rw-r--r--arch/i386/oprofile/Kconfig23
-rw-r--r--arch/i386/oprofile/Makefile12
-rw-r--r--arch/i386/oprofile/backtrace.c111
-rw-r--r--arch/i386/oprofile/init.c48
-rw-r--r--arch/i386/oprofile/nmi_int.c427
-rw-r--r--arch/i386/oprofile/nmi_timer_int.c55
-rw-r--r--arch/i386/oprofile/op_counter.h29
-rw-r--r--arch/i386/oprofile/op_model_athlon.c149
-rw-r--r--arch/i386/oprofile/op_model_p4.c725
-rw-r--r--arch/i386/oprofile/op_model_ppro.c143
-rw-r--r--arch/i386/oprofile/op_x86_model.h50
11 files changed, 1772 insertions, 0 deletions
diff --git a/arch/i386/oprofile/Kconfig b/arch/i386/oprofile/Kconfig
new file mode 100644
index 000000000000..5ade19801b97
--- /dev/null
+++ b/arch/i386/oprofile/Kconfig
@@ -0,0 +1,23 @@
1
2menu "Profiling support"
3 depends on EXPERIMENTAL
4
5config PROFILING
6 bool "Profiling support (EXPERIMENTAL)"
7 help
8 Say Y here to enable the extended profiling support mechanisms used
9 by profilers such as OProfile.
10
11
12config OPROFILE
13 tristate "OProfile system profiling (EXPERIMENTAL)"
14 depends on PROFILING
15 help
16 OProfile is a profiling system capable of profiling the
17 whole system, include the kernel, kernel modules, libraries,
18 and applications.
19
20 If unsure, say N.
21
22endmenu
23
diff --git a/arch/i386/oprofile/Makefile b/arch/i386/oprofile/Makefile
new file mode 100644
index 000000000000..30f3eb366667
--- /dev/null
+++ b/arch/i386/oprofile/Makefile
@@ -0,0 +1,12 @@
1obj-$(CONFIG_OPROFILE) += oprofile.o
2
3DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
4 oprof.o cpu_buffer.o buffer_sync.o \
5 event_buffer.o oprofile_files.o \
6 oprofilefs.o oprofile_stats.o \
7 timer_int.o )
8
9oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
10oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \
11 op_model_ppro.o op_model_p4.o
12oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o
diff --git a/arch/i386/oprofile/backtrace.c b/arch/i386/oprofile/backtrace.c
new file mode 100644
index 000000000000..52d72e074f7f
--- /dev/null
+++ b/arch/i386/oprofile/backtrace.c
@@ -0,0 +1,111 @@
1/**
2 * @file backtrace.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon
8 * @author David Smith
9 */
10
11#include <linux/oprofile.h>
12#include <linux/sched.h>
13#include <linux/mm.h>
14#include <asm/ptrace.h>
15
16struct frame_head {
17 struct frame_head * ebp;
18 unsigned long ret;
19} __attribute__((packed));
20
21static struct frame_head *
22dump_backtrace(struct frame_head * head)
23{
24 oprofile_add_trace(head->ret);
25
26 /* frame pointers should strictly progress back up the stack
27 * (towards higher addresses) */
28 if (head >= head->ebp)
29 return NULL;
30
31 return head->ebp;
32}
33
34/* check that the page(s) containing the frame head are present */
35static int pages_present(struct frame_head * head)
36{
37 struct mm_struct * mm = current->mm;
38
39 /* FIXME: only necessary once per page */
40 if (!check_user_page_readable(mm, (unsigned long)head))
41 return 0;
42
43 return check_user_page_readable(mm, (unsigned long)(head + 1));
44}
45
46/*
47 * | | /\ Higher addresses
48 * | |
49 * --------------- stack base (address of current_thread_info)
50 * | thread info |
51 * . .
52 * | stack |
53 * --------------- saved regs->ebp value if valid (frame_head address)
54 * . .
55 * --------------- struct pt_regs stored on stack (struct pt_regs *)
56 * | |
57 * . .
58 * | |
59 * --------------- %esp
60 * | |
61 * | | \/ Lower addresses
62 *
63 * Thus, &pt_regs <-> stack base restricts the valid(ish) ebp values
64 */
65#ifdef CONFIG_FRAME_POINTER
66static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
67{
68 unsigned long headaddr = (unsigned long)head;
69 unsigned long stack = (unsigned long)regs;
70 unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
71
72 return headaddr > stack && headaddr < stack_base;
73}
74#else
75/* without fp, it's just junk */
76static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
77{
78 return 0;
79}
80#endif
81
82
83void
84x86_backtrace(struct pt_regs * const regs, unsigned int depth)
85{
86 struct frame_head *head;
87
88#ifdef CONFIG_X86_64
89 head = (struct frame_head *)regs->rbp;
90#else
91 head = (struct frame_head *)regs->ebp;
92#endif
93
94 if (!user_mode(regs)) {
95 while (depth-- && valid_kernel_stack(head, regs))
96 head = dump_backtrace(head);
97 return;
98 }
99
100#ifdef CONFIG_SMP
101 if (!spin_trylock(&current->mm->page_table_lock))
102 return;
103#endif
104
105 while (depth-- && head && pages_present(head))
106 head = dump_backtrace(head);
107
108#ifdef CONFIG_SMP
109 spin_unlock(&current->mm->page_table_lock);
110#endif
111}
diff --git a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c
new file mode 100644
index 000000000000..c90332de582b
--- /dev/null
+++ b/arch/i386/oprofile/init.c
@@ -0,0 +1,48 @@
1/**
2 * @file init.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon <levon@movementarian.org>
8 */
9
10#include <linux/oprofile.h>
11#include <linux/init.h>
12#include <linux/errno.h>
13
14/* We support CPUs that have performance counters like the Pentium Pro
15 * with the NMI mode driver.
16 */
17
18extern int nmi_init(struct oprofile_operations * ops);
19extern int nmi_timer_init(struct oprofile_operations * ops);
20extern void nmi_exit(void);
21extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
22
23
24int __init oprofile_arch_init(struct oprofile_operations * ops)
25{
26 int ret;
27
28 ret = -ENODEV;
29
30#ifdef CONFIG_X86_LOCAL_APIC
31 ret = nmi_init(ops);
32#endif
33#ifdef CONFIG_X86_IO_APIC
34 if (ret < 0)
35 ret = nmi_timer_init(ops);
36#endif
37 ops->backtrace = x86_backtrace;
38
39 return ret;
40}
41
42
43void oprofile_arch_exit(void)
44{
45#ifdef CONFIG_X86_LOCAL_APIC
46 nmi_exit();
47#endif
48}
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
new file mode 100644
index 000000000000..3492d961d3f1
--- /dev/null
+++ b/arch/i386/oprofile/nmi_int.c
@@ -0,0 +1,427 @@
1/**
2 * @file nmi_int.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon <levon@movementarian.org>
8 */
9
10#include <linux/init.h>
11#include <linux/notifier.h>
12#include <linux/smp.h>
13#include <linux/oprofile.h>
14#include <linux/sysdev.h>
15#include <linux/slab.h>
16#include <asm/nmi.h>
17#include <asm/msr.h>
18#include <asm/apic.h>
19
20#include "op_counter.h"
21#include "op_x86_model.h"
22
23static struct op_x86_model_spec const * model;
24static struct op_msrs cpu_msrs[NR_CPUS];
25static unsigned long saved_lvtpc[NR_CPUS];
26
27static int nmi_start(void);
28static void nmi_stop(void);
29
30/* 0 == registered but off, 1 == registered and on */
31static int nmi_enabled = 0;
32
33#ifdef CONFIG_PM
34
35static int nmi_suspend(struct sys_device *dev, u32 state)
36{
37 if (nmi_enabled == 1)
38 nmi_stop();
39 return 0;
40}
41
42
43static int nmi_resume(struct sys_device *dev)
44{
45 if (nmi_enabled == 1)
46 nmi_start();
47 return 0;
48}
49
50
51static struct sysdev_class oprofile_sysclass = {
52 set_kset_name("oprofile"),
53 .resume = nmi_resume,
54 .suspend = nmi_suspend,
55};
56
57
58static struct sys_device device_oprofile = {
59 .id = 0,
60 .cls = &oprofile_sysclass,
61};
62
63
64static int __init init_driverfs(void)
65{
66 int error;
67 if (!(error = sysdev_class_register(&oprofile_sysclass)))
68 error = sysdev_register(&device_oprofile);
69 return error;
70}
71
72
73static void exit_driverfs(void)
74{
75 sysdev_unregister(&device_oprofile);
76 sysdev_class_unregister(&oprofile_sysclass);
77}
78
79#else
80#define init_driverfs() do { } while (0)
81#define exit_driverfs() do { } while (0)
82#endif /* CONFIG_PM */
83
84
85static int nmi_callback(struct pt_regs * regs, int cpu)
86{
87 return model->check_ctrs(regs, &cpu_msrs[cpu]);
88}
89
90
91static void nmi_cpu_save_registers(struct op_msrs * msrs)
92{
93 unsigned int const nr_ctrs = model->num_counters;
94 unsigned int const nr_ctrls = model->num_controls;
95 struct op_msr * counters = msrs->counters;
96 struct op_msr * controls = msrs->controls;
97 unsigned int i;
98
99 for (i = 0; i < nr_ctrs; ++i) {
100 rdmsr(counters[i].addr,
101 counters[i].saved.low,
102 counters[i].saved.high);
103 }
104
105 for (i = 0; i < nr_ctrls; ++i) {
106 rdmsr(controls[i].addr,
107 controls[i].saved.low,
108 controls[i].saved.high);
109 }
110}
111
112
113static void nmi_save_registers(void * dummy)
114{
115 int cpu = smp_processor_id();
116 struct op_msrs * msrs = &cpu_msrs[cpu];
117 model->fill_in_addresses(msrs);
118 nmi_cpu_save_registers(msrs);
119}
120
121
122static void free_msrs(void)
123{
124 int i;
125 for (i = 0; i < NR_CPUS; ++i) {
126 kfree(cpu_msrs[i].counters);
127 cpu_msrs[i].counters = NULL;
128 kfree(cpu_msrs[i].controls);
129 cpu_msrs[i].controls = NULL;
130 }
131}
132
133
134static int allocate_msrs(void)
135{
136 int success = 1;
137 size_t controls_size = sizeof(struct op_msr) * model->num_controls;
138 size_t counters_size = sizeof(struct op_msr) * model->num_counters;
139
140 int i;
141 for (i = 0; i < NR_CPUS; ++i) {
142 if (!cpu_online(i))
143 continue;
144
145 cpu_msrs[i].counters = kmalloc(counters_size, GFP_KERNEL);
146 if (!cpu_msrs[i].counters) {
147 success = 0;
148 break;
149 }
150 cpu_msrs[i].controls = kmalloc(controls_size, GFP_KERNEL);
151 if (!cpu_msrs[i].controls) {
152 success = 0;
153 break;
154 }
155 }
156
157 if (!success)
158 free_msrs();
159
160 return success;
161}
162
163
164static void nmi_cpu_setup(void * dummy)
165{
166 int cpu = smp_processor_id();
167 struct op_msrs * msrs = &cpu_msrs[cpu];
168 spin_lock(&oprofilefs_lock);
169 model->setup_ctrs(msrs);
170 spin_unlock(&oprofilefs_lock);
171 saved_lvtpc[cpu] = apic_read(APIC_LVTPC);
172 apic_write(APIC_LVTPC, APIC_DM_NMI);
173}
174
175
176static int nmi_setup(void)
177{
178 if (!allocate_msrs())
179 return -ENOMEM;
180
181 /* We walk a thin line between law and rape here.
182 * We need to be careful to install our NMI handler
183 * without actually triggering any NMIs as this will
184 * break the core code horrifically.
185 */
186 if (reserve_lapic_nmi() < 0) {
187 free_msrs();
188 return -EBUSY;
189 }
190 /* We need to serialize save and setup for HT because the subset
191 * of msrs are distinct for save and setup operations
192 */
193 on_each_cpu(nmi_save_registers, NULL, 0, 1);
194 on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
195 set_nmi_callback(nmi_callback);
196 nmi_enabled = 1;
197 return 0;
198}
199
200
201static void nmi_restore_registers(struct op_msrs * msrs)
202{
203 unsigned int const nr_ctrs = model->num_counters;
204 unsigned int const nr_ctrls = model->num_controls;
205 struct op_msr * counters = msrs->counters;
206 struct op_msr * controls = msrs->controls;
207 unsigned int i;
208
209 for (i = 0; i < nr_ctrls; ++i) {
210 wrmsr(controls[i].addr,
211 controls[i].saved.low,
212 controls[i].saved.high);
213 }
214
215 for (i = 0; i < nr_ctrs; ++i) {
216 wrmsr(counters[i].addr,
217 counters[i].saved.low,
218 counters[i].saved.high);
219 }
220}
221
222
223static void nmi_cpu_shutdown(void * dummy)
224{
225 unsigned int v;
226 int cpu = smp_processor_id();
227 struct op_msrs * msrs = &cpu_msrs[cpu];
228
229 /* restoring APIC_LVTPC can trigger an apic error because the delivery
230 * mode and vector nr combination can be illegal. That's by design: on
231 * power on apic lvt contain a zero vector nr which are legal only for
232 * NMI delivery mode. So inhibit apic err before restoring lvtpc
233 */
234 v = apic_read(APIC_LVTERR);
235 apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
236 apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
237 apic_write(APIC_LVTERR, v);
238 nmi_restore_registers(msrs);
239}
240
241
242static void nmi_shutdown(void)
243{
244 nmi_enabled = 0;
245 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
246 unset_nmi_callback();
247 release_lapic_nmi();
248 free_msrs();
249}
250
251
252static void nmi_cpu_start(void * dummy)
253{
254 struct op_msrs const * msrs = &cpu_msrs[smp_processor_id()];
255 model->start(msrs);
256}
257
258
259static int nmi_start(void)
260{
261 on_each_cpu(nmi_cpu_start, NULL, 0, 1);
262 return 0;
263}
264
265
266static void nmi_cpu_stop(void * dummy)
267{
268 struct op_msrs const * msrs = &cpu_msrs[smp_processor_id()];
269 model->stop(msrs);
270}
271
272
273static void nmi_stop(void)
274{
275 on_each_cpu(nmi_cpu_stop, NULL, 0, 1);
276}
277
278
279struct op_counter_config counter_config[OP_MAX_COUNTER];
280
281static int nmi_create_files(struct super_block * sb, struct dentry * root)
282{
283 unsigned int i;
284
285 for (i = 0; i < model->num_counters; ++i) {
286 struct dentry * dir;
287 char buf[2];
288
289 snprintf(buf, 2, "%d", i);
290 dir = oprofilefs_mkdir(sb, root, buf);
291 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
292 oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
293 oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
294 oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
295 oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
296 oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
297 }
298
299 return 0;
300}
301
302
303static int __init p4_init(char ** cpu_type)
304{
305 __u8 cpu_model = boot_cpu_data.x86_model;
306
307 if (cpu_model > 4)
308 return 0;
309
310#ifndef CONFIG_SMP
311 *cpu_type = "i386/p4";
312 model = &op_p4_spec;
313 return 1;
314#else
315 switch (smp_num_siblings) {
316 case 1:
317 *cpu_type = "i386/p4";
318 model = &op_p4_spec;
319 return 1;
320
321 case 2:
322 *cpu_type = "i386/p4-ht";
323 model = &op_p4_ht2_spec;
324 return 1;
325 }
326#endif
327
328 printk(KERN_INFO "oprofile: P4 HyperThreading detected with > 2 threads\n");
329 printk(KERN_INFO "oprofile: Reverting to timer mode.\n");
330 return 0;
331}
332
333
334static int __init ppro_init(char ** cpu_type)
335{
336 __u8 cpu_model = boot_cpu_data.x86_model;
337
338 if (cpu_model > 0xd)
339 return 0;
340
341 if (cpu_model == 9) {
342 *cpu_type = "i386/p6_mobile";
343 } else if (cpu_model > 5) {
344 *cpu_type = "i386/piii";
345 } else if (cpu_model > 2) {
346 *cpu_type = "i386/pii";
347 } else {
348 *cpu_type = "i386/ppro";
349 }
350
351 model = &op_ppro_spec;
352 return 1;
353}
354
355/* in order to get driverfs right */
356static int using_nmi;
357
358int __init nmi_init(struct oprofile_operations *ops)
359{
360 __u8 vendor = boot_cpu_data.x86_vendor;
361 __u8 family = boot_cpu_data.x86;
362 char *cpu_type;
363
364 if (!cpu_has_apic)
365 return -ENODEV;
366
367 switch (vendor) {
368 case X86_VENDOR_AMD:
369 /* Needs to be at least an Athlon (or hammer in 32bit mode) */
370
371 switch (family) {
372 default:
373 return -ENODEV;
374 case 6:
375 model = &op_athlon_spec;
376 cpu_type = "i386/athlon";
377 break;
378 case 0xf:
379 model = &op_athlon_spec;
380 /* Actually it could be i386/hammer too, but give
381 user space an consistent name. */
382 cpu_type = "x86-64/hammer";
383 break;
384 }
385 break;
386
387 case X86_VENDOR_INTEL:
388 switch (family) {
389 /* Pentium IV */
390 case 0xf:
391 if (!p4_init(&cpu_type))
392 return -ENODEV;
393 break;
394
395 /* A P6-class processor */
396 case 6:
397 if (!ppro_init(&cpu_type))
398 return -ENODEV;
399 break;
400
401 default:
402 return -ENODEV;
403 }
404 break;
405
406 default:
407 return -ENODEV;
408 }
409
410 init_driverfs();
411 using_nmi = 1;
412 ops->create_files = nmi_create_files;
413 ops->setup = nmi_setup;
414 ops->shutdown = nmi_shutdown;
415 ops->start = nmi_start;
416 ops->stop = nmi_stop;
417 ops->cpu_type = cpu_type;
418 printk(KERN_INFO "oprofile: using NMI interrupt.\n");
419 return 0;
420}
421
422
423void nmi_exit(void)
424{
425 if (using_nmi)
426 exit_driverfs();
427}
diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
new file mode 100644
index 000000000000..b2e462abf337
--- /dev/null
+++ b/arch/i386/oprofile/nmi_timer_int.c
@@ -0,0 +1,55 @@
1/**
2 * @file nmi_timer_int.c
3 *
4 * @remark Copyright 2003 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author Zwane Mwaikambo <zwane@linuxpower.ca>
8 */
9
10#include <linux/init.h>
11#include <linux/smp.h>
12#include <linux/irq.h>
13#include <linux/oprofile.h>
14#include <linux/rcupdate.h>
15
16
17#include <asm/nmi.h>
18#include <asm/apic.h>
19#include <asm/ptrace.h>
20
21static int nmi_timer_callback(struct pt_regs * regs, int cpu)
22{
23 oprofile_add_sample(regs, 0);
24 return 1;
25}
26
27static int timer_start(void)
28{
29 disable_timer_nmi_watchdog();
30 set_nmi_callback(nmi_timer_callback);
31 return 0;
32}
33
34
35static void timer_stop(void)
36{
37 enable_timer_nmi_watchdog();
38 unset_nmi_callback();
39 synchronize_kernel();
40}
41
42
43int __init nmi_timer_init(struct oprofile_operations * ops)
44{
45 extern int nmi_active;
46
47 if (nmi_active <= 0)
48 return -ENODEV;
49
50 ops->start = timer_start;
51 ops->stop = timer_stop;
52 ops->cpu_type = "timer";
53 printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
54 return 0;
55}
diff --git a/arch/i386/oprofile/op_counter.h b/arch/i386/oprofile/op_counter.h
new file mode 100644
index 000000000000..2880b15c4675
--- /dev/null
+++ b/arch/i386/oprofile/op_counter.h
@@ -0,0 +1,29 @@
1/**
2 * @file op_counter.h
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon
8 */
9
10#ifndef OP_COUNTER_H
11#define OP_COUNTER_H
12
13#define OP_MAX_COUNTER 8
14
15/* Per-perfctr configuration as set via
16 * oprofilefs.
17 */
18struct op_counter_config {
19 unsigned long count;
20 unsigned long enabled;
21 unsigned long event;
22 unsigned long kernel;
23 unsigned long user;
24 unsigned long unit_mask;
25};
26
27extern struct op_counter_config counter_config[];
28
29#endif /* OP_COUNTER_H */
diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c
new file mode 100644
index 000000000000..3ad9a72a5036
--- /dev/null
+++ b/arch/i386/oprofile/op_model_athlon.c
@@ -0,0 +1,149 @@
1/**
2 * @file op_model_athlon.h
3 * athlon / K7 model-specific MSR operations
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 * @author Graydon Hoare
11 */
12
13#include <linux/oprofile.h>
14#include <asm/ptrace.h>
15#include <asm/msr.h>
16
17#include "op_x86_model.h"
18#include "op_counter.h"
19
20#define NUM_COUNTERS 4
21#define NUM_CONTROLS 4
22
23#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
24#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0)
25#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
26
27#define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
28#define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
29#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
30#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
31#define CTRL_CLEAR(x) (x &= (1<<21))
32#define CTRL_SET_ENABLE(val) (val |= 1<<20)
33#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16))
34#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17))
35#define CTRL_SET_UM(val, m) (val |= (m << 8))
36#define CTRL_SET_EVENT(val, e) (val |= e)
37
38static unsigned long reset_value[NUM_COUNTERS];
39
40static void athlon_fill_in_addresses(struct op_msrs * const msrs)
41{
42 msrs->counters[0].addr = MSR_K7_PERFCTR0;
43 msrs->counters[1].addr = MSR_K7_PERFCTR1;
44 msrs->counters[2].addr = MSR_K7_PERFCTR2;
45 msrs->counters[3].addr = MSR_K7_PERFCTR3;
46
47 msrs->controls[0].addr = MSR_K7_EVNTSEL0;
48 msrs->controls[1].addr = MSR_K7_EVNTSEL1;
49 msrs->controls[2].addr = MSR_K7_EVNTSEL2;
50 msrs->controls[3].addr = MSR_K7_EVNTSEL3;
51}
52
53
54static void athlon_setup_ctrs(struct op_msrs const * const msrs)
55{
56 unsigned int low, high;
57 int i;
58
59 /* clear all counters */
60 for (i = 0 ; i < NUM_CONTROLS; ++i) {
61 CTRL_READ(low, high, msrs, i);
62 CTRL_CLEAR(low);
63 CTRL_WRITE(low, high, msrs, i);
64 }
65
66 /* avoid a false detection of ctr overflows in NMI handler */
67 for (i = 0; i < NUM_COUNTERS; ++i) {
68 CTR_WRITE(1, msrs, i);
69 }
70
71 /* enable active counters */
72 for (i = 0; i < NUM_COUNTERS; ++i) {
73 if (counter_config[i].enabled) {
74 reset_value[i] = counter_config[i].count;
75
76 CTR_WRITE(counter_config[i].count, msrs, i);
77
78 CTRL_READ(low, high, msrs, i);
79 CTRL_CLEAR(low);
80 CTRL_SET_ENABLE(low);
81 CTRL_SET_USR(low, counter_config[i].user);
82 CTRL_SET_KERN(low, counter_config[i].kernel);
83 CTRL_SET_UM(low, counter_config[i].unit_mask);
84 CTRL_SET_EVENT(low, counter_config[i].event);
85 CTRL_WRITE(low, high, msrs, i);
86 } else {
87 reset_value[i] = 0;
88 }
89 }
90}
91
92
93static int athlon_check_ctrs(struct pt_regs * const regs,
94 struct op_msrs const * const msrs)
95{
96 unsigned int low, high;
97 int i;
98
99 for (i = 0 ; i < NUM_COUNTERS; ++i) {
100 CTR_READ(low, high, msrs, i);
101 if (CTR_OVERFLOWED(low)) {
102 oprofile_add_sample(regs, i);
103 CTR_WRITE(reset_value[i], msrs, i);
104 }
105 }
106
107 /* See op_model_ppro.c */
108 return 1;
109}
110
111
112static void athlon_start(struct op_msrs const * const msrs)
113{
114 unsigned int low, high;
115 int i;
116 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
117 if (reset_value[i]) {
118 CTRL_READ(low, high, msrs, i);
119 CTRL_SET_ACTIVE(low);
120 CTRL_WRITE(low, high, msrs, i);
121 }
122 }
123}
124
125
126static void athlon_stop(struct op_msrs const * const msrs)
127{
128 unsigned int low,high;
129 int i;
130
131 /* Subtle: stop on all counters to avoid race with
132 * setting our pm callback */
133 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
134 CTRL_READ(low, high, msrs, i);
135 CTRL_SET_INACTIVE(low);
136 CTRL_WRITE(low, high, msrs, i);
137 }
138}
139
140
141struct op_x86_model_spec const op_athlon_spec = {
142 .num_counters = NUM_COUNTERS,
143 .num_controls = NUM_CONTROLS,
144 .fill_in_addresses = &athlon_fill_in_addresses,
145 .setup_ctrs = &athlon_setup_ctrs,
146 .check_ctrs = &athlon_check_ctrs,
147 .start = &athlon_start,
148 .stop = &athlon_stop
149};
diff --git a/arch/i386/oprofile/op_model_p4.c b/arch/i386/oprofile/op_model_p4.c
new file mode 100644
index 000000000000..ac8a066035c2
--- /dev/null
+++ b/arch/i386/oprofile/op_model_p4.c
@@ -0,0 +1,725 @@
1/**
2 * @file op_model_p4.c
3 * P4 model-specific MSR operations
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Graydon Hoare
9 */
10
11#include <linux/oprofile.h>
12#include <linux/smp.h>
13#include <asm/msr.h>
14#include <asm/ptrace.h>
15#include <asm/fixmap.h>
16#include <asm/apic.h>
17
18#include "op_x86_model.h"
19#include "op_counter.h"
20
21#define NUM_EVENTS 39
22
23#define NUM_COUNTERS_NON_HT 8
24#define NUM_ESCRS_NON_HT 45
25#define NUM_CCCRS_NON_HT 18
26#define NUM_CONTROLS_NON_HT (NUM_ESCRS_NON_HT + NUM_CCCRS_NON_HT)
27
28#define NUM_COUNTERS_HT2 4
29#define NUM_ESCRS_HT2 23
30#define NUM_CCCRS_HT2 9
31#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
32
33static unsigned int num_counters = NUM_COUNTERS_NON_HT;
34
35
36/* this has to be checked dynamically since the
37 hyper-threadedness of a chip is discovered at
38 kernel boot-time. */
39static inline void setup_num_counters(void)
40{
41#ifdef CONFIG_SMP
42 if (smp_num_siblings == 2)
43 num_counters = NUM_COUNTERS_HT2;
44#endif
45}
46
47static int inline addr_increment(void)
48{
49#ifdef CONFIG_SMP
50 return smp_num_siblings == 2 ? 2 : 1;
51#else
52 return 1;
53#endif
54}
55
56
57/* tables to simulate simplified hardware view of p4 registers */
58struct p4_counter_binding {
59 int virt_counter;
60 int counter_address;
61 int cccr_address;
62};
63
64struct p4_event_binding {
65 int escr_select; /* value to put in CCCR */
66 int event_select; /* value to put in ESCR */
67 struct {
68 int virt_counter; /* for this counter... */
69 int escr_address; /* use this ESCR */
70 } bindings[2];
71};
72
73/* nb: these CTR_* defines are a duplicate of defines in
74 event/i386.p4*events. */
75
76
77#define CTR_BPU_0 (1 << 0)
78#define CTR_MS_0 (1 << 1)
79#define CTR_FLAME_0 (1 << 2)
80#define CTR_IQ_4 (1 << 3)
81#define CTR_BPU_2 (1 << 4)
82#define CTR_MS_2 (1 << 5)
83#define CTR_FLAME_2 (1 << 6)
84#define CTR_IQ_5 (1 << 7)
85
86static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = {
87 { CTR_BPU_0, MSR_P4_BPU_PERFCTR0, MSR_P4_BPU_CCCR0 },
88 { CTR_MS_0, MSR_P4_MS_PERFCTR0, MSR_P4_MS_CCCR0 },
89 { CTR_FLAME_0, MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_CCCR0 },
90 { CTR_IQ_4, MSR_P4_IQ_PERFCTR4, MSR_P4_IQ_CCCR4 },
91 { CTR_BPU_2, MSR_P4_BPU_PERFCTR2, MSR_P4_BPU_CCCR2 },
92 { CTR_MS_2, MSR_P4_MS_PERFCTR2, MSR_P4_MS_CCCR2 },
93 { CTR_FLAME_2, MSR_P4_FLAME_PERFCTR2, MSR_P4_FLAME_CCCR2 },
94 { CTR_IQ_5, MSR_P4_IQ_PERFCTR5, MSR_P4_IQ_CCCR5 }
95};
96
97#define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT
98
99/* All cccr we don't use. */
100static int p4_unused_cccr[NUM_UNUSED_CCCRS] = {
101 MSR_P4_BPU_CCCR1, MSR_P4_BPU_CCCR3,
102 MSR_P4_MS_CCCR1, MSR_P4_MS_CCCR3,
103 MSR_P4_FLAME_CCCR1, MSR_P4_FLAME_CCCR3,
104 MSR_P4_IQ_CCCR0, MSR_P4_IQ_CCCR1,
105 MSR_P4_IQ_CCCR2, MSR_P4_IQ_CCCR3
106};
107
108/* p4 event codes in libop/op_event.h are indices into this table. */
109
110static struct p4_event_binding p4_events[NUM_EVENTS] = {
111
112 { /* BRANCH_RETIRED */
113 0x05, 0x06,
114 { {CTR_IQ_4, MSR_P4_CRU_ESCR2},
115 {CTR_IQ_5, MSR_P4_CRU_ESCR3} }
116 },
117
118 { /* MISPRED_BRANCH_RETIRED */
119 0x04, 0x03,
120 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
121 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
122 },
123
124 { /* TC_DELIVER_MODE */
125 0x01, 0x01,
126 { { CTR_MS_0, MSR_P4_TC_ESCR0},
127 { CTR_MS_2, MSR_P4_TC_ESCR1} }
128 },
129
130 { /* BPU_FETCH_REQUEST */
131 0x00, 0x03,
132 { { CTR_BPU_0, MSR_P4_BPU_ESCR0},
133 { CTR_BPU_2, MSR_P4_BPU_ESCR1} }
134 },
135
136 { /* ITLB_REFERENCE */
137 0x03, 0x18,
138 { { CTR_BPU_0, MSR_P4_ITLB_ESCR0},
139 { CTR_BPU_2, MSR_P4_ITLB_ESCR1} }
140 },
141
142 { /* MEMORY_CANCEL */
143 0x05, 0x02,
144 { { CTR_FLAME_0, MSR_P4_DAC_ESCR0},
145 { CTR_FLAME_2, MSR_P4_DAC_ESCR1} }
146 },
147
148 { /* MEMORY_COMPLETE */
149 0x02, 0x08,
150 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
151 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
152 },
153
154 { /* LOAD_PORT_REPLAY */
155 0x02, 0x04,
156 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
157 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
158 },
159
160 { /* STORE_PORT_REPLAY */
161 0x02, 0x05,
162 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
163 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
164 },
165
166 { /* MOB_LOAD_REPLAY */
167 0x02, 0x03,
168 { { CTR_BPU_0, MSR_P4_MOB_ESCR0},
169 { CTR_BPU_2, MSR_P4_MOB_ESCR1} }
170 },
171
172 { /* PAGE_WALK_TYPE */
173 0x04, 0x01,
174 { { CTR_BPU_0, MSR_P4_PMH_ESCR0},
175 { CTR_BPU_2, MSR_P4_PMH_ESCR1} }
176 },
177
178 { /* BSQ_CACHE_REFERENCE */
179 0x07, 0x0c,
180 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
181 { CTR_BPU_2, MSR_P4_BSU_ESCR1} }
182 },
183
184 { /* IOQ_ALLOCATION */
185 0x06, 0x03,
186 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
187 { 0, 0 } }
188 },
189
190 { /* IOQ_ACTIVE_ENTRIES */
191 0x06, 0x1a,
192 { { CTR_BPU_2, MSR_P4_FSB_ESCR1},
193 { 0, 0 } }
194 },
195
196 { /* FSB_DATA_ACTIVITY */
197 0x06, 0x17,
198 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
199 { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
200 },
201
202 { /* BSQ_ALLOCATION */
203 0x07, 0x05,
204 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
205 { 0, 0 } }
206 },
207
208 { /* BSQ_ACTIVE_ENTRIES */
209 0x07, 0x06,
210 { { CTR_BPU_2, MSR_P4_BSU_ESCR1 /* guess */},
211 { 0, 0 } }
212 },
213
214 { /* X87_ASSIST */
215 0x05, 0x03,
216 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
217 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
218 },
219
220 { /* SSE_INPUT_ASSIST */
221 0x01, 0x34,
222 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
223 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
224 },
225
226 { /* PACKED_SP_UOP */
227 0x01, 0x08,
228 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
229 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
230 },
231
232 { /* PACKED_DP_UOP */
233 0x01, 0x0c,
234 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
235 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
236 },
237
238 { /* SCALAR_SP_UOP */
239 0x01, 0x0a,
240 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
241 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
242 },
243
244 { /* SCALAR_DP_UOP */
245 0x01, 0x0e,
246 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
247 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
248 },
249
250 { /* 64BIT_MMX_UOP */
251 0x01, 0x02,
252 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
253 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
254 },
255
256 { /* 128BIT_MMX_UOP */
257 0x01, 0x1a,
258 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
259 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
260 },
261
262 { /* X87_FP_UOP */
263 0x01, 0x04,
264 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
265 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
266 },
267
268 { /* X87_SIMD_MOVES_UOP */
269 0x01, 0x2e,
270 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
271 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
272 },
273
274 { /* MACHINE_CLEAR */
275 0x05, 0x02,
276 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
277 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
278 },
279
280 { /* GLOBAL_POWER_EVENTS */
281 0x06, 0x13 /* older manual says 0x05, newer 0x13 */,
282 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
283 { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
284 },
285
286 { /* TC_MS_XFER */
287 0x00, 0x05,
288 { { CTR_MS_0, MSR_P4_MS_ESCR0},
289 { CTR_MS_2, MSR_P4_MS_ESCR1} }
290 },
291
292 { /* UOP_QUEUE_WRITES */
293 0x00, 0x09,
294 { { CTR_MS_0, MSR_P4_MS_ESCR0},
295 { CTR_MS_2, MSR_P4_MS_ESCR1} }
296 },
297
298 { /* FRONT_END_EVENT */
299 0x05, 0x08,
300 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
301 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
302 },
303
304 { /* EXECUTION_EVENT */
305 0x05, 0x0c,
306 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
307 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
308 },
309
310 { /* REPLAY_EVENT */
311 0x05, 0x09,
312 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
313 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
314 },
315
316 { /* INSTR_RETIRED */
317 0x04, 0x02,
318 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
319 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
320 },
321
322 { /* UOPS_RETIRED */
323 0x04, 0x01,
324 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
325 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
326 },
327
328 { /* UOP_TYPE */
329 0x02, 0x02,
330 { { CTR_IQ_4, MSR_P4_RAT_ESCR0},
331 { CTR_IQ_5, MSR_P4_RAT_ESCR1} }
332 },
333
334 { /* RETIRED_MISPRED_BRANCH_TYPE */
335 0x02, 0x05,
336 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
337 { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
338 },
339
340 { /* RETIRED_BRANCH_TYPE */
341 0x02, 0x04,
342 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
343 { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
344 }
345};
346
347
348#define MISC_PMC_ENABLED_P(x) ((x) & 1 << 7)
349
350#define ESCR_RESERVED_BITS 0x80000003
351#define ESCR_CLEAR(escr) ((escr) &= ESCR_RESERVED_BITS)
352#define ESCR_SET_USR_0(escr, usr) ((escr) |= (((usr) & 1) << 2))
353#define ESCR_SET_OS_0(escr, os) ((escr) |= (((os) & 1) << 3))
354#define ESCR_SET_USR_1(escr, usr) ((escr) |= (((usr) & 1)))
355#define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
356#define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25))
357#define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
358#define ESCR_READ(escr,high,ev,i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0)
359#define ESCR_WRITE(escr,high,ev,i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0)
360
361#define CCCR_RESERVED_BITS 0x38030FFF
362#define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
363#define CCCR_SET_REQUIRED_BITS(cccr) ((cccr) |= 0x00030000)
364#define CCCR_SET_ESCR_SELECT(cccr, sel) ((cccr) |= (((sel) & 0x07) << 13))
365#define CCCR_SET_PMI_OVF_0(cccr) ((cccr) |= (1<<26))
366#define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
367#define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
368#define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
369#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high));} while (0)
370#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high));} while (0)
371#define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
372#define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
373
374#define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0)
375#define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0)
376#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
377
378
379/* this assigns a "stagger" to the current CPU, which is used throughout
380 the code in this module as an extra array offset, to select the "even"
381 or "odd" part of all the divided resources. */
382static unsigned int get_stagger(void)
383{
384#ifdef CONFIG_SMP
385 int cpu = smp_processor_id();
386 return (cpu != first_cpu(cpu_sibling_map[cpu]));
387#endif
388 return 0;
389}
390
391
392/* finally, mediate access to a real hardware counter
393 by passing a "virtual" counter numer to this macro,
394 along with your stagger setting. */
395#define VIRT_CTR(stagger, i) ((i) + ((num_counters) * (stagger)))
396
397static unsigned long reset_value[NUM_COUNTERS_NON_HT];
398
399
400static void p4_fill_in_addresses(struct op_msrs * const msrs)
401{
402 unsigned int i;
403 unsigned int addr, stag;
404
405 setup_num_counters();
406 stag = get_stagger();
407
408 /* the counter registers we pay attention to */
409 for (i = 0; i < num_counters; ++i) {
410 msrs->counters[i].addr =
411 p4_counters[VIRT_CTR(stag, i)].counter_address;
412 }
413
414 /* FIXME: bad feeling, we don't save the 10 counters we don't use. */
415
416 /* 18 CCCR registers */
417 for (i = 0, addr = MSR_P4_BPU_CCCR0 + stag;
418 addr <= MSR_P4_IQ_CCCR5; ++i, addr += addr_increment()) {
419 msrs->controls[i].addr = addr;
420 }
421
422 /* 43 ESCR registers in three or four discontiguous group */
423 for (addr = MSR_P4_BSU_ESCR0 + stag;
424 addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
425 msrs->controls[i].addr = addr;
426 }
427
428 /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
429 * to avoid special case in nmi_{save|restore}_registers() */
430 if (boot_cpu_data.x86_model >= 0x3) {
431 for (addr = MSR_P4_BSU_ESCR0 + stag;
432 addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
433 msrs->controls[i].addr = addr;
434 }
435 } else {
436 for (addr = MSR_P4_IQ_ESCR0 + stag;
437 addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
438 msrs->controls[i].addr = addr;
439 }
440 }
441
442 for (addr = MSR_P4_RAT_ESCR0 + stag;
443 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
444 msrs->controls[i].addr = addr;
445 }
446
447 for (addr = MSR_P4_MS_ESCR0 + stag;
448 addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
449 msrs->controls[i].addr = addr;
450 }
451
452 for (addr = MSR_P4_IX_ESCR0 + stag;
453 addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
454 msrs->controls[i].addr = addr;
455 }
456
457 /* there are 2 remaining non-contiguously located ESCRs */
458
459 if (num_counters == NUM_COUNTERS_NON_HT) {
460 /* standard non-HT CPUs handle both remaining ESCRs*/
461 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
462 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
463
464 } else if (stag == 0) {
465 /* HT CPUs give the first remainder to the even thread, as
466 the 32nd control register */
467 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
468
469 } else {
470 /* and two copies of the second to the odd thread,
471 for the 22st and 23nd control registers */
472 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
473 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
474 }
475}
476
477
478static void pmc_setup_one_p4_counter(unsigned int ctr)
479{
480 int i;
481 int const maxbind = 2;
482 unsigned int cccr = 0;
483 unsigned int escr = 0;
484 unsigned int high = 0;
485 unsigned int counter_bit;
486 struct p4_event_binding *ev = NULL;
487 unsigned int stag;
488
489 stag = get_stagger();
490
491 /* convert from counter *number* to counter *bit* */
492 counter_bit = 1 << VIRT_CTR(stag, ctr);
493
494 /* find our event binding structure. */
495 if (counter_config[ctr].event <= 0 || counter_config[ctr].event > NUM_EVENTS) {
496 printk(KERN_ERR
497 "oprofile: P4 event code 0x%lx out of range\n",
498 counter_config[ctr].event);
499 return;
500 }
501
502 ev = &(p4_events[counter_config[ctr].event - 1]);
503
504 for (i = 0; i < maxbind; i++) {
505 if (ev->bindings[i].virt_counter & counter_bit) {
506
507 /* modify ESCR */
508 ESCR_READ(escr, high, ev, i);
509 ESCR_CLEAR(escr);
510 if (stag == 0) {
511 ESCR_SET_USR_0(escr, counter_config[ctr].user);
512 ESCR_SET_OS_0(escr, counter_config[ctr].kernel);
513 } else {
514 ESCR_SET_USR_1(escr, counter_config[ctr].user);
515 ESCR_SET_OS_1(escr, counter_config[ctr].kernel);
516 }
517 ESCR_SET_EVENT_SELECT(escr, ev->event_select);
518 ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
519 ESCR_WRITE(escr, high, ev, i);
520
521 /* modify CCCR */
522 CCCR_READ(cccr, high, VIRT_CTR(stag, ctr));
523 CCCR_CLEAR(cccr);
524 CCCR_SET_REQUIRED_BITS(cccr);
525 CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
526 if (stag == 0) {
527 CCCR_SET_PMI_OVF_0(cccr);
528 } else {
529 CCCR_SET_PMI_OVF_1(cccr);
530 }
531 CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr));
532 return;
533 }
534 }
535
536 printk(KERN_ERR
537 "oprofile: P4 event code 0x%lx no binding, stag %d ctr %d\n",
538 counter_config[ctr].event, stag, ctr);
539}
540
541
542static void p4_setup_ctrs(struct op_msrs const * const msrs)
543{
544 unsigned int i;
545 unsigned int low, high;
546 unsigned int addr;
547 unsigned int stag;
548
549 stag = get_stagger();
550
551 rdmsr(MSR_IA32_MISC_ENABLE, low, high);
552 if (! MISC_PMC_ENABLED_P(low)) {
553 printk(KERN_ERR "oprofile: P4 PMC not available\n");
554 return;
555 }
556
557 /* clear the cccrs we will use */
558 for (i = 0 ; i < num_counters ; i++) {
559 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
560 CCCR_CLEAR(low);
561 CCCR_SET_REQUIRED_BITS(low);
562 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
563 }
564
565 /* clear cccrs outside our concern */
566 for (i = stag ; i < NUM_UNUSED_CCCRS ; i += addr_increment()) {
567 rdmsr(p4_unused_cccr[i], low, high);
568 CCCR_CLEAR(low);
569 CCCR_SET_REQUIRED_BITS(low);
570 wrmsr(p4_unused_cccr[i], low, high);
571 }
572
573 /* clear all escrs (including those outside our concern) */
574 for (addr = MSR_P4_BSU_ESCR0 + stag;
575 addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) {
576 wrmsr(addr, 0, 0);
577 }
578
579 /* On older models clear also MSR_P4_IQ_ESCR0/1 */
580 if (boot_cpu_data.x86_model < 0x3) {
581 wrmsr(MSR_P4_IQ_ESCR0, 0, 0);
582 wrmsr(MSR_P4_IQ_ESCR1, 0, 0);
583 }
584
585 for (addr = MSR_P4_RAT_ESCR0 + stag;
586 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
587 wrmsr(addr, 0, 0);
588 }
589
590 for (addr = MSR_P4_MS_ESCR0 + stag;
591 addr <= MSR_P4_TC_ESCR1; addr += addr_increment()){
592 wrmsr(addr, 0, 0);
593 }
594
595 for (addr = MSR_P4_IX_ESCR0 + stag;
596 addr <= MSR_P4_CRU_ESCR3; addr += addr_increment()){
597 wrmsr(addr, 0, 0);
598 }
599
600 if (num_counters == NUM_COUNTERS_NON_HT) {
601 wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
602 wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
603 } else if (stag == 0) {
604 wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
605 } else {
606 wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
607 }
608
609 /* setup all counters */
610 for (i = 0 ; i < num_counters ; ++i) {
611 if (counter_config[i].enabled) {
612 reset_value[i] = counter_config[i].count;
613 pmc_setup_one_p4_counter(i);
614 CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
615 } else {
616 reset_value[i] = 0;
617 }
618 }
619}
620
621
622static int p4_check_ctrs(struct pt_regs * const regs,
623 struct op_msrs const * const msrs)
624{
625 unsigned long ctr, low, high, stag, real;
626 int i;
627
628 stag = get_stagger();
629
630 for (i = 0; i < num_counters; ++i) {
631
632 if (!reset_value[i])
633 continue;
634
635 /*
636 * there is some eccentricity in the hardware which
637 * requires that we perform 2 extra corrections:
638 *
639 * - check both the CCCR:OVF flag for overflow and the
640 * counter high bit for un-flagged overflows.
641 *
642 * - write the counter back twice to ensure it gets
643 * updated properly.
644 *
645 * the former seems to be related to extra NMIs happening
646 * during the current NMI; the latter is reported as errata
647 * N15 in intel doc 249199-029, pentium 4 specification
648 * update, though their suggested work-around does not
649 * appear to solve the problem.
650 */
651
652 real = VIRT_CTR(stag, i);
653
654 CCCR_READ(low, high, real);
655 CTR_READ(ctr, high, real);
656 if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
657 oprofile_add_sample(regs, i);
658 CTR_WRITE(reset_value[i], real);
659 CCCR_CLEAR_OVF(low);
660 CCCR_WRITE(low, high, real);
661 CTR_WRITE(reset_value[i], real);
662 }
663 }
664
665 /* P4 quirk: you have to re-unmask the apic vector */
666 apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
667
668 /* See op_model_ppro.c */
669 return 1;
670}
671
672
673static void p4_start(struct op_msrs const * const msrs)
674{
675 unsigned int low, high, stag;
676 int i;
677
678 stag = get_stagger();
679
680 for (i = 0; i < num_counters; ++i) {
681 if (!reset_value[i])
682 continue;
683 CCCR_READ(low, high, VIRT_CTR(stag, i));
684 CCCR_SET_ENABLE(low);
685 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
686 }
687}
688
689
690static void p4_stop(struct op_msrs const * const msrs)
691{
692 unsigned int low, high, stag;
693 int i;
694
695 stag = get_stagger();
696
697 for (i = 0; i < num_counters; ++i) {
698 CCCR_READ(low, high, VIRT_CTR(stag, i));
699 CCCR_SET_DISABLE(low);
700 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
701 }
702}
703
704
705#ifdef CONFIG_SMP
706struct op_x86_model_spec const op_p4_ht2_spec = {
707 .num_counters = NUM_COUNTERS_HT2,
708 .num_controls = NUM_CONTROLS_HT2,
709 .fill_in_addresses = &p4_fill_in_addresses,
710 .setup_ctrs = &p4_setup_ctrs,
711 .check_ctrs = &p4_check_ctrs,
712 .start = &p4_start,
713 .stop = &p4_stop
714};
715#endif
716
717struct op_x86_model_spec const op_p4_spec = {
718 .num_counters = NUM_COUNTERS_NON_HT,
719 .num_controls = NUM_CONTROLS_NON_HT,
720 .fill_in_addresses = &p4_fill_in_addresses,
721 .setup_ctrs = &p4_setup_ctrs,
722 .check_ctrs = &p4_check_ctrs,
723 .start = &p4_start,
724 .stop = &p4_stop
725};
diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c
new file mode 100644
index 000000000000..d719015fc044
--- /dev/null
+++ b/arch/i386/oprofile/op_model_ppro.c
@@ -0,0 +1,143 @@
1/**
2 * @file op_model_ppro.h
3 * pentium pro / P6 model-specific MSR operations
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 * @author Graydon Hoare
11 */
12
13#include <linux/oprofile.h>
14#include <asm/ptrace.h>
15#include <asm/msr.h>
16#include <asm/apic.h>
17
18#include "op_x86_model.h"
19#include "op_counter.h"
20
21#define NUM_COUNTERS 2
22#define NUM_CONTROLS 2
23
24#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
25#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0)
26#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
27
28#define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
29#define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
30#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
31#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
32#define CTRL_CLEAR(x) (x &= (1<<21))
33#define CTRL_SET_ENABLE(val) (val |= 1<<20)
34#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16))
35#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17))
36#define CTRL_SET_UM(val, m) (val |= (m << 8))
37#define CTRL_SET_EVENT(val, e) (val |= e)
38
39static unsigned long reset_value[NUM_COUNTERS];
40
41static void ppro_fill_in_addresses(struct op_msrs * const msrs)
42{
43 msrs->counters[0].addr = MSR_P6_PERFCTR0;
44 msrs->counters[1].addr = MSR_P6_PERFCTR1;
45
46 msrs->controls[0].addr = MSR_P6_EVNTSEL0;
47 msrs->controls[1].addr = MSR_P6_EVNTSEL1;
48}
49
50
51static void ppro_setup_ctrs(struct op_msrs const * const msrs)
52{
53 unsigned int low, high;
54 int i;
55
56 /* clear all counters */
57 for (i = 0 ; i < NUM_CONTROLS; ++i) {
58 CTRL_READ(low, high, msrs, i);
59 CTRL_CLEAR(low);
60 CTRL_WRITE(low, high, msrs, i);
61 }
62
63 /* avoid a false detection of ctr overflows in NMI handler */
64 for (i = 0; i < NUM_COUNTERS; ++i) {
65 CTR_WRITE(1, msrs, i);
66 }
67
68 /* enable active counters */
69 for (i = 0; i < NUM_COUNTERS; ++i) {
70 if (counter_config[i].enabled) {
71 reset_value[i] = counter_config[i].count;
72
73 CTR_WRITE(counter_config[i].count, msrs, i);
74
75 CTRL_READ(low, high, msrs, i);
76 CTRL_CLEAR(low);
77 CTRL_SET_ENABLE(low);
78 CTRL_SET_USR(low, counter_config[i].user);
79 CTRL_SET_KERN(low, counter_config[i].kernel);
80 CTRL_SET_UM(low, counter_config[i].unit_mask);
81 CTRL_SET_EVENT(low, counter_config[i].event);
82 CTRL_WRITE(low, high, msrs, i);
83 }
84 }
85}
86
87
88static int ppro_check_ctrs(struct pt_regs * const regs,
89 struct op_msrs const * const msrs)
90{
91 unsigned int low, high;
92 int i;
93
94 for (i = 0 ; i < NUM_COUNTERS; ++i) {
95 CTR_READ(low, high, msrs, i);
96 if (CTR_OVERFLOWED(low)) {
97 oprofile_add_sample(regs, i);
98 CTR_WRITE(reset_value[i], msrs, i);
99 }
100 }
101
102 /* Only P6 based Pentium M need to re-unmask the apic vector but it
103 * doesn't hurt other P6 variant */
104 apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
105
106 /* We can't work out if we really handled an interrupt. We
107 * might have caught a *second* counter just after overflowing
108 * the interrupt for this counter then arrives
109 * and we don't find a counter that's overflowed, so we
110 * would return 0 and get dazed + confused. Instead we always
111 * assume we found an overflow. This sucks.
112 */
113 return 1;
114}
115
116
117static void ppro_start(struct op_msrs const * const msrs)
118{
119 unsigned int low,high;
120 CTRL_READ(low, high, msrs, 0);
121 CTRL_SET_ACTIVE(low);
122 CTRL_WRITE(low, high, msrs, 0);
123}
124
125
126static void ppro_stop(struct op_msrs const * const msrs)
127{
128 unsigned int low,high;
129 CTRL_READ(low, high, msrs, 0);
130 CTRL_SET_INACTIVE(low);
131 CTRL_WRITE(low, high, msrs, 0);
132}
133
134
135struct op_x86_model_spec const op_ppro_spec = {
136 .num_counters = NUM_COUNTERS,
137 .num_controls = NUM_CONTROLS,
138 .fill_in_addresses = &ppro_fill_in_addresses,
139 .setup_ctrs = &ppro_setup_ctrs,
140 .check_ctrs = &ppro_check_ctrs,
141 .start = &ppro_start,
142 .stop = &ppro_stop
143};
diff --git a/arch/i386/oprofile/op_x86_model.h b/arch/i386/oprofile/op_x86_model.h
new file mode 100644
index 000000000000..123b7e90a9ee
--- /dev/null
+++ b/arch/i386/oprofile/op_x86_model.h
@@ -0,0 +1,50 @@
1/**
2 * @file op_x86_model.h
3 * interface to x86 model-specific MSR operations
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Graydon Hoare
9 */
10
11#ifndef OP_X86_MODEL_H
12#define OP_X86_MODEL_H
13
14struct op_saved_msr {
15 unsigned int high;
16 unsigned int low;
17};
18
19struct op_msr {
20 unsigned long addr;
21 struct op_saved_msr saved;
22};
23
24struct op_msrs {
25 struct op_msr * counters;
26 struct op_msr * controls;
27};
28
29struct pt_regs;
30
31/* The model vtable abstracts the differences between
32 * various x86 CPU model's perfctr support.
33 */
34struct op_x86_model_spec {
35 unsigned int const num_counters;
36 unsigned int const num_controls;
37 void (*fill_in_addresses)(struct op_msrs * const msrs);
38 void (*setup_ctrs)(struct op_msrs const * const msrs);
39 int (*check_ctrs)(struct pt_regs * const regs,
40 struct op_msrs const * const msrs);
41 void (*start)(struct op_msrs const * const msrs);
42 void (*stop)(struct op_msrs const * const msrs);
43};
44
45extern struct op_x86_model_spec const op_ppro_spec;
46extern struct op_x86_model_spec const op_p4_spec;
47extern struct op_x86_model_spec const op_p4_ht2_spec;
48extern struct op_x86_model_spec const op_athlon_spec;
49
50#endif /* OP_X86_MODEL_H */