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 "op_x86_model.h"
14 #include "op_arch.h"
15 #include "op_msr.h"
16
17 #define NUM_COUNTERS 4
18 #define NUM_CONTROLS 4
19
20 #define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters.addrs[(c)], (l), (h));} while (0)
21 #define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters.addrs[(c)], -(u32)(l), 0xffff);} while (0)
22 #define CTR_OVERFLOWED(n) (!((n) & (1U << 31)))
23
24 #define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls.addrs[(c)], (l), (h));} while (0)
25 #define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls.addrs[(c)], (l), (h));} while (0)
26 #define CTRL_SET_ACTIVE(n) (n |= (1 << 22))
27 #define CTRL_SET_INACTIVE(n) (n &= ~(1 << 22))
28 #define CTRL_CLEAR(x) (x &= (1 << 21))
29 #define CTRL_SET_ENABLE(val) (val |= 1 << 20)
30 #define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
31 #define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
32 #define CTRL_SET_UM(val, m) (val |= (m << 8))
33 #define CTRL_SET_EVENT(val, e) (val |= e)
34
35
athlon_fill_in_addresses(struct op_msrs * const msrs)36 static void athlon_fill_in_addresses(struct op_msrs * const msrs)
37 {
38 msrs->counters.addrs[0] = MSR_K7_PERFCTR0;
39 msrs->counters.addrs[1] = MSR_K7_PERFCTR1;
40 msrs->counters.addrs[2] = MSR_K7_PERFCTR2;
41 msrs->counters.addrs[3] = MSR_K7_PERFCTR3;
42
43 msrs->controls.addrs[0] = MSR_K7_EVNTSEL0;
44 msrs->controls.addrs[1] = MSR_K7_EVNTSEL1;
45 msrs->controls.addrs[2] = MSR_K7_EVNTSEL2;
46 msrs->controls.addrs[3] = MSR_K7_EVNTSEL3;
47 }
48
49
athlon_setup_ctrs(struct op_msrs const * const msrs)50 static void athlon_setup_ctrs(struct op_msrs const * const msrs)
51 {
52 uint low, high;
53 int i;
54
55 /* clear all counters */
56 for (i = 0 ; i < NUM_CONTROLS; ++i) {
57 CTRL_READ(low, high, msrs, i);
58 CTRL_CLEAR(low);
59 CTRL_WRITE(low, high, msrs, i);
60 }
61
62 /* avoid a false detection of ctr overflows in NMI handler */
63 for (i = 0; i < NUM_COUNTERS; ++i)
64 CTR_WRITE(1, msrs, i);
65
66 /* enable active counters */
67 for (i = 0; i < NUM_COUNTERS; ++i) {
68 if (sysctl.ctr[i].enabled) {
69
70 CTR_WRITE(sysctl.ctr[i].count, msrs, i);
71
72 CTRL_READ(low, high, msrs, i);
73 CTRL_CLEAR(low);
74 CTRL_SET_ENABLE(low);
75 CTRL_SET_USR(low, sysctl.ctr[i].user);
76 CTRL_SET_KERN(low, sysctl.ctr[i].kernel);
77 CTRL_SET_UM(low, sysctl.ctr[i].unit_mask);
78 CTRL_SET_EVENT(low, sysctl.ctr[i].event);
79 CTRL_WRITE(low, high, msrs, i);
80 }
81 }
82 }
83
84
athlon_check_ctrs(uint const cpu,struct op_msrs const * const msrs,struct pt_regs * const regs)85 static void athlon_check_ctrs(uint const cpu,
86 struct op_msrs const * const msrs,
87 struct pt_regs * const regs)
88 {
89 uint low, high;
90 int i;
91 for (i = 0 ; i < NUM_COUNTERS; ++i) {
92 if (sysctl.ctr[i].enabled) {
93 CTR_READ(low, high, msrs, i);
94 if (CTR_OVERFLOWED(low)) {
95 op_do_profile(cpu, instruction_pointer(regs), IRQ_ENABLED(regs), i);
96 CTR_WRITE(oprof_data[cpu].ctr_count[i], msrs, i);
97 }
98 }
99 }
100 }
101
102
athlon_start(struct op_msrs const * const msrs)103 static void athlon_start(struct op_msrs const * const msrs)
104 {
105 uint low, high;
106 int i;
107 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
108 if (sysctl.ctr[i].enabled) {
109 CTRL_READ(low, high, msrs, i);
110 CTRL_SET_ACTIVE(low);
111 CTRL_WRITE(low, high, msrs, i);
112 }
113 }
114 }
115
116
athlon_stop(struct op_msrs const * const msrs)117 static void athlon_stop(struct op_msrs const * const msrs)
118 {
119 uint low, high;
120 int i;
121 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
122 if (sysctl.ctr[i].enabled) {
123 CTRL_READ(low, high, msrs, i);
124 CTRL_SET_INACTIVE(low);
125 CTRL_WRITE(low, high, msrs, i);
126 }
127 }
128 }
129
130
131 struct op_x86_model_spec const op_athlon_spec = {
132 .num_counters = NUM_COUNTERS,
133 .num_controls = NUM_CONTROLS,
134 .fill_in_addresses = &athlon_fill_in_addresses,
135 .setup_ctrs = &athlon_setup_ctrs,
136 .check_ctrs = &athlon_check_ctrs,
137 .start = &athlon_start,
138 .stop = &athlon_stop
139 };
140