Branch data 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 : : }
|