538 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			538 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-only
 | 
						|
/*
 | 
						|
 * Copyright 2022, Athira Rajeev, IBM Corp.
 | 
						|
 * Copyright 2022, Madhavan Srinivasan, IBM Corp.
 | 
						|
 * Copyright 2022, Kajol Jain, IBM Corp.
 | 
						|
 */
 | 
						|
 | 
						|
#include <unistd.h>
 | 
						|
#include <sys/syscall.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <sys/ioctl.h>
 | 
						|
#include <sys/mman.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <ctype.h>
 | 
						|
 | 
						|
#include "misc.h"
 | 
						|
 | 
						|
#define PAGE_SIZE               sysconf(_SC_PAGESIZE)
 | 
						|
 | 
						|
/* Storage for platform version */
 | 
						|
int pvr;
 | 
						|
u64 platform_extended_mask;
 | 
						|
 | 
						|
/* Mask and Shift for Event code fields */
 | 
						|
int ev_mask_pmcxsel, ev_shift_pmcxsel;		//pmcxsel field
 | 
						|
int ev_mask_marked, ev_shift_marked;		//marked filed
 | 
						|
int ev_mask_comb, ev_shift_comb;		//combine field
 | 
						|
int ev_mask_unit, ev_shift_unit;		//unit field
 | 
						|
int ev_mask_pmc, ev_shift_pmc;			//pmc field
 | 
						|
int ev_mask_cache, ev_shift_cache;		//Cache sel field
 | 
						|
int ev_mask_sample, ev_shift_sample;		//Random sampling field
 | 
						|
int ev_mask_thd_sel, ev_shift_thd_sel;		//thresh_sel field
 | 
						|
int ev_mask_thd_start, ev_shift_thd_start;	//thresh_start field
 | 
						|
int ev_mask_thd_stop, ev_shift_thd_stop;	//thresh_stop field
 | 
						|
int ev_mask_thd_cmp, ev_shift_thd_cmp;		//thresh cmp field
 | 
						|
int ev_mask_sm, ev_shift_sm;			//SDAR mode field
 | 
						|
int ev_mask_rsq, ev_shift_rsq;			//radix scope qual field
 | 
						|
int ev_mask_l2l3, ev_shift_l2l3;		//l2l3 sel field
 | 
						|
int ev_mask_mmcr3_src, ev_shift_mmcr3_src;	//mmcr3 field
 | 
						|
 | 
						|
