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