File Index
Files and directories
Sign in
FILE

misc.c

File preview with syntax highlighting.

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