1
2
3
4
5
6
7
8
9
10
11#include <linux/oprofile.h>
12#include <linux/smp.h>
13#include <asm/ptrace.h>
14
15#include "op_impl.h"
16
17
18
19
20static void
21ev67_reg_setup(struct op_register_config *reg,
22 struct op_counter_config *ctr,
23 struct op_system_config *sys)
24{
25 unsigned long ctl, reset, need_reset, i;
26
27
28 ctl = 1UL << 4;
29
30
31
32 if (ctr[1].enabled) {
33 ctl |= (ctr[1].event & 3) << 2;
34 } else {
35 if (ctr[0].event == 0)
36 ctl |= 1UL << 2;
37 }
38 reg->mux_select = ctl;
39
40
41
42
43
44 reg->proc_mode = 0;
45
46
47
48
49
50 reset = need_reset = 0;
51 for (i = 0; i < 2; ++i) {
52 unsigned long count = ctr[i].count;
53 if (!ctr[i].enabled)
54 continue;
55
56 if (count > 0x100000)
57 count = 0x100000;
58 ctr[i].count = count;
59 reset |= (0x100000 - count) << (i ? 6 : 28);
60 if (count != 0x100000)
61 need_reset |= 1 << i;
62 }
63 reg->reset_values = reset;
64 reg->need_reset = need_reset;
65}
66
67
68
69static void
70ev67_cpu_setup (void *x)
71{
72 struct op_register_config *reg = x;
73
74 wrperfmon(2, reg->mux_select);
75 wrperfmon(3, reg->proc_mode);
76 wrperfmon(6, reg->reset_values | 3);
77}
78
79
80
81
82
83static void
84ev67_reset_ctr(struct op_register_config *reg, unsigned long ctr)
85{
86 wrperfmon(6, reg->reset_values | (1 << ctr));
87}
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117enum profileme_counters {
118 PM_STALLED,
119
120 PM_TAKEN,
121 PM_MISPREDICT,
122 PM_ITB_MISS,
123 PM_DTB_MISS,
124 PM_REPLAY,
125 PM_LOAD_STORE,
126 PM_ICACHE_MISS,
127 PM_UNALIGNED,
128 PM_NUM_COUNTERS
129};
130
131static inline void
132op_add_pm(unsigned long pc, int kern, unsigned long counter,
133 struct op_counter_config *ctr, unsigned long event)
134{
135 unsigned long fake_counter = 2 + event;
136 if (counter == 1)
137 fake_counter += PM_NUM_COUNTERS;
138 if (ctr[fake_counter].enabled)
139 oprofile_add_pc(pc, kern, fake_counter);
140}
141
142static void
143ev67_handle_interrupt(unsigned long which, struct pt_regs *regs,
144 struct op_counter_config *ctr)
145{
146 unsigned long pmpc, pctr_ctl;
147 int kern = !user_mode(regs);
148 int mispredict = 0;
149 union {
150 unsigned long v;
151 struct {
152 unsigned reserved: 30;
153 unsigned overcount: 3;
154 unsigned icache_miss: 1;
155 unsigned trap_type: 4;
156 unsigned load_store: 1;
157 unsigned trap: 1;
158 unsigned mispredict: 1;
159 } fields;
160 } i_stat;
161
162 enum trap_types {
163 TRAP_REPLAY,
164 TRAP_INVALID0,
165 TRAP_DTB_DOUBLE_MISS_3,
166 TRAP_DTB_DOUBLE_MISS_4,
167 TRAP_FP_DISABLED,
168 TRAP_UNALIGNED,
169 TRAP_DTB_SINGLE_MISS,
170 TRAP_DSTREAM_FAULT,
171 TRAP_OPCDEC,
172 TRAP_INVALID1,
173 TRAP_MACHINE_CHECK,
174 TRAP_INVALID2,
175 TRAP_ARITHMETIC,
176 TRAP_INVALID3,
177 TRAP_MT_FPCR,
178 TRAP_RESET
179 };
180
181 pmpc = wrperfmon(9, 0);
182
183 if (pmpc & 1)
184 return;
185 pmpc &= ~2;
186
187 i_stat.v = wrperfmon(8, 0);
188 if (i_stat.fields.trap) {
189 switch (i_stat.fields.trap_type) {
190 case TRAP_INVALID1:
191 case TRAP_INVALID2:
192 case TRAP_INVALID3:
193
194
195
196
197 oprofile_add_pc(regs->pc, kern, which);
198 if ((pmpc & ((1 << 15) - 1)) == 581)
199 op_add_pm(regs->pc, kern, which,
200 ctr, PM_ITB_MISS);
201
202
203
204 return;
205 case TRAP_REPLAY:
206 op_add_pm(pmpc, kern, which, ctr,
207 (i_stat.fields.load_store
208 ? PM_LOAD_STORE : PM_REPLAY));
209 break;
210 case TRAP_DTB_DOUBLE_MISS_3:
211 case TRAP_DTB_DOUBLE_MISS_4:
212 case TRAP_DTB_SINGLE_MISS:
213 op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS);
214 break;
215 case TRAP_UNALIGNED:
216 op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED);
217 break;
218 case TRAP_INVALID0:
219 case TRAP_FP_DISABLED:
220 case TRAP_DSTREAM_FAULT:
221 case TRAP_OPCDEC:
222 case TRAP_MACHINE_CHECK:
223 case TRAP_ARITHMETIC:
224 case TRAP_MT_FPCR:
225 case TRAP_RESET:
226 break;
227 }
228
229
230
231
232
233
234 if (i_stat.fields.mispredict) {
235 mispredict = 1;
236 op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT);
237 }
238 }
239
240 oprofile_add_pc(pmpc, kern, which);
241
242 pctr_ctl = wrperfmon(5, 0);
243 if (pctr_ctl & (1UL << 27))
244 op_add_pm(pmpc, kern, which, ctr, PM_STALLED);
245
246
247
248
249 if (!mispredict && pctr_ctl & (1UL << 0))
250 op_add_pm(pmpc, kern, which, ctr, PM_TAKEN);
251}
252
253struct op_axp_model op_model_ev67 = {
254 .reg_setup = ev67_reg_setup,
255 .cpu_setup = ev67_cpu_setup,
256 .reset_ctr = ev67_reset_ctr,
257 .handle_interrupt = ev67_handle_interrupt,
258 .cpu_type = "alpha/ev67",
259 .num_counters = 20,
260 .can_set_proc_mode = 0,
261};
262