Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2022, Athira Rajeev, IBM Corp.
0004  * Copyright 2022, Madhavan Srinivasan, IBM Corp.
0005  * Copyright 2022, Kajol Jain, IBM Corp.
0006  */
0007 
0008 #include <unistd.h>
0009 #include <sys/syscall.h>
0010 #include <string.h>
0011 #include <stdio.h>
0012 #include <sys/ioctl.h>
0013 #include <sys/mman.h>
0014 #include <stdlib.h>
0015 #include <ctype.h>
0016 
0017 #include "misc.h"
0018 
0019 #define PAGE_SIZE               sysconf(_SC_PAGESIZE)
0020 
0021 /* Storage for platform version */
0022 int pvr;
0023 u64 platform_extended_mask;
0024 
0025 /* Mask and Shift for Event code fields */
0026 int ev_mask_pmcxsel, ev_shift_pmcxsel;      //pmcxsel field
0027 int ev_mask_marked, ev_shift_marked;        //marked filed
0028 int ev_mask_comb, ev_shift_comb;        //combine field
0029 int ev_mask_unit, ev_shift_unit;        //unit field
0030 int ev_mask_pmc, ev_shift_pmc;          //pmc field
0031 int ev_mask_cache, ev_shift_cache;      //Cache sel field
0032 int ev_mask_sample, ev_shift_sample;        //Random sampling field
0033 int ev_mask_thd_sel, ev_shift_thd_sel;      //thresh_sel field
0034 int ev_mask_thd_start, ev_shift_thd_start;  //thresh_start field
0035 int ev_mask_thd_stop, ev_shift_thd_stop;    //thresh_stop field
0036 int ev_mask_thd_cmp, ev_shift_thd_cmp;      //thresh cmp field
0037 int ev_mask_sm, ev_shift_sm;            //SDAR mode field
0038 int ev_mask_rsq, ev_shift_rsq;          //radix scope qual field
0039 int ev_mask_l2l3, ev_shift_l2l3;        //l2l3 sel field
0040 int ev_mask_mmcr3_src, ev_shift_mmcr3_src;  //mmcr3 field
0041 
0042 static void init_ev_encodes(void)
0043 {
0044     ev_mask_pmcxsel = 0xff;
0045     ev_shift_pmcxsel = 0;
0046     ev_mask_marked = 1;
0047     ev_shift_marked = 8;
0048     ev_mask_unit = 0xf;
0049     ev_shift_unit = 12;
0050     ev_mask_pmc = 0xf;
0051     ev_shift_pmc = 16;
0052     ev_mask_sample  = 0x1f;
0053     ev_shift_sample = 24;
0054     ev_mask_thd_sel = 0x7;
0055     ev_shift_thd_sel = 29;
0056     ev_mask_thd_start = 0xf;
0057     ev_shift_thd_start = 36;
0058     ev_mask_thd_stop = 0xf;
0059     ev_shift_thd_stop = 32;
0060 
0061     switch (pvr) {
0062     case POWER10:
0063         ev_mask_thd_cmp = 0x3ffff;
0064         ev_shift_thd_cmp = 0;
0065         ev_mask_rsq = 1;
0066         ev_shift_rsq = 9;
0067         ev_mask_comb = 3;
0068         ev_shift_comb = 10;
0069         ev_mask_cache = 3;
0070         ev_shift_cache = 20;
0071         ev_mask_sm = 0x3;
0072         ev_shift_sm = 22;
0073         ev_mask_l2l3 = 0x1f;
0074         ev_shift_l2l3 = 40;
0075         ev_mask_mmcr3_src = 0x7fff;
0076         ev_shift_mmcr3_src = 45;
0077         break;
0078     case POWER9:
0079         ev_mask_comb = 3;
0080         ev_shift_comb = 10;
0081         ev_mask_cache = 0xf;
0082         ev_shift_cache = 20;
0083         ev_mask_thd_cmp = 0x3ff;
0084         ev_shift_thd_cmp = 40;
0085         ev_mask_sm = 0x3;
0086         ev_shift_sm = 50;
0087         break;
0088     default:
0089         FAIL_IF_EXIT(1);
0090     }
0091 }
0092 
0093 /* Return the extended regs mask value */
0094 static u64 perf_get_platform_reg_mask(void)
0095 {
0096     if (have_hwcap2(PPC_FEATURE2_ARCH_3_1))
0097         return PERF_POWER10_MASK;
0098     if (have_hwcap2(PPC_FEATURE2_ARCH_3_00))
0099         return PERF_POWER9_MASK;
0100 
0101     return -1;
0102 }
0103 
0104 int check_extended_regs_support(void)
0105 {
0106     int fd;
0107     struct event event;
0108 
0109     event_init(&event, 0x1001e);
0110 
0111     event.attr.type = 4;
0112     event.attr.sample_period = 1;
0113     event.attr.disabled = 1;
0114     event.attr.sample_type = PERF_SAMPLE_REGS_INTR;
0115     event.attr.sample_regs_intr = platform_extended_mask;
0116 
0117     fd = event_open(&event);
0118     if (fd != -1)
0119         return 0;
0120 
0121     return -1;
0122 }
0123 
0124 int platform_check_for_tests(void)
0125 {
0126     pvr = PVR_VER(mfspr(SPRN_PVR));
0127 
0128     /*
0129      * Check for supported platforms
0130      * for sampling test
0131      */
0132     if ((pvr != POWER10) && (pvr != POWER9))
0133         goto out;
0134 
0135     /*
0136      * Check PMU driver registered by looking for
0137      * PPC_FEATURE2_EBB bit in AT_HWCAP2
0138      */
0139     if (!have_hwcap2(PPC_FEATURE2_EBB) || !have_hwcap2(PPC_FEATURE2_ARCH_3_00))
0140         goto out;
0141 
0142     return 0;
0143 
0144 out:
0145     printf("%s: Tests unsupported for this platform\n", __func__);
0146     return -1;
0147 }
0148 
0149 int check_pvr_for_sampling_tests(void)
0150 {
0151     SKIP_IF(platform_check_for_tests());
0152 
0153     platform_extended_mask = perf_get_platform_reg_mask();
0154     /* check if platform supports extended regs */
0155     if (check_extended_regs_support())
0156         goto out;
0157 
0158     init_ev_encodes();
0159     return 0;
0160 
0161 out:
0162     printf("%s: Sampling tests un-supported\n", __func__);
0163     return -1;
0164 }
0165 
0166 /*
0167  * Allocate mmap buffer of "mmap_pages" number of
0168  * pages.
0169  */
0170 void *event_sample_buf_mmap(int fd, int mmap_pages)
0171 {
0172     size_t page_size = sysconf(_SC_PAGESIZE);
0173     size_t mmap_size;
0174     void *buff;
0175 
0176     if (mmap_pages <= 0)
0177         return NULL;
0178 
0179     if (fd <= 0)
0180         return NULL;
0181 
0182     mmap_size =  page_size * (1 + mmap_pages);
0183     buff = mmap(NULL, mmap_size,
0184         PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
0185 
0186     if (buff == MAP_FAILED) {
0187         perror("mmap() failed.");
0188         return NULL;
0189     }
0190     return buff;
0191 }
0192 
0193 /*
0194  * Post process the mmap buffer.
0195  * - If sample_count != NULL then return count of total
0196  *   number of samples present in the mmap buffer.
0197  * - If sample_count == NULL then return the address
0198  *   of first sample from the mmap buffer
0199  */
0200 void *__event_read_samples(void *sample_buff, size_t *size, u64 *sample_count)
0201 {
0202     size_t page_size = sysconf(_SC_PAGESIZE);
0203     struct perf_event_header *header = sample_buff + page_size;
0204     struct perf_event_mmap_page *metadata_page = sample_buff;
0205     unsigned long data_head, data_tail;
0206 
0207     /*
0208      * PERF_RECORD_SAMPLE:
0209      * struct {
0210      *     struct perf_event_header hdr;
0211      *     u64 data[];
0212      * };
0213      */
0214 
0215     data_head = metadata_page->data_head;
0216     /* sync memory before reading sample */
0217     mb();
0218     data_tail = metadata_page->data_tail;
0219 
0220     /* Check for sample_count */
0221     if (sample_count)
0222         *sample_count = 0;
0223 
0224     while (1) {
0225         /*
0226          * Reads the mmap data buffer by moving
0227          * the data_tail to know the last read data.
0228          * data_head points to head in data buffer.
0229          * refer "struct perf_event_mmap_page" in
0230          * "include/uapi/linux/perf_event.h".
0231          */
0232         if (data_head - data_tail < sizeof(header))
0233             return NULL;
0234 
0235         data_tail += sizeof(header);
0236         if (header->type == PERF_RECORD_SAMPLE) {
0237             *size = (header->size - sizeof(header));
0238             if (!sample_count)
0239                 return sample_buff + page_size + data_tail;
0240             data_tail += *size;
0241             *sample_count += 1;
0242         } else {
0243             *size = (header->size - sizeof(header));
0244             if ((metadata_page->data_tail + *size) > metadata_page->data_head)
0245                 data_tail = metadata_page->data_head;
0246             else
0247                 data_tail += *size;
0248         }
0249         header = (struct perf_event_header *)((void *)header + header->size);
0250     }
0251     return NULL;
0252 }
0253 
0254 int collect_samples(void *sample_buff)
0255 {
0256     u64 sample_count;
0257     size_t size = 0;
0258 
0259     __event_read_samples(sample_buff, &size, &sample_count);
0260     return sample_count;
0261 }
0262 
0263 static void *perf_read_first_sample(void *sample_buff, size_t *size)
0264 {
0265     return __event_read_samples(sample_buff, size, NULL);
0266 }
0267 
0268 u64 *get_intr_regs(struct event *event, void *sample_buff)
0269 {
0270     u64 type = event->attr.sample_type;
0271     u64 *intr_regs;
0272     size_t size = 0;
0273 
0274     if ((type ^ (PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_BRANCH_STACK)) &&
0275             (type  ^ PERF_SAMPLE_REGS_INTR))
0276         return NULL;
0277 
0278     intr_regs = (u64 *)perf_read_first_sample(sample_buff, &size);
0279     if (!intr_regs)
0280         return NULL;
0281 
0282     if (type & PERF_SAMPLE_BRANCH_STACK) {
0283         /*
0284          * PERF_RECORD_SAMPLE and PERF_SAMPLE_BRANCH_STACK:
0285          * struct {
0286          *     struct perf_event_header hdr;
0287          *     u64 number_of_branches;
0288          *     struct perf_branch_entry[number_of_branches];
0289          *     u64 data[];
0290          * };
0291          * struct perf_branch_entry {
0292          *     u64  from;
0293          *     u64  to;
0294          *     u64  misc;
0295          * };
0296          */
0297         intr_regs += ((*intr_regs) * 3) + 1;
0298     }
0299 
0300     /*
0301      * First entry in the sample buffer used to specify
0302      * PERF_SAMPLE_REGS_ABI_64, skip perf regs abi to access
0303      * interrupt registers.
0304      */
0305     ++intr_regs;
0306 
0307     return intr_regs;
0308 }
0309 
0310 static const int __perf_reg_mask(const char *register_name)
0311 {
0312     if (!strcmp(register_name, "R0"))
0313         return 0;
0314     else if (!strcmp(register_name, "R1"))
0315         return 1;
0316     else if (!strcmp(register_name, "R2"))
0317         return 2;
0318     else if (!strcmp(register_name, "R3"))
0319         return 3;
0320     else if (!strcmp(register_name, "R4"))
0321         return 4;
0322     else if (!strcmp(register_name, "R5"))
0323         return 5;
0324     else if (!strcmp(register_name, "R6"))
0325         return 6;
0326     else if (!strcmp(register_name, "R7"))
0327         return 7;
0328     else if (!strcmp(register_name, "R8"))
0329         return 8;
0330     else if (!strcmp(register_name, "R9"))
0331         return 9;
0332     else if (!strcmp(register_name, "R10"))
0333         return 10;
0334     else if (!strcmp(register_name, "R11"))
0335         return 11;
0336     else if (!strcmp(register_name, "R12"))
0337         return 12;
0338     else if (!strcmp(register_name, "R13"))
0339         return 13;
0340     else if (!strcmp(register_name, "R14"))
0341         return 14;
0342     else if (!strcmp(register_name, "R15"))
0343         return 15;
0344     else if (!strcmp(register_name, "R16"))
0345         return 16;
0346     else if (!strcmp(register_name, "R17"))
0347         return 17;
0348     else if (!strcmp(register_name, "R18"))
0349         return 18;
0350     else if (!strcmp(register_name, "R19"))
0351         return 19;
0352     else if (!strcmp(register_name, "R20"))
0353         return 20;
0354     else if (!strcmp(register_name, "R21"))
0355         return 21;
0356     else if (!strcmp(register_name, "R22"))
0357         return 22;
0358     else if (!strcmp(register_name, "R23"))
0359         return 23;
0360     else if (!strcmp(register_name, "R24"))
0361         return 24;
0362     else if (!strcmp(register_name, "R25"))
0363         return 25;
0364     else if (!strcmp(register_name, "R26"))
0365         return 26;
0366     else if (!strcmp(register_name, "R27"))
0367         return 27;
0368     else if (!strcmp(register_name, "R28"))
0369         return 28;
0370     else if (!strcmp(register_name, "R29"))
0371         return 29;
0372     else if (!strcmp(register_name, "R30"))
0373         return 30;
0374     else if (!strcmp(register_name, "R31"))
0375         return 31;
0376     else if (!strcmp(register_name, "NIP"))
0377         return 32;
0378     else if (!strcmp(register_name, "MSR"))
0379         return 33;
0380     else if (!strcmp(register_name, "ORIG_R3"))
0381         return 34;
0382     else if (!strcmp(register_name, "CTR"))
0383         return 35;
0384     else if (!strcmp(register_name, "LINK"))
0385         return 36;
0386     else if (!strcmp(register_name, "XER"))
0387         return 37;
0388     else if (!strcmp(register_name, "CCR"))
0389         return 38;
0390     else if (!strcmp(register_name, "SOFTE"))
0391         return 39;
0392     else if (!strcmp(register_name, "TRAP"))
0393         return 40;
0394     else if (!strcmp(register_name, "DAR"))
0395         return 41;
0396     else if (!strcmp(register_name, "DSISR"))
0397         return 42;
0398     else if (!strcmp(register_name, "SIER"))
0399         return 43;
0400     else if (!strcmp(register_name, "MMCRA"))
0401         return 44;
0402     else if (!strcmp(register_name, "MMCR0"))
0403         return 45;
0404     else if (!strcmp(register_name, "MMCR1"))
0405         return 46;
0406     else if (!strcmp(register_name, "MMCR2"))
0407         return 47;
0408     else if (!strcmp(register_name, "MMCR3"))
0409         return 48;
0410     else if (!strcmp(register_name, "SIER2"))
0411         return 49;
0412     else if (!strcmp(register_name, "SIER3"))
0413         return 50;
0414     else if (!strcmp(register_name, "PMC1"))
0415         return 51;
0416     else if (!strcmp(register_name, "PMC2"))
0417         return 52;
0418     else if (!strcmp(register_name, "PMC3"))
0419         return 53;
0420     else if (!strcmp(register_name, "PMC4"))
0421         return 54;
0422     else if (!strcmp(register_name, "PMC5"))
0423         return 55;
0424     else if (!strcmp(register_name, "PMC6"))
0425         return 56;
0426     else if (!strcmp(register_name, "SDAR"))
0427         return 57;
0428     else if (!strcmp(register_name, "SIAR"))
0429         return 58;
0430     else
0431         return -1;
0432 }
0433 
0434 u64 get_reg_value(u64 *intr_regs, char *register_name)
0435 {
0436     int register_bit_position;
0437 
0438     register_bit_position = __perf_reg_mask(register_name);
0439 
0440     if (register_bit_position < 0 || (!((platform_extended_mask >>
0441             (register_bit_position - 1)) & 1)))
0442         return -1;
0443 
0444     return *(intr_regs + register_bit_position);
0445 }
0446 
0447 int get_thresh_cmp_val(struct event event)
0448 {
0449     int exp = 0;
0450     u64 result = 0;
0451     u64 value;
0452 
0453     if (!have_hwcap2(PPC_FEATURE2_ARCH_3_1))
0454         return EV_CODE_EXTRACT(event.attr.config, thd_cmp);
0455 
0456     value = EV_CODE_EXTRACT(event.attr.config1, thd_cmp);
0457 
0458     if (!value)
0459         return value;
0460 
0461     /*
0462      * Incase of P10, thresh_cmp value is not part of raw event code
0463      * and provided via attr.config1 parameter. To program threshold in MMCRA,
0464      * take a 18 bit number N and shift right 2 places and increment
0465      * the exponent E by 1 until the upper 10 bits of N are zero.
0466      * Write E to the threshold exponent and write the lower 8 bits of N
0467      * to the threshold mantissa.
0468      * The max threshold that can be written is 261120.
0469      */
0470     if (value > 261120)
0471         value = 261120;
0472     while ((64 - __builtin_clzl(value)) > 8) {
0473         exp++;
0474         value >>= 2;
0475     }
0476 
0477     /*
0478      * Note that it is invalid to write a mantissa with the
0479      * upper 2 bits of mantissa being zero, unless the
0480      * exponent is also zero.
0481      */
0482     if (!(value & 0xC0) && exp)
0483         result = -1;
0484     else
0485         result = (exp << 8) | value;
0486     return result;
0487 }
0488 
0489 /*
0490  * Utility function to check for generic compat PMU
0491  * by comparing base_platform value from auxv and real
0492  * PVR value.
0493  */
0494 static bool auxv_generic_compat_pmu(void)
0495 {
0496     int base_pvr = 0;
0497 
0498     if (!strcmp(auxv_base_platform(), "power9"))
0499         base_pvr = POWER9;
0500     else if (!strcmp(auxv_base_platform(), "power10"))
0501         base_pvr = POWER10;
0502 
0503     return (!base_pvr);
0504 }
0505 
0506 /*
0507  * Check for generic compat PMU.
0508  * First check for presence of pmu_name from
0509  * "/sys/bus/event_source/devices/cpu/caps".
0510  * If doesn't exist, fallback to using value
0511  * auxv.
0512  */
0513 bool check_for_generic_compat_pmu(void)
0514 {
0515     char pmu_name[256];
0516 
0517     memset(pmu_name, 0, sizeof(pmu_name));
0518     if (read_sysfs_file("bus/event_source/devices/cpu/caps/pmu_name",
0519         pmu_name, sizeof(pmu_name)) < 0)
0520         return auxv_generic_compat_pmu();
0521 
0522     if (!strcmp(pmu_name, "ISAv3"))
0523         return true;
0524     else
0525         return false;
0526 }
0527 
0528 /*
0529  * Check if system is booted in compat mode.
0530  */
0531 bool check_for_compat_mode(void)
0532 {
0533     char *platform = auxv_platform();
0534     char *base_platform = auxv_base_platform();
0535 
0536     return strcmp(platform, base_platform);
0537 }