Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/alpha/oprofile/op_model_ev5.c
10817 views
1
/**
2
* @file arch/alpha/oprofile/op_model_ev5.c
3
*
4
* @remark Copyright 2002 OProfile authors
5
* @remark Read the file COPYING
6
*
7
* @author Richard Henderson <[email protected]>
8
*/
9
10
#include <linux/oprofile.h>
11
#include <linux/init.h>
12
#include <linux/smp.h>
13
#include <asm/ptrace.h>
14
#include <asm/system.h>
15
16
#include "op_impl.h"
17
18
19
/* Compute all of the registers in preparation for enabling profiling.
20
21
The 21164 (EV5) and 21164PC (PCA65) vary in the bit placement and
22
meaning of the "CBOX" events. Given that we don't care about meaning
23
at this point, arrange for the difference in bit placement to be
24
handled by common code. */
25
26
static void
27
common_reg_setup(struct op_register_config *reg,
28
struct op_counter_config *ctr,
29
struct op_system_config *sys,
30
int cbox1_ofs, int cbox2_ofs)
31
{
32
int i, ctl, reset, need_reset;
33
34
/* Select desired events. The event numbers are selected such
35
that they map directly into the event selection fields:
36
37
PCSEL0: 0, 1
38
PCSEL1: 24-39
39
CBOX1: 40-47
40
PCSEL2: 48-63
41
CBOX2: 64-71
42
43
There are two special cases, in that CYCLES can be measured
44
on PCSEL[02], and SCACHE_WRITE can be measured on CBOX[12].
45
These event numbers are canonicalizes to their first appearance. */
46
47
ctl = 0;
48
for (i = 0; i < 3; ++i) {
49
unsigned long event = ctr[i].event;
50
if (!ctr[i].enabled)
51
continue;
52
53
/* Remap the duplicate events, as described above. */
54
if (i == 2) {
55
if (event == 0)
56
event = 12+48;
57
else if (event == 2+41)
58
event = 4+65;
59
}
60
61
/* Convert the event numbers onto mux_select bit mask. */
62
if (event < 2)
63
ctl |= event << 31;
64
else if (event < 24)
65
/* error */;
66
else if (event < 40)
67
ctl |= (event - 24) << 4;
68
else if (event < 48)
69
ctl |= (event - 40) << cbox1_ofs | 15 << 4;
70
else if (event < 64)
71
ctl |= event - 48;
72
else if (event < 72)
73
ctl |= (event - 64) << cbox2_ofs | 15;
74
}
75
reg->mux_select = ctl;
76
77
/* Select processor mode. */
78
/* ??? Need to come up with some mechanism to trace only selected
79
processes. For now select from pal, kernel and user mode. */
80
ctl = 0;
81
ctl |= !sys->enable_pal << 9;
82
ctl |= !sys->enable_kernel << 8;
83
ctl |= !sys->enable_user << 30;
84
reg->proc_mode = ctl;
85
86
/* Select interrupt frequencies. Take the interrupt count selected
87
by the user, and map it onto one of the possible counter widths.
88
If the user value is in between, compute a value to which the
89
counter is reset at each interrupt. */
90
91
ctl = reset = need_reset = 0;
92
for (i = 0; i < 3; ++i) {
93
unsigned long max, hilo, count = ctr[i].count;
94
if (!ctr[i].enabled)
95
continue;
96
97
if (count <= 256)
98
count = 256, hilo = 3, max = 256;
99
else {
100
max = (i == 2 ? 16384 : 65536);
101
hilo = 2;
102
if (count > max)
103
count = max;
104
}
105
ctr[i].count = count;
106
107
ctl |= hilo << (8 - i*2);
108
reset |= (max - count) << (48 - 16*i);
109
if (count != max)
110
need_reset |= 1 << i;
111
}
112
reg->freq = ctl;
113
reg->reset_values = reset;
114
reg->need_reset = need_reset;
115
}
116
117
static void
118
ev5_reg_setup(struct op_register_config *reg,
119
struct op_counter_config *ctr,
120
struct op_system_config *sys)
121
{
122
common_reg_setup(reg, ctr, sys, 19, 22);
123
}
124
125
static void
126
pca56_reg_setup(struct op_register_config *reg,
127
struct op_counter_config *ctr,
128
struct op_system_config *sys)
129
{
130
common_reg_setup(reg, ctr, sys, 8, 11);
131
}
132
133
/* Program all of the registers in preparation for enabling profiling. */
134
135
static void
136
ev5_cpu_setup (void *x)
137
{
138
struct op_register_config *reg = x;
139
140
wrperfmon(2, reg->mux_select);
141
wrperfmon(3, reg->proc_mode);
142
wrperfmon(4, reg->freq);
143
wrperfmon(6, reg->reset_values);
144
}
145
146
/* CTR is a counter for which the user has requested an interrupt count
147
in between one of the widths selectable in hardware. Reset the count
148
for CTR to the value stored in REG->RESET_VALUES.
149
150
For EV5, this means disabling profiling, reading the current values,
151
masking in the value for the desired register, writing, then turning
152
profiling back on.
153
154
This can be streamlined if profiling is only enabled for user mode.
155
In that case we know that the counters are not currently incrementing
156
(due to being in kernel mode). */
157
158
static void
159
ev5_reset_ctr(struct op_register_config *reg, unsigned long ctr)
160
{
161
unsigned long values, mask, not_pk, reset_values;
162
163
mask = (ctr == 0 ? 0xfffful << 48
164
: ctr == 1 ? 0xfffful << 32
165
: 0x3fff << 16);
166
167
not_pk = 1 << 9 | 1 << 8;
168
169
reset_values = reg->reset_values;
170
171
if ((reg->proc_mode & not_pk) == not_pk) {
172
values = wrperfmon(5, 0);
173
values = (reset_values & mask) | (values & ~mask & -2);
174
wrperfmon(6, values);
175
} else {
176
wrperfmon(0, -1);
177
values = wrperfmon(5, 0);
178
values = (reset_values & mask) | (values & ~mask & -2);
179
wrperfmon(6, values);
180
wrperfmon(1, reg->enable);
181
}
182
}
183
184
static void
185
ev5_handle_interrupt(unsigned long which, struct pt_regs *regs,
186
struct op_counter_config *ctr)
187
{
188
/* Record the sample. */
189
oprofile_add_sample(regs, which);
190
}
191
192
193
struct op_axp_model op_model_ev5 = {
194
.reg_setup = ev5_reg_setup,
195
.cpu_setup = ev5_cpu_setup,
196
.reset_ctr = ev5_reset_ctr,
197
.handle_interrupt = ev5_handle_interrupt,
198
.cpu_type = "alpha/ev5",
199
.num_counters = 3,
200
.can_set_proc_mode = 1,
201
};
202
203
struct op_axp_model op_model_pca56 = {
204
.reg_setup = pca56_reg_setup,
205
.cpu_setup = ev5_cpu_setup,
206
.reset_ctr = ev5_reset_ctr,
207
.handle_interrupt = ev5_handle_interrupt,
208
.cpu_type = "alpha/pca56",
209
.num_counters = 3,
210
.can_set_proc_mode = 1,
211
};
212
213