538 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 field27int ev_mask_marked, ev_shift_marked; //marked filed28int ev_mask_comb, ev_shift_comb; //combine field29int ev_mask_unit, ev_shift_unit; //unit field30int ev_mask_pmc, ev_shift_pmc; //pmc field31int ev_mask_cache, ev_shift_cache; //Cache sel field32int ev_mask_sample, ev_shift_sample; //Random sampling field33int ev_mask_thd_sel, ev_shift_thd_sel; //thresh_sel field34int ev_mask_thd_start, ev_shift_thd_start; //thresh_start field35int ev_mask_thd_stop, ev_shift_thd_stop; //thresh_stop field36int ev_mask_thd_cmp, ev_shift_thd_cmp; //thresh cmp field37int ev_mask_sm, ev_shift_sm; //SDAR mode field38int ev_mask_rsq, ev_shift_rsq; //radix scope qual field39int ev_mask_l2l3, ev_shift_l2l3; //l2l3 sel field40int ev_mask_mmcr3_src, ev_shift_mmcr3_src; //mmcr3 field41 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_thd_cmp = 0x3ffff;64 ev_shift_thd_cmp = 0;65 ev_mask_rsq = 1;66 ev_shift_rsq = 9;67 ev_mask_comb = 3;68 ev_shift_comb = 10;69 ev_mask_cache = 3;70 ev_shift_cache = 20;71 ev_mask_sm = 0x3;72 ev_shift_sm = 22;73 ev_mask_l2l3 = 0x1f;74 ev_shift_l2l3 = 40;75 ev_mask_mmcr3_src = 0x7fff;76 ev_shift_mmcr3_src = 45;77 break;78 case POWER9:79 ev_mask_comb = 3;80 ev_shift_comb = 10;81 ev_mask_cache = 0xf;82 ev_shift_cache = 20;83 ev_mask_thd_cmp = 0x3ff;84 ev_shift_thd_cmp = 40;85 ev_mask_sm = 0x3;86 ev_shift_sm = 50;87 break;88 default:89 FAIL_IF_EXIT(1);90 }91}92 93/* Return the extended regs mask value */94static u64 perf_get_platform_reg_mask(void)95{96 if (have_hwcap2(PPC_FEATURE2_ARCH_3_1))97 return PERF_POWER10_MASK;98 if (have_hwcap2(PPC_FEATURE2_ARCH_3_00))99 return PERF_POWER9_MASK;100 101 return -1;102}103 104int check_extended_regs_support(void)105{106 int fd;107 struct event event;108 109 event_init(&event, 0x1001e);110 111 event.attr.type = 4;112 event.attr.sample_period = 1;113 event.attr.disabled = 1;114 event.attr.sample_type = PERF_SAMPLE_REGS_INTR;115 event.attr.sample_regs_intr = platform_extended_mask;116 117 fd = event_open(&event);118 if (fd != -1)119 return 0;120 121 return -1;122}123 124int platform_check_for_tests(void)125{126 pvr = PVR_VER(mfspr(SPRN_PVR));127 128 /*129 * Check for supported platforms130 * for sampling test131 */132 if ((pvr != POWER10) && (pvr != POWER9))133 goto out;134 135 /*136 * Check PMU driver registered by looking for137 * PPC_FEATURE2_EBB bit in AT_HWCAP2138 */139 if (!have_hwcap2(PPC_FEATURE2_EBB) || !have_hwcap2(PPC_FEATURE2_ARCH_3_00))140 goto out;141 142 return 0;143 144out:145 printf("%s: Tests unsupported for this platform\n", __func__);146 return -1;147}148 149int check_pvr_for_sampling_tests(void)150{151 SKIP_IF(platform_check_for_tests());152 153 platform_extended_mask = perf_get_platform_reg_mask();154 /* check if platform supports extended regs */155 if (check_extended_regs_support())156 goto out;157 158 init_ev_encodes();159 return 0;160 161out:162 printf("%s: Sampling tests un-supported\n", __func__);163 return -1;164}165 166/*167 * Allocate mmap buffer of "mmap_pages" number of168 * pages.169 */170void *event_sample_buf_mmap(int fd, int mmap_pages)171{172 size_t page_size = sysconf(_SC_PAGESIZE);173 size_t mmap_size;174 void *buff;175 176 if (mmap_pages <= 0)177 return NULL;178 179 if (fd <= 0)180 return NULL;181 182 mmap_size = page_size * (1 + mmap_pages);183 buff = mmap(NULL, mmap_size,184 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);185 186 if (buff == MAP_FAILED) {187 perror("mmap() failed.");188 return NULL;189 }190 return buff;191}192 193/*194 * Post process the mmap buffer.195 * - If sample_count != NULL then return count of total196 * number of samples present in the mmap buffer.197 * - If sample_count == NULL then return the address198 * of first sample from the mmap buffer199 */200void *__event_read_samples(void *sample_buff, size_t *size, u64 *sample_count)201{202 size_t page_size = sysconf(_SC_PAGESIZE);203 struct perf_event_header *header = sample_buff + page_size;204 struct perf_event_mmap_page *metadata_page = sample_buff;205 unsigned long data_head, data_tail;206 207 /*208 * PERF_RECORD_SAMPLE:209 * struct {210 * struct perf_event_header hdr;211 * u64 data[];212 * };213 */214 215 data_head = metadata_page->data_head;216 /* sync memory before reading sample */217 mb();218 data_tail = metadata_page->data_tail;219 220 /* Check for sample_count */221 if (sample_count)222 *sample_count = 0;223 224 while (1) {225 /*226 * Reads the mmap data buffer by moving227 * the data_tail to know the last read data.228 * data_head points to head in data buffer.229 * refer "struct perf_event_mmap_page" in230 * "include/uapi/linux/perf_event.h".231 */232 if (data_head - data_tail < sizeof(header))233 return NULL;234 235 data_tail += sizeof(header);236 if (header->type == PERF_RECORD_SAMPLE) {237 *size = (header->size - sizeof(header));238 if (!sample_count)239 return sample_buff + page_size + data_tail;240 data_tail += *size;241 *sample_count += 1;242 } else {243 *size = (header->size - sizeof(header));244 if ((metadata_page->data_tail + *size) > metadata_page->data_head)245 data_tail = metadata_page->data_head;246 else247 data_tail += *size;248 }249 header = (struct perf_event_header *)((void *)header + header->size);250 }251 return NULL;252}253 254int collect_samples(void *sample_buff)255{256 u64 sample_count;257 size_t size = 0;258 259 __event_read_samples(sample_buff, &size, &sample_count);260 return sample_count;261}262 263static void *perf_read_first_sample(void *sample_buff, size_t *size)264{265 return __event_read_samples(sample_buff, size, NULL);266}267 268u64 *get_intr_regs(struct event *event, void *sample_buff)269{270 u64 type = event->attr.sample_type;271 u64 *intr_regs;272 size_t size = 0;273 274 if ((type ^ (PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_BRANCH_STACK)) &&275 (type ^ PERF_SAMPLE_REGS_INTR))276 return NULL;277 278 intr_regs = (u64 *)perf_read_first_sample(sample_buff, &size);279 if (!intr_regs)280 return NULL;281 282 if (type & PERF_SAMPLE_BRANCH_STACK) {283 /*284 * PERF_RECORD_SAMPLE and PERF_SAMPLE_BRANCH_STACK:285 * struct {286 * struct perf_event_header hdr;287 * u64 number_of_branches;288 * struct perf_branch_entry[number_of_branches];289 * u64 data[];290 * };291 * struct perf_branch_entry {292 * u64 from;293 * u64 to;294 * u64 misc;295 * };296 */297 intr_regs += ((*intr_regs) * 3) + 1;298 }299 300 /*301 * First entry in the sample buffer used to specify302 * PERF_SAMPLE_REGS_ABI_64, skip perf regs abi to access303 * interrupt registers.304 */305 ++intr_regs;306 307 return intr_regs;308}309 310static const int __perf_reg_mask(const char *register_name)311{312 if (!strcmp(register_name, "R0"))313 return 0;314 else if (!strcmp(register_name, "R1"))315 return 1;316 else if (!strcmp(register_name, "R2"))317 return 2;318 else if (!strcmp(register_name, "R3"))319 return 3;320 else if (!strcmp(register_name, "R4"))321 return 4;322 else if (!strcmp(register_name, "R5"))323 return 5;324 else if (!strcmp(register_name, "R6"))325 return 6;326 else if (!strcmp(register_name, "R7"))327 return 7;328 else if (!strcmp(register_name, "R8"))329 return 8;330 else if (!strcmp(register_name, "R9"))331 return 9;332 else if (!strcmp(register_name, "R10"))333 return 10;334 else if (!strcmp(register_name, "R11"))335 return 11;336 else if (!strcmp(register_name, "R12"))337 return 12;338 else if (!strcmp(register_name, "R13"))339 return 13;340 else if (!strcmp(register_name, "R14"))341 return 14;342 else if (!strcmp(register_name, "R15"))343 return 15;344 else if (!strcmp(register_name, "R16"))345 return 16;346 else if (!strcmp(register_name, "R17"))347 return 17;348 else if (!strcmp(register_name, "R18"))349 return 18;350 else if (!strcmp(register_name, "R19"))351 return 19;352 else if (!strcmp(register_name, "R20"))353 return 20;354 else if (!strcmp(register_name, "R21"))355 return 21;356 else if (!strcmp(register_name, "R22"))357 return 22;358 else if (!strcmp(register_name, "R23"))359 return 23;360 else if (!strcmp(register_name, "R24"))361 return 24;362 else if (!strcmp(register_name, "R25"))363 return 25;364 else if (!strcmp(register_name, "R26"))365 return 26;366 else if (!strcmp(register_name, "R27"))367 return 27;368 else if (!strcmp(register_name, "R28"))369 return 28;370 else if (!strcmp(register_name, "R29"))371 return 29;372 else if (!strcmp(register_name, "R30"))373 return 30;374 else if (!strcmp(register_name, "R31"))375 return 31;376 else if (!strcmp(register_name, "NIP"))377 return 32;378 else if (!strcmp(register_name, "MSR"))379 return 33;380 else if (!strcmp(register_name, "ORIG_R3"))381 return 34;382 else if (!strcmp(register_name, "CTR"))383 return 35;384 else if (!strcmp(register_name, "LINK"))385 return 36;386 else if (!strcmp(register_name, "XER"))387 return 37;388 else if (!strcmp(register_name, "CCR"))389 return 38;390 else if (!strcmp(register_name, "SOFTE"))391 return 39;392 else if (!strcmp(register_name, "TRAP"))393 return 40;394 else if (!strcmp(register_name, "DAR"))395 return 41;396 else if (!strcmp(register_name, "DSISR"))397 return 42;398 else if (!strcmp(register_name, "SIER"))399 return 43;400 else if (!strcmp(register_name, "MMCRA"))401 return 44;402 else if (!strcmp(register_name, "MMCR0"))403 return 45;404 else if (!strcmp(register_name, "MMCR1"))405 return 46;406 else if (!strcmp(register_name, "MMCR2"))407 return 47;408 else if (!strcmp(register_name, "MMCR3"))409 return 48;410 else if (!strcmp(register_name, "SIER2"))411 return 49;412 else if (!strcmp(register_name, "SIER3"))413 return 50;414 else if (!strcmp(register_name, "PMC1"))415 return 51;416 else if (!strcmp(register_name, "PMC2"))417 return 52;418 else if (!strcmp(register_name, "PMC3"))419 return 53;420 else if (!strcmp(register_name, "PMC4"))421 return 54;422 else if (!strcmp(register_name, "PMC5"))423 return 55;424 else if (!strcmp(register_name, "PMC6"))425 return 56;426 else if (!strcmp(register_name, "SDAR"))427 return 57;428 else if (!strcmp(register_name, "SIAR"))429 return 58;430 else431 return -1;432}433 434u64 get_reg_value(u64 *intr_regs, char *register_name)435{436 int register_bit_position;437 438 register_bit_position = __perf_reg_mask(register_name);439 440 if (register_bit_position < 0 || (!((platform_extended_mask >>441 (register_bit_position - 1)) & 1)))442 return -1;443 444 return *(intr_regs + register_bit_position);445}446 447int get_thresh_cmp_val(struct event event)448{449 int exp = 0;450 u64 result = 0;451 u64 value;452 453 if (!have_hwcap2(PPC_FEATURE2_ARCH_3_1))454 return EV_CODE_EXTRACT(event.attr.config, thd_cmp);455 456 value = EV_CODE_EXTRACT(event.attr.config1, thd_cmp);457 458 if (!value)459 return value;460 461 /*462 * Incase of P10, thresh_cmp value is not part of raw event code463 * and provided via attr.config1 parameter. To program threshold in MMCRA,464 * take a 18 bit number N and shift right 2 places and increment465 * the exponent E by 1 until the upper 10 bits of N are zero.466 * Write E to the threshold exponent and write the lower 8 bits of N467 * to the threshold mantissa.468 * The max threshold that can be written is 261120.469 */470 if (value > 261120)471 value = 261120;472 while ((64 - __builtin_clzl(value)) > 8) {473 exp++;474 value >>= 2;475 }476 477 /*478 * Note that it is invalid to write a mantissa with the479 * upper 2 bits of mantissa being zero, unless the480 * exponent is also zero.481 */482 if (!(value & 0xC0) && exp)483 result = -1;484 else485 result = (exp << 8) | value;486 return result;487}488 489/*490 * Utility function to check for generic compat PMU491 * by comparing base_platform value from auxv and real492 * PVR value.493 */494static bool auxv_generic_compat_pmu(void)495{496 int base_pvr = 0;497 498 if (!strcmp(auxv_base_platform(), "power9"))499 base_pvr = POWER9;500 else if (!strcmp(auxv_base_platform(), "power10"))501 base_pvr = POWER10;502 503 return (!base_pvr);504}505 506/*507 * Check for generic compat PMU.508 * First check for presence of pmu_name from509 * "/sys/bus/event_source/devices/cpu/caps".510 * If doesn't exist, fallback to using value511 * auxv.512 */513bool check_for_generic_compat_pmu(void)514{515 char pmu_name[256];516 517 memset(pmu_name, 0, sizeof(pmu_name));518 if (read_sysfs_file("bus/event_source/devices/cpu/caps/pmu_name",519 pmu_name, sizeof(pmu_name)) < 0)520 return auxv_generic_compat_pmu();521 522 if (!strcmp(pmu_name, "ISAv3"))523 return true;524 else525 return false;526}527 528/*529 * Check if system is booted in compat mode.530 */531bool check_for_compat_mode(void)532{533 char *platform = auxv_platform();534 char *base_platform = auxv_base_platform();535 536 return strcmp(platform, base_platform);537}538