2 * @file op_model_ppro.h
3 * pentium pro / P6 model-specific MSR operations
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
9 * @author Philippe Elie
10 * @author Graydon Hoare
13 #include <linux/oprofile.h>
14 #include <asm/ptrace.h>
19 #include "op_x86_model.h"
20 #include "op_counter.h"
22 #define NUM_COUNTERS 2
23 #define NUM_CONTROLS 2
25 #define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
26 #define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
27 #define CTR_32BIT_WRITE(l, msrs, c) \
28 do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), 0); } while (0)
29 #define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
31 #define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
32 #define CTRL_READ(l, h, msrs, c) do {rdmsr((msrs->controls[(c)].addr), (l), (h)); } while (0)
33 #define CTRL_WRITE(l, h, msrs, c) do {wrmsr((msrs->controls[(c)].addr), (l), (h)); } while (0)
34 #define CTRL_SET_ACTIVE(n) (n |= (1<<22))
35 #define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
36 #define CTRL_CLEAR(x) (x &= (1<<21))
37 #define CTRL_SET_ENABLE(val) (val |= 1<<20)
38 #define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
39 #define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
40 #define CTRL_SET_UM(val, m) (val |= (m << 8))
41 #define CTRL_SET_EVENT(val, e) (val |= e)
43 static unsigned long reset_value
[NUM_COUNTERS
];
45 static void ppro_fill_in_addresses(struct op_msrs
* const msrs
)
49 for (i
= 0; i
< NUM_COUNTERS
; i
++) {
50 if (reserve_perfctr_nmi(MSR_P6_PERFCTR0
+ i
))
51 msrs
->counters
[i
].addr
= MSR_P6_PERFCTR0
+ i
;
53 msrs
->counters
[i
].addr
= 0;
56 for (i
= 0; i
< NUM_CONTROLS
; i
++) {
57 if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0
+ i
))
58 msrs
->controls
[i
].addr
= MSR_P6_EVNTSEL0
+ i
;
60 msrs
->controls
[i
].addr
= 0;
65 static void ppro_setup_ctrs(struct op_msrs
const * const msrs
)
67 unsigned int low
, high
;
70 /* clear all counters */
71 for (i
= 0 ; i
< NUM_CONTROLS
; ++i
) {
72 if (unlikely(!CTRL_IS_RESERVED(msrs
, i
)))
74 CTRL_READ(low
, high
, msrs
, i
);
76 CTRL_WRITE(low
, high
, msrs
, i
);
79 /* avoid a false detection of ctr overflows in NMI handler */
80 for (i
= 0; i
< NUM_COUNTERS
; ++i
) {
81 if (unlikely(!CTR_IS_RESERVED(msrs
, i
)))
83 CTR_32BIT_WRITE(1, msrs
, i
);
86 /* enable active counters */
87 for (i
= 0; i
< NUM_COUNTERS
; ++i
) {
88 if ((counter_config
[i
].enabled
) && (CTR_IS_RESERVED(msrs
, i
))) {
89 reset_value
[i
] = counter_config
[i
].count
;
91 CTR_32BIT_WRITE(counter_config
[i
].count
, msrs
, i
);
93 CTRL_READ(low
, high
, msrs
, i
);
96 CTRL_SET_USR(low
, counter_config
[i
].user
);
97 CTRL_SET_KERN(low
, counter_config
[i
].kernel
);
98 CTRL_SET_UM(low
, counter_config
[i
].unit_mask
);
99 CTRL_SET_EVENT(low
, counter_config
[i
].event
);
100 CTRL_WRITE(low
, high
, msrs
, i
);
108 static int ppro_check_ctrs(struct pt_regs
* const regs
,
109 struct op_msrs
const * const msrs
)
111 unsigned int low
, high
;
114 for (i
= 0 ; i
< NUM_COUNTERS
; ++i
) {
117 CTR_READ(low
, high
, msrs
, i
);
118 if (CTR_OVERFLOWED(low
)) {
119 oprofile_add_sample(regs
, i
);
120 CTR_32BIT_WRITE(reset_value
[i
], msrs
, i
);
124 /* Only P6 based Pentium M need to re-unmask the apic vector but it
125 * doesn't hurt other P6 variant */
126 apic_write(APIC_LVTPC
, apic_read(APIC_LVTPC
) & ~APIC_LVT_MASKED
);
128 /* We can't work out if we really handled an interrupt. We
129 * might have caught a *second* counter just after overflowing
130 * the interrupt for this counter then arrives
131 * and we don't find a counter that's overflowed, so we
132 * would return 0 and get dazed + confused. Instead we always
133 * assume we found an overflow. This sucks.
139 static void ppro_start(struct op_msrs
const * const msrs
)
141 unsigned int low
, high
;
144 for (i
= 0; i
< NUM_COUNTERS
; ++i
) {
145 if (reset_value
[i
]) {
146 CTRL_READ(low
, high
, msrs
, i
);
147 CTRL_SET_ACTIVE(low
);
148 CTRL_WRITE(low
, high
, msrs
, i
);
154 static void ppro_stop(struct op_msrs
const * const msrs
)
156 unsigned int low
, high
;
159 for (i
= 0; i
< NUM_COUNTERS
; ++i
) {
162 CTRL_READ(low
, high
, msrs
, i
);
163 CTRL_SET_INACTIVE(low
);
164 CTRL_WRITE(low
, high
, msrs
, i
);
168 static void ppro_shutdown(struct op_msrs
const * const msrs
)
172 for (i
= 0 ; i
< NUM_COUNTERS
; ++i
) {
173 if (CTR_IS_RESERVED(msrs
, i
))
174 release_perfctr_nmi(MSR_P6_PERFCTR0
+ i
);
176 for (i
= 0 ; i
< NUM_CONTROLS
; ++i
) {
177 if (CTRL_IS_RESERVED(msrs
, i
))
178 release_evntsel_nmi(MSR_P6_EVNTSEL0
+ i
);
183 struct op_x86_model_spec
const op_ppro_spec
= {
184 .num_counters
= NUM_COUNTERS
,
185 .num_controls
= NUM_CONTROLS
,
186 .fill_in_addresses
= &ppro_fill_in_addresses
,
187 .setup_ctrs
= &ppro_setup_ctrs
,
188 .check_ctrs
= &ppro_check_ctrs
,
189 .start
= &ppro_start
,
191 .shutdown
= &ppro_shutdown