Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/events/intel/p6.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/perf_event.h>
3
#include <linux/types.h>
4
5
#include <asm/cpu_device_id.h>
6
#include <asm/msr.h>
7
8
#include "../perf_event.h"
9
10
/*
11
* Not sure about some of these
12
*/
13
static const u64 p6_perfmon_event_map[] =
14
{
15
[PERF_COUNT_HW_CPU_CYCLES] = 0x0079, /* CPU_CLK_UNHALTED */
16
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, /* INST_RETIRED */
17
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x0f2e, /* L2_RQSTS:M:E:S:I */
18
[PERF_COUNT_HW_CACHE_MISSES] = 0x012e, /* L2_RQSTS:I */
19
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, /* BR_INST_RETIRED */
20
[PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, /* BR_MISS_PRED_RETIRED */
21
[PERF_COUNT_HW_BUS_CYCLES] = 0x0062, /* BUS_DRDY_CLOCKS */
22
[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00a2, /* RESOURCE_STALLS */
23
24
};
25
26
static const u64 __initconst p6_hw_cache_event_ids
27
[PERF_COUNT_HW_CACHE_MAX]
28
[PERF_COUNT_HW_CACHE_OP_MAX]
29
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
30
{
31
[ C(L1D) ] = {
32
[ C(OP_READ) ] = {
33
[ C(RESULT_ACCESS) ] = 0x0043, /* DATA_MEM_REFS */
34
[ C(RESULT_MISS) ] = 0x0045, /* DCU_LINES_IN */
35
},
36
[ C(OP_WRITE) ] = {
37
[ C(RESULT_ACCESS) ] = 0,
38
[ C(RESULT_MISS) ] = 0x0f29, /* L2_LD:M:E:S:I */
39
},
40
[ C(OP_PREFETCH) ] = {
41
[ C(RESULT_ACCESS) ] = 0,
42
[ C(RESULT_MISS) ] = 0,
43
},
44
},
45
[ C(L1I ) ] = {
46
[ C(OP_READ) ] = {
47
[ C(RESULT_ACCESS) ] = 0x0080, /* IFU_IFETCH */
48
[ C(RESULT_MISS) ] = 0x0f28, /* L2_IFETCH:M:E:S:I */
49
},
50
[ C(OP_WRITE) ] = {
51
[ C(RESULT_ACCESS) ] = -1,
52
[ C(RESULT_MISS) ] = -1,
53
},
54
[ C(OP_PREFETCH) ] = {
55
[ C(RESULT_ACCESS) ] = 0,
56
[ C(RESULT_MISS) ] = 0,
57
},
58
},
59
[ C(LL ) ] = {
60
[ C(OP_READ) ] = {
61
[ C(RESULT_ACCESS) ] = 0,
62
[ C(RESULT_MISS) ] = 0,
63
},
64
[ C(OP_WRITE) ] = {
65
[ C(RESULT_ACCESS) ] = 0,
66
[ C(RESULT_MISS) ] = 0x0025, /* L2_M_LINES_INM */
67
},
68
[ C(OP_PREFETCH) ] = {
69
[ C(RESULT_ACCESS) ] = 0,
70
[ C(RESULT_MISS) ] = 0,
71
},
72
},
73
[ C(DTLB) ] = {
74
[ C(OP_READ) ] = {
75
[ C(RESULT_ACCESS) ] = 0x0043, /* DATA_MEM_REFS */
76
[ C(RESULT_MISS) ] = 0,
77
},
78
[ C(OP_WRITE) ] = {
79
[ C(RESULT_ACCESS) ] = 0,
80
[ C(RESULT_MISS) ] = 0,
81
},
82
[ C(OP_PREFETCH) ] = {
83
[ C(RESULT_ACCESS) ] = 0,
84
[ C(RESULT_MISS) ] = 0,
85
},
86
},
87
[ C(ITLB) ] = {
88
[ C(OP_READ) ] = {
89
[ C(RESULT_ACCESS) ] = 0x0080, /* IFU_IFETCH */
90
[ C(RESULT_MISS) ] = 0x0085, /* ITLB_MISS */
91
},
92
[ C(OP_WRITE) ] = {
93
[ C(RESULT_ACCESS) ] = -1,
94
[ C(RESULT_MISS) ] = -1,
95
},
96
[ C(OP_PREFETCH) ] = {
97
[ C(RESULT_ACCESS) ] = -1,
98
[ C(RESULT_MISS) ] = -1,
99
},
100
},
101
[ C(BPU ) ] = {
102
[ C(OP_READ) ] = {
103
[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED */
104
[ C(RESULT_MISS) ] = 0x00c5, /* BR_MISS_PRED_RETIRED */
105
},
106
[ C(OP_WRITE) ] = {
107
[ C(RESULT_ACCESS) ] = -1,
108
[ C(RESULT_MISS) ] = -1,
109
},
110
[ C(OP_PREFETCH) ] = {
111
[ C(RESULT_ACCESS) ] = -1,
112
[ C(RESULT_MISS) ] = -1,
113
},
114
},
115
};
116
117
static u64 p6_pmu_event_map(int hw_event)
118
{
119
return p6_perfmon_event_map[hw_event];
120
}
121
122
/*
123
* Event setting that is specified not to count anything.
124
* We use this to effectively disable a counter.
125
*
126
* L2_RQSTS with 0 MESI unit mask.
127
*/
128
#define P6_NOP_EVENT 0x0000002EULL
129
130
static struct event_constraint p6_event_constraints[] =
131
{
132
INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */
133
INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
134
INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
135
INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
136
INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
137
INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
138
EVENT_CONSTRAINT_END
139
};
140
141
static void p6_pmu_disable_all(void)
142
{
143
u64 val;
144
145
/* p6 only has one enable register */
146
rdmsrq(MSR_P6_EVNTSEL0, val);
147
val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
148
wrmsrq(MSR_P6_EVNTSEL0, val);
149
}
150
151
static void p6_pmu_enable_all(int added)
152
{
153
unsigned long val;
154
155
/* p6 only has one enable register */
156
rdmsrq(MSR_P6_EVNTSEL0, val);
157
val |= ARCH_PERFMON_EVENTSEL_ENABLE;
158
wrmsrq(MSR_P6_EVNTSEL0, val);
159
}
160
161
static inline void
162
p6_pmu_disable_event(struct perf_event *event)
163
{
164
struct hw_perf_event *hwc = &event->hw;
165
u64 val = P6_NOP_EVENT;
166
167
(void)wrmsrq_safe(hwc->config_base, val);
168
}
169
170
static void p6_pmu_enable_event(struct perf_event *event)
171
{
172
struct hw_perf_event *hwc = &event->hw;
173
u64 val;
174
175
val = hwc->config;
176
177
/*
178
* p6 only has a global event enable, set on PerfEvtSel0
179
* We "disable" events by programming P6_NOP_EVENT
180
* and we rely on p6_pmu_enable_all() being called
181
* to actually enable the events.
182
*/
183
184
(void)wrmsrq_safe(hwc->config_base, val);
185
}
186
187
PMU_FORMAT_ATTR(event, "config:0-7" );
188
PMU_FORMAT_ATTR(umask, "config:8-15" );
189
PMU_FORMAT_ATTR(edge, "config:18" );
190
PMU_FORMAT_ATTR(pc, "config:19" );
191
PMU_FORMAT_ATTR(inv, "config:23" );
192
PMU_FORMAT_ATTR(cmask, "config:24-31" );
193
194
static struct attribute *intel_p6_formats_attr[] = {
195
&format_attr_event.attr,
196
&format_attr_umask.attr,
197
&format_attr_edge.attr,
198
&format_attr_pc.attr,
199
&format_attr_inv.attr,
200
&format_attr_cmask.attr,
201
NULL,
202
};
203
204
static __initconst const struct x86_pmu p6_pmu = {
205
.name = "p6",
206
.handle_irq = x86_pmu_handle_irq,
207
.disable_all = p6_pmu_disable_all,
208
.enable_all = p6_pmu_enable_all,
209
.enable = p6_pmu_enable_event,
210
.disable = p6_pmu_disable_event,
211
.hw_config = x86_pmu_hw_config,
212
.schedule_events = x86_schedule_events,
213
.eventsel = MSR_P6_EVNTSEL0,
214
.perfctr = MSR_P6_PERFCTR0,
215
.event_map = p6_pmu_event_map,
216
.max_events = ARRAY_SIZE(p6_perfmon_event_map),
217
.apic = 1,
218
.max_period = (1ULL << 31) - 1,
219
.version = 0,
220
.cntr_mask64 = 0x3,
221
/*
222
* Events have 40 bits implemented. However they are designed such
223
* that bits [32-39] are sign extensions of bit 31. As such the
224
* effective width of a event for P6-like PMU is 32 bits only.
225
*
226
* See IA-32 Intel Architecture Software developer manual Vol 3B
227
*/
228
.cntval_bits = 32,
229
.cntval_mask = (1ULL << 32) - 1,
230
.get_event_constraints = x86_get_event_constraints,
231
.event_constraints = p6_event_constraints,
232
233
.format_attrs = intel_p6_formats_attr,
234
.events_sysfs_show = intel_event_sysfs_show,
235
236
};
237
238
static __init void p6_pmu_rdpmc_quirk(void)
239
{
240
if (boot_cpu_data.x86_stepping < 9) {
241
/*
242
* PPro erratum 26; fixed in stepping 9 and above.
243
*/
244
pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
245
x86_pmu.attr_rdpmc_broken = 1;
246
x86_pmu.attr_rdpmc = 0;
247
}
248
}
249
250
__init int p6_pmu_init(void)
251
{
252
x86_pmu = p6_pmu;
253
254
if (boot_cpu_data.x86_vfm == INTEL_PENTIUM_PRO)
255
x86_add_quirk(p6_pmu_rdpmc_quirk);
256
257
memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
258
sizeof(hw_cache_event_ids));
259
260
return 0;
261
}
262
263