1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright 2022, Athira Rajeev, IBM Corp.
4 * Copyright 2022, Madhavan Srinivasan, IBM Corp.
5 * Copyright 2022, Kajol Jain, IBM Corp.
6 */
7
8 #include <unistd.h>
9 #include <sys/syscall.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <sys/ioctl.h>
13 #include <sys/mman.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16
17 #include "misc.h"
18
19 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
20
21 /* Storage for platform version */
22 int pvr;
23 u64 platform_extended_mask;
24
25 /* Mask and Shift for Event code fields */
26 int ev_mask_pmcxsel, ev_shift_pmcxsel; //pmcxsel field
27 int ev_mask_marked, ev_shift_marked; //marked filed
28 int ev_mask_comb, ev_shift_comb; //combine field
29 int ev_mask_unit, ev_shift_unit; //unit field
30 int ev_mask_pmc, ev_shift_pmc; //pmc field
31 int ev_mask_cache, ev_shift_cache; //Cache sel field
32 int ev_mask_sample, ev_shift_sample; //Random sampling field
33 int ev_mask_thd_sel, ev_shift_thd_sel; //thresh_sel field
34 int ev_mask_thd_start, ev_shift_thd_start; //thresh_start field
35 int ev_mask_thd_stop, ev_shift_thd_stop; //thresh_stop field
36 int ev_mask_thd_cmp, ev_shift_thd_cmp; //thresh cmp field
37 int ev_mask_sm, ev_shift_sm; //SDAR mode field
38 int ev_mask_rsq, ev_shift_rsq; //radix scope qual field
39 int ev_mask_l2l3, ev_shift_l2l3; //l2l3 sel field
40 int ev_mask_mmcr3_src, ev_shift_mmcr3_src; //mmcr3 field
41
init_ev_encodes(void)42 static void init_ev_encodes(void)
43 {
44 ev_mask_pmcxsel = 0xff;
45 ev_shift_pmcxsel = 0;
46 ev_mask_marked = 1;
47 ev_shift_marked = 8;
48 ev_mask_unit = 0xf;
49 ev_shift_unit = 12;
50 ev_mask_pmc = 0xf;
51 ev_shift_pmc = 16;
52 ev_mask_sample = 0x1f;
53 ev_shift_sample = 24;
54 ev_mask_thd_sel = 0x7;
55 ev_shift_thd_sel = 29;
56 ev_mask_thd_start = 0xf;
57 ev_shift_thd_start = 36;
58 ev_mask_thd_stop = 0xf;
59 ev_shift_thd_stop = 32;
60
61 switch (pvr) {
62 case POWER10:
63 ev_mask_rsq = 1;
64 ev_shift_rsq = 9;
65 ev_mask_comb = 3;
66 ev_shift_comb = 10;
67 ev_mask_cache = 3;
68 ev_shift_cache = 20;
69 ev_mask_sm = 0x3;
70 ev_shift_sm = 22;
71 ev_mask_l2l3 = 0x1f;
72 ev_shift_l2l3 = 40;
73 ev_mask_mmcr3_src = 0x7fff;
74 ev_shift_mmcr3_src = 45;
75 break;
76 case POWER9:
77 ev_mask_comb = 3;
78 ev_shift_comb = 10;
79 ev_mask_cache = 0xf;
80 ev_shift_cache = 20;
81 ev_mask_thd_cmp = 0x3ff;
82 ev_shift_thd_cmp = 40;
83 ev_mask_sm = 0x3;
84 ev_shift_sm = 50;
85 break;
86 default:
87 FAIL_IF_EXIT(1);
88 }
89 }
90
91 /* Return the extended regs mask value */
perf_get_platform_reg_mask(void)92 static u64 perf_get_platform_reg_mask(void)
93 {
94 if (have_hwcap2(PPC_FEATURE2_ARCH_3_1))
95 return PERF_POWER10_MASK;
96 if (have_hwcap2(PPC_FEATURE2_ARCH_3_00))
97 return PERF_POWER9_MASK;
98
99 return -1;
100 }
101
check_extended_regs_support(void)102 int check_extended_regs_support(void)
103 {
104 int fd;
105 struct event event;
106
107 event_init(&event, 0x1001e);
108
109 event.attr.type = 4;
110 event.attr.sample_period = 1;
111 event.attr.disabled = 1;
112 event.attr.sample_type = PERF_SAMPLE_REGS_INTR;
113 event.attr.sample_regs_intr = platform_extended_mask;
114
115 fd = event_open(&event);
116 if (fd != -1)
117 return 0;
118
119 return -1;
120 }
121
check_pvr_for_sampling_tests(void)122 int check_pvr_for_sampling_tests(void)
123 {
124 pvr = PVR_VER(mfspr(SPRN_PVR));
125
126 platform_extended_mask = perf_get_platform_reg_mask();
127
128 /*
129 * Check for supported platforms
130 * for sampling test
131 */
132 if ((pvr != POWER10) && (pvr != POWER9))
133 goto out;
134
135 /*
136 * Check PMU driver registered by looking for
137 * PPC_FEATURE2_EBB bit in AT_HWCAP2
138 */
139 if (!have_hwcap2(PPC_FEATURE2_EBB))
140 goto out;
141
142 /* check if platform supports extended regs */
143 if (check_extended_regs_support())
144 goto out;
145
146 init_ev_encodes();
147 return 0;
148 out:
149 printf("%s: Sampling tests un-supported\n", __func__);
150 return -1;
151 }
152 /*
153 * Allocate mmap buffer of "mmap_pages" number of
154 * pages.
155 */
event_sample_buf_mmap(int fd,int mmap_pages)156 void *event_sample_buf_mmap(int fd, int mmap_pages)
157 {
158 size_t page_size = sysconf(_SC_PAGESIZE);
159 size_t mmap_size;
160 void *buff;
161
162 if (mmap_pages <= 0)
163 return NULL;
164
165 if (fd <= 0)
166 return NULL;
167
168 mmap_size = page_size * (1 + mmap_pages);
169 buff = mmap(NULL, mmap_size,
170 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
171
172 if (buff == MAP_FAILED) {
173 perror("mmap() failed.");
174 return NULL;
175 }
176 return buff;
177 }
178
179 /*
180 * Post process the mmap buffer.
181 * - If sample_count != NULL then return count of total
182 * number of samples present in the mmap buffer.
183 * - If sample_count == NULL then return the address
184 * of first sample from the mmap buffer
185 */
__event_read_samples(void * sample_buff,size_t * size,u64 * sample_count)186 void *__event_read_samples(void *sample_buff, size_t *size, u64 *sample_count)
187 {
188 size_t page_size = sysconf(_SC_PAGESIZE);
189 struct perf_event_header *header = sample_buff + page_size;
190 struct perf_event_mmap_page *metadata_page = sample_buff;
191 unsigned long data_head, data_tail;
192
193 /*
194 * PERF_RECORD_SAMPLE:
195 * struct {
196 * struct perf_event_header hdr;
197 * u64 data[];
198 * };
199 */
200
201 data_head = metadata_page->data_head;
202 /* sync memory before reading sample */
203 mb();
204 data_tail = metadata_page->data_tail;
205
206 /* Check for sample_count */
207 if (sample_count)
208 *sample_count = 0;
209
210 while (1) {
211 /*
212 * Reads the mmap data buffer by moving
213 * the data_tail to know the last read data.
214 * data_head points to head in data buffer.
215 * refer "struct perf_event_mmap_page" in
216 * "include/uapi/linux/perf_event.h".
217 */
218 if (data_head - data_tail < sizeof(header))
219 return NULL;
220
221 data_tail += sizeof(header);
222 if (header->type == PERF_RECORD_SAMPLE) {
223 *size = (header->size - sizeof(header));
224 if (!sample_count)
225 return sample_buff + page_size + data_tail;
226 data_tail += *size;
227 *sample_count += 1;
228 } else {
229 *size = (header->size - sizeof(header));
230 if ((metadata_page->data_tail + *size) > metadata_page->data_head)
231 data_tail = metadata_page->data_head;
232 else
233 data_tail += *size;
234 }
235 header = (struct perf_event_header *)((void *)header + header->size);
236 }
237 return NULL;
238 }
239
collect_samples(void * sample_buff)240 int collect_samples(void *sample_buff)
241 {
242 u64 sample_count;
243 size_t size = 0;
244
245 __event_read_samples(sample_buff, &size, &sample_count);
246 return sample_count;
247 }
248
perf_read_first_sample(void * sample_buff,size_t * size)249 static void *perf_read_first_sample(void *sample_buff, size_t *size)
250 {
251 return __event_read_samples(sample_buff, size, NULL);
252 }
253
get_intr_regs(struct event * event,void * sample_buff)254 u64 *get_intr_regs(struct event *event, void *sample_buff)
255 {
256 u64 type = event->attr.sample_type;
257 u64 *intr_regs;
258 size_t size = 0;
259
260 if ((type ^ PERF_SAMPLE_REGS_INTR))
261 return NULL;
262
263 intr_regs = (u64 *)perf_read_first_sample(sample_buff, &size);
264 if (!intr_regs)
265 return NULL;
266
267 /*
268 * First entry in the sample buffer used to specify
269 * PERF_SAMPLE_REGS_ABI_64, skip perf regs abi to access
270 * interrupt registers.
271 */
272 ++intr_regs;
273
274 return intr_regs;
275 }
276
__perf_reg_mask(const char * register_name)277 static const int __perf_reg_mask(const char *register_name)
278 {
279 if (!strcmp(register_name, "R0"))
280 return 0;
281 else if (!strcmp(register_name, "R1"))
282 return 1;
283 else if (!strcmp(register_name, "R2"))
284 return 2;
285 else if (!strcmp(register_name, "R3"))
286 return 3;
287 else if (!strcmp(register_name, "R4"))
288 return 4;
289 else if (!strcmp(register_name, "R5"))
290 return 5;
291 else if (!strcmp(register_name, "R6"))
292 return 6;
293 else if (!strcmp(register_name, "R7"))
294 return 7;
295 else if (!strcmp(register_name, "R8"))
296 return 8;
297 else if (!strcmp(register_name, "R9"))
298 return 9;
299 else if (!strcmp(register_name, "R10"))
300 return 10;
301 else if (!strcmp(register_name, "R11"))
302 return 11;
303 else if (!strcmp(register_name, "R12"))
304 return 12;
305 else if (!strcmp(register_name, "R13"))
306 return 13;
307 else if (!strcmp(register_name, "R14"))
308 return 14;
309 else if (!strcmp(register_name, "R15"))
310 return 15;
311 else if (!strcmp(register_name, "R16"))
312 return 16;
313 else if (!strcmp(register_name, "R17"))
314 return 17;
315 else if (!strcmp(register_name, "R18"))
316 return 18;
317 else if (!strcmp(register_name, "R19"))
318 return 19;
319 else if (!strcmp(register_name, "R20"))
320 return 20;
321 else if (!strcmp(register_name, "R21"))
322 return 21;
323 else if (!strcmp(register_name, "R22"))
324 return 22;
325 else if (!strcmp(register_name, "R23"))
326 return 23;
327 else if (!strcmp(register_name, "R24"))
328 return 24;
329 else if (!strcmp(register_name, "R25"))
330 return 25;
331 else if (!strcmp(register_name, "R26"))
332 return 26;
333 else if (!strcmp(register_name, "R27"))
334 return 27;
335 else if (!strcmp(register_name, "R28"))
336 return 28;
337 else if (!strcmp(register_name, "R29"))
338 return 29;
339 else if (!strcmp(register_name, "R30"))
340 return 30;
341 else if (!strcmp(register_name, "R31"))
342 return 31;
343 else if (!strcmp(register_name, "NIP"))
344 return 32;
345 else if (!strcmp(register_name, "MSR"))
346 return 33;
347 else if (!strcmp(register_name, "ORIG_R3"))
348 return 34;
349 else if (!strcmp(register_name, "CTR"))
350 return 35;
351 else if (!strcmp(register_name, "LINK"))
352 return 36;
353 else if (!strcmp(register_name, "XER"))
354 return 37;
355 else if (!strcmp(register_name, "CCR"))
356 return 38;
357 else if (!strcmp(register_name, "SOFTE"))
358 return 39;
359 else if (!strcmp(register_name, "TRAP"))
360 return 40;
361 else if (!strcmp(register_name, "DAR"))
362 return 41;
363 else if (!strcmp(register_name, "DSISR"))
364 return 42;
365 else if (!strcmp(register_name, "SIER"))
366 return 43;
367 else if (!strcmp(register_name, "MMCRA"))
368 return 44;
369 else if (!strcmp(register_name, "MMCR0"))
370 return 45;
371 else if (!strcmp(register_name, "MMCR1"))
372 return 46;
373 else if (!strcmp(register_name, "MMCR2"))
374 return 47;
375 else if (!strcmp(register_name, "MMCR3"))
376 return 48;
377 else if (!strcmp(register_name, "SIER2"))
378 return 49;
379 else if (!strcmp(register_name, "SIER3"))
380 return 50;
381 else if (!strcmp(register_name, "PMC1"))
382 return 51;
383 else if (!strcmp(register_name, "PMC2"))
384 return 52;
385 else if (!strcmp(register_name, "PMC3"))
386 return 53;
387 else if (!strcmp(register_name, "PMC4"))
388 return 54;
389 else if (!strcmp(register_name, "PMC5"))
390 return 55;
391 else if (!strcmp(register_name, "PMC6"))
392 return 56;
393 else if (!strcmp(register_name, "SDAR"))
394 return 57;
395 else if (!strcmp(register_name, "SIAR"))
396 return 58;
397 else
398 return -1;
399 }
400
get_reg_value(u64 * intr_regs,char * register_name)401 u64 get_reg_value(u64 *intr_regs, char *register_name)
402 {
403 int register_bit_position;
404
405 register_bit_position = __perf_reg_mask(register_name);
406
407 if (register_bit_position < 0 || (!((platform_extended_mask >>
408 (register_bit_position - 1)) & 1)))
409 return -1;
410
411 return *(intr_regs + register_bit_position);
412 }
413