brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · eac6420 Raw
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