misc.c (10007B)
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 */ 22int pvr; 23u64 platform_extended_mask; 24 25/* Mask and Shift for Event code fields */ 26int ev_mask_pmcxsel, ev_shift_pmcxsel; //pmcxsel field 27int ev_mask_marked, ev_shift_marked; //marked filed 28int ev_mask_comb, ev_shift_comb; //combine field 29int ev_mask_unit, ev_shift_unit; //unit field 30int ev_mask_pmc, ev_shift_pmc; //pmc field 31int ev_mask_cache, ev_shift_cache; //Cache sel field 32int ev_mask_sample, ev_shift_sample; //Random sampling field 33int ev_mask_thd_sel, ev_shift_thd_sel; //thresh_sel field 34int ev_mask_thd_start, ev_shift_thd_start; //thresh_start field 35int ev_mask_thd_stop, ev_shift_thd_stop; //thresh_stop field 36int ev_mask_thd_cmp, ev_shift_thd_cmp; //thresh cmp field 37int ev_mask_sm, ev_shift_sm; //SDAR mode field 38int ev_mask_rsq, ev_shift_rsq; //radix scope qual field 39int ev_mask_l2l3, ev_shift_l2l3; //l2l3 sel field 40int ev_mask_mmcr3_src, ev_shift_mmcr3_src; //mmcr3 field 41 42static 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 */ 92static 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 102int 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 122int 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; 148out: 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 */ 156void *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 */ 186void *__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 240int 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 249static void *perf_read_first_sample(void *sample_buff, size_t *size) 250{ 251 return __event_read_samples(sample_buff, size, NULL); 252} 253 254u64 *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 277static 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 401u64 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}