static void init_ev_encodes(void)
 | 
						|
{
 | 
						|
	ev_mask_pmcxsel = 0xff;
 | 
						|
	ev_shift_pmcxsel = 0;
 | 
						|
	ev_mask_marked = 1;
 | 
						|
	ev_shift_marked = 8;
 | 
						|
	ev_mask_unit = 0xf;
 | 
						|
	ev_shift_unit = 12;
 | 
						|
	ev_mask_pmc = 0xf;
 | 
						|
	ev_shift_pmc = 16;
 | 
						|
	ev_mask_sample	= 0x1f;
 | 
						|
	ev_shift_sample = 24;
 | 
						|
	ev_mask_thd_sel = 0x7;
 | 
						|
	ev_shift_thd_sel = 29;
 | 
						|
	ev_mask_thd_start = 0xf;
 | 
						|
	ev_shift_thd_start = 36;
 | 
						|
	ev_mask_thd_stop = 0xf;
 | 
						|
	ev_shift_thd_stop = 32;
 | 
						|
 | 
						|
	switch (pvr) {
 | 
						|
	case POWER10:
 | 
						|
		ev_mask_thd_cmp = 0x3ffff;
 | 
						|
		ev_shift_thd_cmp = 0;
 | 
						|
		ev_mask_rsq = 1;
 | 
						|
		ev_shift_rsq = 9;
 | 
						|
		ev_mask_comb = 3;
 | 
						|
		ev_shift_comb = 10;
 | 
						|
		ev_mask_cache = 3;
 | 
						|
		ev_shift_cache = 20;
 | 
						|
		ev_mask_sm = 0x3;
 | 
						|
		ev_shift_sm = 22;
 | 
						|
		ev_mask_l2l3 = 0x1f;
 | 
						|
		ev_shift_l2l3 = 40;
 | 
						|
		ev_mask_mmcr3_src = 0x7fff;
 | 
						|
		ev_shift_mmcr3_src = 45;
 | 
						|
		break;
 | 
						|
	case POWER9:
 | 
						|
		ev_mask_comb = 3;
 | 
						|
		ev_shift_comb = 10;
 | 
						|
		ev_mask_cache = 0xf;
 | 
						|
		ev_shift_cache = 20;
 | 
						|
		ev_mask_thd_cmp = 0x3ff;
 | 
						|
		ev_shift_thd_cmp = 40;
 | 
						|
		ev_mask_sm = 0x3;
 | 
						|
		ev_shift_sm = 50;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		FAIL_IF_EXIT(1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Return the extended regs mask value */
 | 
						|
static u64 perf_get_platform_reg_mask(void)
 | 
						|
{
 | 
						|
	if (have_hwcap2(PPC_FEATURE2_ARCH_3_1))
 | 
						|
		return PERF_POWER10_MASK;
 | 
						|
	if (have_hwcap2(PPC_FEATURE2_ARCH_3_00))
 | 
						|
		return PERF_POWER9_MASK;
 | 
						|
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
int check_extended_regs_support(void)
 | 
						|
{
 | 
						|
	int fd;
 | 
						|
	struct event event;
 | 
						|
 | 
						|
	event_init(&event, 0x1001e);
 | 
						|
 | 
						|
	event.attr.type = 4;
 | 
						|
	event.attr.sample_period = 1;
 | 
						|
	event.attr.disabled = 1;
 | 
						|
	event.attr.sample_type = PERF_SAMPLE_REGS_INTR;
 | 
						|
	event.attr.sample_regs_intr = platform_extended_mask;
 | 
						|
 | 
						|
	fd = event_open(&event);
 | 
						|
	if (fd != -1)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
int platform_check_for_tests(void)
 | 
						|
{
 | 
						|
	pvr = PVR_VER(mfspr(SPRN_PVR));
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Check for supported platforms
 | 
						|
	 * for sampling test
 | 
						|
	 */
 | 
						|
	if ((pvr != POWER10) && (pvr != POWER9))
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Check PMU driver registered by looking for
 | 
						|
	 * PPC_FEATURE2_EBB bit in AT_HWCAP2
 | 
						|
	 */
 | 
						|
	if (!have_hwcap2(PPC_FEATURE2_EBB) || !have_hwcap2(PPC_FEATURE2_ARCH_3_00))
 | 
						|
		goto out;
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
out:
 | 
						|
	printf("%s: Tests unsupported for this platform\n", __func__);
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
int check_pvr_for_sampling_tests(void)
 | 
						|
{
 | 
						|
	SKIP_IF(platform_check_for_tests());
 | 
						|
 | 
						|
	platform_extended_mask = perf_get_platform_reg_mask();
 | 
						|
	/* check if platform supports extended regs */
 | 
						|
	if (check_extended_regs_support())
 | 
						|
		goto out;
 | 
						|
 | 
						|
	init_ev_encodes();
 | 
						|
	return 0;
 | 
						|
 | 
						|
out:
 | 
						|
	printf("%s: Sampling tests un-supported\n", __func__);
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Allocate mmap buffer of "mmap_pages" number of
 | 
						|
 * pages.
 | 
						|
 */
 | 
						|
void *event_sample_buf_mmap(int fd, int mmap_pages)
 | 
						|
{
 | 
						|
	size_t page_size = sysconf(_SC_PAGESIZE);
 | 
						|
	size_t mmap_size;
 | 
						|
	void *buff;
 | 
						|
 | 
						|
	if (mmap_pages <= 0)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	if (fd <= 0)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	mmap_size =  page_size * (1 + mmap_pages);
 | 
						|
	buff = mmap(NULL, mmap_size,
 | 
						|
		PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 | 
						|
 | 
						|
	if (buff == MAP_FAILED) {
 | 
						|
		perror("mmap() failed.");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return buff;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Post process the mmap buffer.
 | 
						|
 * - If sample_count != NULL then return count of total
 | 
						|
 *   number of samples present in the mmap buffer.
 | 
						|
 * - If sample_count == NULL then return the address
 | 
						|
 *   of first sample from the mmap buffer
 | 
						|
 */
 | 
						|
void *__event_read_samples(void *sample_buff, size_t *size, u64 *sample_count)
 | 
						|
{
 | 
						|
	size_t page_size = sysconf(_SC_PAGESIZE);
 | 
						|
	struct perf_event_header *header = sample_buff + page_size;
 | 
						|
	struct perf_event_mmap_page *metadata_page = sample_buff;
 | 
						|
	unsigned long data_head, data_tail;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * PERF_RECORD_SAMPLE:
 | 
						|
	 * struct {
 | 
						|
	 *     struct perf_event_header hdr;
 | 
						|
	 *     u64 data[];
 | 
						|
	 * };
 | 
						|
	 */
 | 
						|
 | 
						|
	data_head = metadata_page->data_head;
 | 
						|
	/* sync memory before reading sample */
 | 
						|
	mb();
 | 
						|
	data_tail = metadata_page->data_tail;
 | 
						|
 | 
						|
	/* Check for sample_count */
 | 
						|
	if (sample_count)
 | 
						|
		*sample_count = 0;
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		/*
 | 
						|
		 * Reads the mmap data buffer by moving
 | 
						|
		 * the data_tail to know the last read data.
 | 
						|
		 * data_head points to head in data buffer.
 | 
						|
		 * refer "struct perf_event_mmap_page" in
 | 
						|
		 * "include/uapi/linux/perf_event.h".
 | 
						|
		 */
 | 
						|
		if (data_head - data_tail < sizeof(header))
 | 
						|
			return NULL;
 | 
						|
 | 
						|
		data_tail += sizeof(header);
 | 
						|
		if (header->type == PERF_RECORD_SAMPLE) {
 | 
						|
			*size = (header->size - sizeof(header));
 | 
						|
			if (!sample_count)
 | 
						|
				return sample_buff + page_size + data_tail;
 | 
						|
			data_tail += *size;
 | 
						|
			*sample_count += 1;
 | 
						|
		} else {
 | 
						|
			*size = (header->size - sizeof(header));
 | 
						|
			if ((metadata_page->data_tail + *size) > metadata_page->data_head)
 | 
						|
				data_tail = metadata_page->data_head;
 | 
						|
			else
 | 
						|
				data_tail += *size;
 | 
						|
		}
 | 
						|
		header = (struct perf_event_header *)((void *)header + header->size);
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
int collect_samples(void *sample_buff)
 | 
						|
{
 | 
						|
	u64 sample_count;
 | 
						|
	size_t size = 0;
 | 
						|
 | 
						|
	__event_read_samples(sample_buff, &size, &sample_count);
 | 
						|
	return sample_count;
 | 
						|
}
 | 
						|
 | 
						|
static void *perf_read_first_sample(void *sample_buff, size_t *size)
 | 
						|
{
 | 
						|
	return __event_read_samples(sample_buff, size, NULL);
 | 
						|
}
 | 
						|
 | 
						|
u64 *get_intr_regs(struct event *event, void *sample_buff)
 | 
						|
{
 | 
						|
	u64 type = event->attr.sample_type;
 | 
						|
	u64 *intr_regs;
 | 
						|
	size_t size = 0;
 | 
						|
 | 
						|
	if ((type ^ (PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_BRANCH_STACK)) &&
 | 
						|
			(type  ^ PERF_SAMPLE_REGS_INTR))
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	intr_regs = (u64 *)perf_read_first_sample(sample_buff, &size);
 | 
						|
	if (!intr_regs)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	if (type & PERF_SAMPLE_BRANCH_STACK) {
 | 
						|
		/*
 | 
						|
		 * PERF_RECORD_SAMPLE and PERF_SAMPLE_BRANCH_STACK:
 | 
						|
		 * struct {
 | 
						|
		 *     struct perf_event_header hdr;
 | 
						|
		 *     u64 number_of_branches;
 | 
						|
		 *     struct perf_branch_entry[number_of_branches];
 | 
						|
		 *     u64 data[];
 | 
						|
		 * };
 | 
						|
		 * struct perf_branch_entry {
 | 
						|
		 *     u64	from;
 | 
						|
		 *     u64	to;
 | 
						|
		 *     u64	misc;
 | 
						|
		 * };
 | 
						|
		 */
 | 
						|
		intr_regs += ((*intr_regs) * 3) + 1;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * First entry in the sample buffer used to specify
 | 
						|
	 * PERF_SAMPLE_REGS_ABI_64, skip perf regs abi to access
 | 
						|
	 * interrupt registers.
 | 
						|
	 */
 | 
						|
	++intr_regs;
 | 
						|
 | 
						|
	return intr_regs;
 | 
						|
}
 | 
						|
 | 
						|
static const int __perf_reg_mask(const char *register_name)
 | 
						|
{
 | 
						|
	if (!strcmp(register_name, "R0"))
 | 
						|
		return 0;
 | 
						|
	else if (!strcmp(register_name, "R1"))
 | 
						|
		return 1;
 | 
						|
	else if (!strcmp(register_name, "R2"))
 | 
						|
		return 2;
 | 
						|
	else if (!strcmp(register_name, "R3"))
 | 
						|
		return 3;
 | 
						|
	else if (!strcmp(register_name, "R4"))
 | 
						|
		return 4;
 | 
						|
	else if (!strcmp(register_name, "R5"))
 | 
						|
		return 5;
 | 
						|
	else if (!strcmp(register_name, "R6"))
 | 
						|
		return 6;
 | 
						|
	else if (!strcmp(register_name, "R7"))
 | 
						|
		return 7;
 | 
						|
	else if (!strcmp(register_name, "R8"))
 | 
						|
		return 8;
 | 
						|
	else if (!strcmp(register_name, "R9"))
 | 
						|
		return 9;
 | 
						|
	else if (!strcmp(register_name, "R10"))
 | 
						|
		return 10;
 | 
						|
	else if (!strcmp(register_name, "R11"))
 | 
						|
		return 11;
 | 
						|
	else if (!strcmp(register_name, "R12"))
 | 
						|
		return 12;
 | 
						|
	else if (!strcmp(register_name, "R13"))
 | 
						|
		return 13;
 | 
						|
	else if (!strcmp(register_name, "R14"))
 | 
						|
		return 14;
 | 
						|
	else if (!strcmp(register_name, "R15"))
 | 
						|
		return 15;
 | 
						|
	else if (!strcmp(register_name, "R16"))
 | 
						|
		return 16;
 | 
						|
	else if (!strcmp(register_name, "R17"))
 | 
						|
		return 17;
 | 
						|
	else if (!strcmp(register_name, "R18"))
 | 
						|
		return 18;
 | 
						|
	else if (!strcmp(register_name, "R19"))
 | 
						|
		return 19;
 | 
						|
	else if (!strcmp(register_name, "R20"))
 | 
						|
		return 20;
 | 
						|
	else if (!strcmp(register_name, "R21"))
 | 
						|
		return 21;
 | 
						|
	else if (!strcmp(register_name, "R22"))
 | 
						|
		return 22;
 | 
						|
	else if (!strcmp(register_name, "R23"))
 | 
						|
		return 23;
 | 
						|
	else if (!strcmp(register_name, "R24"))
 | 
						|
		return 24;
 | 
						|
	else if (!strcmp(register_name, "R25"))
 | 
						|
		return 25;
 | 
						|
	else if (!strcmp(register_name, "R26"))
 | 
						|
		return 26;
 | 
						|
	else if (!strcmp(register_name, "R27"))
 | 
						|
		return 27;
 | 
						|
	else if (!strcmp(register_name, "R28"))
 | 
						|
		return 28;
 | 
						|
	else if (!strcmp(register_name, "R29"))
 | 
						|
		return 29;
 | 
						|
	else if (!strcmp(register_name, "R30"))
 | 
						|
		return 30;
 | 
						|
	else if (!strcmp(register_name, "R31"))
 | 
						|
		return 31;
 | 
						|
	else if (!strcmp(register_name, "NIP"))
 | 
						|
		return 32;
 | 
						|
	else if (!strcmp(register_name, "MSR"))
 | 
						|
		return 33;
 | 
						|
	else if (!strcmp(register_name, "ORIG_R3"))
 | 
						|
		return 34;
 | 
						|
	else if (!strcmp(register_name, "CTR"))
 | 
						|
		return 35;
 | 
						|
	else if (!strcmp(register_name, "LINK"))
 | 
						|
		return 36;
 | 
						|
	else if (!strcmp(register_name, "XER"))
 | 
						|
		return 37;
 | 
						|
	else if (!strcmp(register_name, "CCR"))
 | 
						|
		return 38;
 | 
						|
	else if (!strcmp(register_name, "SOFTE"))
 | 
						|
		return 39;
 | 
						|
	else if (!strcmp(register_name, "TRAP"))
 | 
						|
		return 40;
 | 
						|
	else if (!strcmp(register_name, "DAR"))
 | 
						|
		return 41;
 | 
						|
	else if (!strcmp(register_name, "DSISR"))
 | 
						|
		return 42;
 | 
						|
	else if (!strcmp(register_name, "SIER"))
 | 
						|
		return 43;
 | 
						|
	else if (!strcmp(register_name, "MMCRA"))
 | 
						|
		return 44;
 | 
						|
	else if (!strcmp(register_name, "MMCR0"))
 | 
						|
		return 45;
 | 
						|
	else if (!strcmp(register_name, "MMCR1"))
 | 
						|
		return 46;
 | 
						|
	else if (!strcmp(register_name, "MMCR2"))
 | 
						|
		return 47;
 | 
						|
	else if (!strcmp(register_name, "MMCR3"))
 | 
						|
		return 48;
 | 
						|
	else if (!strcmp(register_name, "SIER2"))
 | 
						|
		return 49;
 | 
						|
	else if (!strcmp(register_name, "SIER3"))
 | 
						|
		return 50;
 | 
						|
	else if (!strcmp(register_name, "PMC1"))
 | 
						|
		return 51;
 | 
						|
	else if (!strcmp(register_name, "PMC2"))
 | 
						|
		return 52;
 | 
						|
	else if (!strcmp(register_name, "PMC3"))
 | 
						|
		return 53;
 | 
						|
	else if (!strcmp(register_name, "PMC4"))
 | 
						|
		return 54;
 | 
						|
	else if (!strcmp(register_name, "PMC5"))
 | 
						|
		return 55;
 | 
						|
	else if (!strcmp(register_name, "PMC6"))
 | 
						|
		return 56;
 | 
						|
	else if (!strcmp(register_name, "SDAR"))
 | 
						|
		return 57;
 | 
						|
	else if (!strcmp(register_name, "SIAR"))
 | 
						|
		return 58;
 | 
						|
	else
 | 
						|
		return -1;
 | 
						|
}
 | 
						|
 | 
						|
u64 get_reg_value(u64 *intr_regs, char *register_name)
 | 
						|
{
 | 
						|
	int register_bit_position;
 | 
						|
 | 
						|
	register_bit_position = __perf_reg_mask(register_name);
 | 
						|
 | 
						|
	if (register_bit_position < 0 || (!((platform_extended_mask >>
 | 
						|
			(register_bit_position - 1)) & 1)))
 | 
						|
		return -1;
 | 
						|
 | 
						|
	return *(intr_regs + register_bit_position);
 | 
						|
}
 | 
						|
 | 
						|
int get_thresh_cmp_val(struct event event)
 | 
						|
{
 | 
						|
	int exp = 0;
 | 
						|
	u64 result = 0;
 | 
						|
	u64 value;
 | 
						|
 | 
						|
	if (!have_hwcap2(PPC_FEATURE2_ARCH_3_1))
 | 
						|
		return EV_CODE_EXTRACT(event.attr.config, thd_cmp);
 | 
						|
 | 
						|
	value = EV_CODE_EXTRACT(event.attr.config1, thd_cmp);
 | 
						|
 | 
						|
	if (!value)
 | 
						|
		return value;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Incase of P10, thresh_cmp value is not part of raw event code
 | 
						|
	 * and provided via attr.config1 parameter. To program threshold in MMCRA,
 | 
						|
	 * take a 18 bit number N and shift right 2 places and increment
 | 
						|
	 * the exponent E by 1 until the upper 10 bits of N are zero.
 | 
						|
	 * Write E to the threshold exponent and write the lower 8 bits of N
 | 
						|
	 * to the threshold mantissa.
 | 
						|
	 * The max threshold that can be written is 261120.
 | 
						|
	 */
 | 
						|
	if (value > 261120)
 | 
						|
		value = 261120;
 | 
						|
	while ((64 - __builtin_clzl(value)) > 8) {
 | 
						|
		exp++;
 | 
						|
		value >>= 2;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Note that it is invalid to write a mantissa with the
 | 
						|
	 * upper 2 bits of mantissa being zero, unless the
 | 
						|
	 * exponent is also zero.
 | 
						|
	 */
 | 
						|
	if (!(value & 0xC0) && exp)
 | 
						|
		result = -1;
 | 
						|
	else
 | 
						|
		result = (exp << 8) | value;
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Utility function to check for generic compat PMU
 | 
						|
 * by comparing base_platform value from auxv and real
 | 
						|
 * PVR value.
 | 
						|
 */
 | 
						|
static bool auxv_generic_compat_pmu(void)
 | 
						|
{
 | 
						|
	int base_pvr = 0;
 | 
						|
 | 
						|
	if (!strcmp(auxv_base_platform(), "power9"))
 | 
						|
		base_pvr = POWER9;
 | 
						|
	else if (!strcmp(auxv_base_platform(), "power10"))
 | 
						|
		base_pvr = POWER10;
 | 
						|
 | 
						|
	return (!base_pvr);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Check for generic compat PMU.
 | 
						|
 * First check for presence of pmu_name from
 | 
						|
 * "/sys/bus/event_source/devices/cpu/caps".
 | 
						|
 * If doesn't exist, fallback to using value
 | 
						|
 * auxv.
 | 
						|
 */
 | 
						|
bool check_for_generic_compat_pmu(void)
 | 
						|
{
 | 
						|
	char pmu_name[256];
 | 
						|
 | 
						|
	memset(pmu_name, 0, sizeof(pmu_name));
 | 
						|
	if (read_sysfs_file("bus/event_source/devices/cpu/caps/pmu_name",
 | 
						|
		pmu_name, sizeof(pmu_name)) < 0)
 | 
						|
		return auxv_generic_compat_pmu();
 | 
						|
 | 
						|
	if (!strcmp(pmu_name, "ISAv3"))
 | 
						|
		return true;
 | 
						|
	else
 | 
						|
		return false;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Check if system is booted in compat mode.
 | 
						|
 */
 | 
						|
bool check_for_compat_mode(void)
 | 
						|
{
 | 
						|
	char *platform = auxv_platform();
 | 
						|
	char *base_platform = auxv_base_platform();
 | 
						|
 | 
						|
	return strcmp(platform, base_platform);
 | 
						|
}
 |