xref: /openbmc/linux/tools/testing/selftests/powerpc/pmu/ebb/ebb.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
1*f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23752e453SMichael Ellerman /*
33752e453SMichael Ellerman  * Copyright 2014, Michael Ellerman, IBM Corp.
43752e453SMichael Ellerman  */
53752e453SMichael Ellerman 
63752e453SMichael Ellerman #define _GNU_SOURCE	/* For CPU_ZERO etc. */
73752e453SMichael Ellerman 
83752e453SMichael Ellerman #include <sched.h>
93752e453SMichael Ellerman #include <sys/wait.h>
103752e453SMichael Ellerman #include <setjmp.h>
113752e453SMichael Ellerman #include <signal.h>
123752e453SMichael Ellerman #include <stdio.h>
133752e453SMichael Ellerman #include <stdlib.h>
143752e453SMichael Ellerman #include <string.h>
153752e453SMichael Ellerman #include <sys/ioctl.h>
163752e453SMichael Ellerman 
173752e453SMichael Ellerman #include "trace.h"
183752e453SMichael Ellerman #include "ebb.h"
193752e453SMichael Ellerman 
203752e453SMichael Ellerman 
213752e453SMichael Ellerman void (*ebb_user_func)(void);
223752e453SMichael Ellerman 
ebb_hook(void)233752e453SMichael Ellerman void ebb_hook(void)
243752e453SMichael Ellerman {
253752e453SMichael Ellerman 	if (ebb_user_func)
263752e453SMichael Ellerman 		ebb_user_func();
273752e453SMichael Ellerman }
283752e453SMichael Ellerman 
293752e453SMichael Ellerman struct ebb_state ebb_state;
303752e453SMichael Ellerman 
313752e453SMichael Ellerman u64 sample_period = 0x40000000ull;
323752e453SMichael Ellerman 
reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask)333752e453SMichael Ellerman void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask)
343752e453SMichael Ellerman {
353752e453SMichael Ellerman 	u64 val;
363752e453SMichael Ellerman 
373752e453SMichael Ellerman 	/* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */
383752e453SMichael Ellerman 	/* 3) set MMCR0[PMAE]	- docs say BESCR[PME] should do this */
393752e453SMichael Ellerman 	val = mfspr(SPRN_MMCR0);
403752e453SMichael Ellerman 	mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE);
413752e453SMichael Ellerman 
423752e453SMichael Ellerman 	/* 4) clear BESCR[PMEO] */
433752e453SMichael Ellerman 	mtspr(SPRN_BESCRR, BESCR_PMEO);
443752e453SMichael Ellerman 
453752e453SMichael Ellerman 	/* 5) set BESCR[PME] */
463752e453SMichael Ellerman 	mtspr(SPRN_BESCRS, BESCR_PME);
473752e453SMichael Ellerman 
483752e453SMichael Ellerman 	/* 6) rfebb 1 - done in our caller */
493752e453SMichael Ellerman }
503752e453SMichael Ellerman 
reset_ebb(void)513752e453SMichael Ellerman void reset_ebb(void)
523752e453SMichael Ellerman {
533752e453SMichael Ellerman 	reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC);
543752e453SMichael Ellerman }
553752e453SMichael Ellerman 
563752e453SMichael Ellerman /* Called outside of the EBB handler to check MMCR0 is sane */
ebb_check_mmcr0(void)573752e453SMichael Ellerman int ebb_check_mmcr0(void)
583752e453SMichael Ellerman {
593752e453SMichael Ellerman 	u64 val;
603752e453SMichael Ellerman 
613752e453SMichael Ellerman 	val = mfspr(SPRN_MMCR0);
623752e453SMichael Ellerman 	if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) {
633752e453SMichael Ellerman 		/* It's OK if we see FC & PMAO, but not FC by itself */
643752e453SMichael Ellerman 		printf("Outside of loop, only FC set 0x%llx\n", val);
653752e453SMichael Ellerman 		return 1;
663752e453SMichael Ellerman 	}
673752e453SMichael Ellerman 
683752e453SMichael Ellerman 	return 0;
693752e453SMichael Ellerman }
703752e453SMichael Ellerman 
ebb_check_count(int pmc,u64 sample_period,int fudge)713752e453SMichael Ellerman bool ebb_check_count(int pmc, u64 sample_period, int fudge)
723752e453SMichael Ellerman {
733752e453SMichael Ellerman 	u64 count, upper, lower;
743752e453SMichael Ellerman 
753752e453SMichael Ellerman 	count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)];
763752e453SMichael Ellerman 
773752e453SMichael Ellerman 	lower = ebb_state.stats.ebb_count * (sample_period - fudge);
783752e453SMichael Ellerman 
793752e453SMichael Ellerman 	if (count < lower) {
803752e453SMichael Ellerman 		printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n",
813752e453SMichael Ellerman 			pmc, count, lower, lower - count);
823752e453SMichael Ellerman 		return false;
833752e453SMichael Ellerman 	}
843752e453SMichael Ellerman 
853752e453SMichael Ellerman 	upper = ebb_state.stats.ebb_count * (sample_period + fudge);
863752e453SMichael Ellerman 
873752e453SMichael Ellerman 	if (count > upper) {
883752e453SMichael Ellerman 		printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n",
893752e453SMichael Ellerman 			pmc, count, upper, count - upper);
903752e453SMichael Ellerman 		return false;
913752e453SMichael Ellerman 	}
923752e453SMichael Ellerman 
933752e453SMichael Ellerman 	printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n",
943752e453SMichael Ellerman 		pmc, count, lower, upper, count - lower, upper - count);
953752e453SMichael Ellerman 
963752e453SMichael Ellerman 	return true;
973752e453SMichael Ellerman }
983752e453SMichael Ellerman 
standard_ebb_callee(void)993752e453SMichael Ellerman void standard_ebb_callee(void)
1003752e453SMichael Ellerman {
1013752e453SMichael Ellerman 	int found, i;
1023752e453SMichael Ellerman 	u64 val;
1033752e453SMichael Ellerman 
1043752e453SMichael Ellerman 	val = mfspr(SPRN_BESCR);
1053752e453SMichael Ellerman 	if (!(val & BESCR_PMEO)) {
1063752e453SMichael Ellerman 		ebb_state.stats.spurious++;
1073752e453SMichael Ellerman 		goto out;
1083752e453SMichael Ellerman 	}
1093752e453SMichael Ellerman 
1103752e453SMichael Ellerman 	ebb_state.stats.ebb_count++;
1113752e453SMichael Ellerman 	trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
1123752e453SMichael Ellerman 
1133752e453SMichael Ellerman 	val = mfspr(SPRN_MMCR0);
1143752e453SMichael Ellerman 	trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
1153752e453SMichael Ellerman 
1163752e453SMichael Ellerman 	found = 0;
1173752e453SMichael Ellerman 	for (i = 1; i <= 6; i++) {
1183752e453SMichael Ellerman 		if (ebb_state.pmc_enable[PMC_INDEX(i)])
1193752e453SMichael Ellerman 			found += count_pmc(i, sample_period);
1203752e453SMichael Ellerman 	}
1213752e453SMichael Ellerman 
1223752e453SMichael Ellerman 	if (!found)
1233752e453SMichael Ellerman 		ebb_state.stats.no_overflow++;
1243752e453SMichael Ellerman 
1253752e453SMichael Ellerman out:
1263752e453SMichael Ellerman 	reset_ebb();
1273752e453SMichael Ellerman }
1283752e453SMichael Ellerman 
1293752e453SMichael Ellerman extern void ebb_handler(void);
1303752e453SMichael Ellerman 
setup_ebb_handler(void (* callee)(void))1313752e453SMichael Ellerman void setup_ebb_handler(void (*callee)(void))
1323752e453SMichael Ellerman {
1333752e453SMichael Ellerman 	u64 entry;
1343752e453SMichael Ellerman 
1353752e453SMichael Ellerman #if defined(_CALL_ELF) && _CALL_ELF == 2
1363752e453SMichael Ellerman 	entry = (u64)ebb_handler;
1373752e453SMichael Ellerman #else
1383752e453SMichael Ellerman 	struct opd
1393752e453SMichael Ellerman 	{
1403752e453SMichael Ellerman 	    u64 entry;
1413752e453SMichael Ellerman 	    u64 toc;
1423752e453SMichael Ellerman 	} *opd;
1433752e453SMichael Ellerman 
1443752e453SMichael Ellerman 	opd = (struct opd *)ebb_handler;
1453752e453SMichael Ellerman 	entry = opd->entry;
1463752e453SMichael Ellerman #endif
1473752e453SMichael Ellerman 	printf("EBB Handler is at %#llx\n", entry);
1483752e453SMichael Ellerman 
1493752e453SMichael Ellerman 	ebb_user_func = callee;
1503752e453SMichael Ellerman 
1513752e453SMichael Ellerman 	/* Ensure ebb_user_func is set before we set the handler */
1523752e453SMichael Ellerman 	mb();
1533752e453SMichael Ellerman 	mtspr(SPRN_EBBHR, entry);
1543752e453SMichael Ellerman 
1553752e453SMichael Ellerman 	/* Make sure the handler is set before we return */
1563752e453SMichael Ellerman 	mb();
1573752e453SMichael Ellerman }
1583752e453SMichael Ellerman 
clear_ebb_stats(void)1593752e453SMichael Ellerman void clear_ebb_stats(void)
1603752e453SMichael Ellerman {
1613752e453SMichael Ellerman 	memset(&ebb_state.stats, 0, sizeof(ebb_state.stats));
1623752e453SMichael Ellerman }
1633752e453SMichael Ellerman 
dump_summary_ebb_state(void)1643752e453SMichael Ellerman void dump_summary_ebb_state(void)
1653752e453SMichael Ellerman {
1663752e453SMichael Ellerman 	printf("ebb_state:\n"			\
1673752e453SMichael Ellerman 	       "  ebb_count    = %d\n"		\
1683752e453SMichael Ellerman 	       "  spurious     = %d\n"		\
1693752e453SMichael Ellerman 	       "  negative     = %d\n"		\
1703752e453SMichael Ellerman 	       "  no_overflow  = %d\n"		\
1713752e453SMichael Ellerman 	       "  pmc[1] count = 0x%llx\n"	\
1723752e453SMichael Ellerman 	       "  pmc[2] count = 0x%llx\n"	\
1733752e453SMichael Ellerman 	       "  pmc[3] count = 0x%llx\n"	\
1743752e453SMichael Ellerman 	       "  pmc[4] count = 0x%llx\n"	\
1753752e453SMichael Ellerman 	       "  pmc[5] count = 0x%llx\n"	\
1763752e453SMichael Ellerman 	       "  pmc[6] count = 0x%llx\n",
1773752e453SMichael Ellerman 		ebb_state.stats.ebb_count, ebb_state.stats.spurious,
1783752e453SMichael Ellerman 		ebb_state.stats.negative, ebb_state.stats.no_overflow,
1793752e453SMichael Ellerman 		ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1],
1803752e453SMichael Ellerman 		ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3],
1813752e453SMichael Ellerman 		ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]);
1823752e453SMichael Ellerman }
1833752e453SMichael Ellerman 
decode_mmcr0(u32 value)1843752e453SMichael Ellerman static char *decode_mmcr0(u32 value)
1853752e453SMichael Ellerman {
1863752e453SMichael Ellerman 	static char buf[16];
1873752e453SMichael Ellerman 
1883752e453SMichael Ellerman 	buf[0] = '\0';
1893752e453SMichael Ellerman 
1903752e453SMichael Ellerman 	if (value & (1 << 31))
1913752e453SMichael Ellerman 		strcat(buf, "FC ");
1923752e453SMichael Ellerman 	if (value & (1 << 26))
1933752e453SMichael Ellerman 		strcat(buf, "PMAE ");
1943752e453SMichael Ellerman 	if (value & (1 << 7))
1953752e453SMichael Ellerman 		strcat(buf, "PMAO ");
1963752e453SMichael Ellerman 
1973752e453SMichael Ellerman 	return buf;
1983752e453SMichael Ellerman }
1993752e453SMichael Ellerman 
decode_bescr(u64 value)2003752e453SMichael Ellerman static char *decode_bescr(u64 value)
2013752e453SMichael Ellerman {
2023752e453SMichael Ellerman 	static char buf[16];
2033752e453SMichael Ellerman 
2043752e453SMichael Ellerman 	buf[0] = '\0';
2053752e453SMichael Ellerman 
2063752e453SMichael Ellerman 	if (value & (1ull << 63))
2073752e453SMichael Ellerman 		strcat(buf, "GE ");
2083752e453SMichael Ellerman 	if (value & (1ull << 32))
2093752e453SMichael Ellerman 		strcat(buf, "PMAE ");
2103752e453SMichael Ellerman 	if (value & 1)
2113752e453SMichael Ellerman 		strcat(buf, "PMAO ");
2123752e453SMichael Ellerman 
2133752e453SMichael Ellerman 	return buf;
2143752e453SMichael Ellerman }
2153752e453SMichael Ellerman 
dump_ebb_hw_state(void)2163752e453SMichael Ellerman void dump_ebb_hw_state(void)
2173752e453SMichael Ellerman {
2183752e453SMichael Ellerman 	u64 bescr;
2193752e453SMichael Ellerman 	u32 mmcr0;
2203752e453SMichael Ellerman 
2213752e453SMichael Ellerman 	mmcr0 = mfspr(SPRN_MMCR0);
2223752e453SMichael Ellerman 	bescr = mfspr(SPRN_BESCR);
2233752e453SMichael Ellerman 
2243752e453SMichael Ellerman 	printf("HW state:\n"		\
2253752e453SMichael Ellerman 	       "MMCR0 0x%016x %s\n"	\
226c418a678SMichael Ellerman 	       "MMCR2 0x%016lx\n"	\
2273752e453SMichael Ellerman 	       "EBBHR 0x%016lx\n"	\
2283752e453SMichael Ellerman 	       "BESCR 0x%016llx %s\n"	\
2293752e453SMichael Ellerman 	       "PMC1  0x%016lx\n"	\
2303752e453SMichael Ellerman 	       "PMC2  0x%016lx\n"	\
2313752e453SMichael Ellerman 	       "PMC3  0x%016lx\n"	\
2323752e453SMichael Ellerman 	       "PMC4  0x%016lx\n"	\
2333752e453SMichael Ellerman 	       "PMC5  0x%016lx\n"	\
2343752e453SMichael Ellerman 	       "PMC6  0x%016lx\n"	\
2353752e453SMichael Ellerman 	       "SIAR  0x%016lx\n",
236c418a678SMichael Ellerman 	       mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2),
237c418a678SMichael Ellerman 	       mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr),
238c418a678SMichael Ellerman 	       mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3),
239c418a678SMichael Ellerman 	       mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6),
240c418a678SMichael Ellerman 	       mfspr(SPRN_SIAR));
2413752e453SMichael Ellerman }
2423752e453SMichael Ellerman 
dump_ebb_state(void)2433752e453SMichael Ellerman void dump_ebb_state(void)
2443752e453SMichael Ellerman {
2453752e453SMichael Ellerman 	dump_summary_ebb_state();
2463752e453SMichael Ellerman 
2473752e453SMichael Ellerman 	dump_ebb_hw_state();
2483752e453SMichael Ellerman 
2493752e453SMichael Ellerman 	trace_buffer_print(ebb_state.trace);
2503752e453SMichael Ellerman }
2513752e453SMichael Ellerman 
count_pmc(int pmc,uint32_t sample_period)2523752e453SMichael Ellerman int count_pmc(int pmc, uint32_t sample_period)
2533752e453SMichael Ellerman {
2543752e453SMichael Ellerman 	uint32_t start_value;
2553752e453SMichael Ellerman 	u64 val;
2563752e453SMichael Ellerman 
2573752e453SMichael Ellerman 	/* 0) Read PMC */
2583752e453SMichael Ellerman 	start_value = pmc_sample_period(sample_period);
2593752e453SMichael Ellerman 
2603752e453SMichael Ellerman 	val = read_pmc(pmc);
2613752e453SMichael Ellerman 	if (val < start_value)
2623752e453SMichael Ellerman 		ebb_state.stats.negative++;
2633752e453SMichael Ellerman 	else
2643752e453SMichael Ellerman 		ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value;
2653752e453SMichael Ellerman 
2663752e453SMichael Ellerman 	trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val);
2673752e453SMichael Ellerman 
2683752e453SMichael Ellerman 	/* 1) Reset PMC */
2693752e453SMichael Ellerman 	write_pmc(pmc, start_value);
2703752e453SMichael Ellerman 
2713752e453SMichael Ellerman 	/* Report if we overflowed */
2723752e453SMichael Ellerman 	return val >= COUNTER_OVERFLOW;
2733752e453SMichael Ellerman }
2743752e453SMichael Ellerman 
ebb_event_enable(struct event * e)2753752e453SMichael Ellerman int ebb_event_enable(struct event *e)
2763752e453SMichael Ellerman {
2773752e453SMichael Ellerman 	int rc;
2783752e453SMichael Ellerman 
2793752e453SMichael Ellerman 	/* Ensure any SPR writes are ordered vs us */
2803752e453SMichael Ellerman 	mb();
2813752e453SMichael Ellerman 
2823752e453SMichael Ellerman 	rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
2833752e453SMichael Ellerman 	if (rc)
2843752e453SMichael Ellerman 		return rc;
2853752e453SMichael Ellerman 
2863752e453SMichael Ellerman 	rc = event_read(e);
2873752e453SMichael Ellerman 
2883752e453SMichael Ellerman 	/* Ditto */
2893752e453SMichael Ellerman 	mb();
2903752e453SMichael Ellerman 
2913752e453SMichael Ellerman 	return rc;
2923752e453SMichael Ellerman }
2933752e453SMichael Ellerman 
ebb_freeze_pmcs(void)2943752e453SMichael Ellerman void ebb_freeze_pmcs(void)
2953752e453SMichael Ellerman {
2963752e453SMichael Ellerman 	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
2973752e453SMichael Ellerman 	mb();
2983752e453SMichael Ellerman }
2993752e453SMichael Ellerman 
ebb_unfreeze_pmcs(void)3003752e453SMichael Ellerman void ebb_unfreeze_pmcs(void)
3013752e453SMichael Ellerman {
3023752e453SMichael Ellerman 	/* Unfreeze counters */
3033752e453SMichael Ellerman 	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
3043752e453SMichael Ellerman 	mb();
3053752e453SMichael Ellerman }
3063752e453SMichael Ellerman 
ebb_global_enable(void)3073752e453SMichael Ellerman void ebb_global_enable(void)
3083752e453SMichael Ellerman {
3093752e453SMichael Ellerman 	/* Enable EBBs globally and PMU EBBs */
3103752e453SMichael Ellerman 	mtspr(SPRN_BESCR, 0x8000000100000000ull);
3113752e453SMichael Ellerman 	mb();
3123752e453SMichael Ellerman }
3133752e453SMichael Ellerman 
ebb_global_disable(void)3143752e453SMichael Ellerman void ebb_global_disable(void)
3153752e453SMichael Ellerman {
3163752e453SMichael Ellerman 	/* Disable EBBs & freeze counters, events are still scheduled */
3173752e453SMichael Ellerman 	mtspr(SPRN_BESCRR, BESCR_PME);
3183752e453SMichael Ellerman 	mb();
3193752e453SMichael Ellerman }
3203752e453SMichael Ellerman 
ebb_is_supported(void)32139fcfb91SDenis Kirjanov bool ebb_is_supported(void)
32239fcfb91SDenis Kirjanov {
32339fcfb91SDenis Kirjanov #ifdef PPC_FEATURE2_EBB
32439fcfb91SDenis Kirjanov 	/* EBB requires at least POWER8 */
325ede8ef3fSMichael Ellerman 	return have_hwcap2(PPC_FEATURE2_EBB);
32639fcfb91SDenis Kirjanov #else
32739fcfb91SDenis Kirjanov 	return false;
32839fcfb91SDenis Kirjanov #endif
32939fcfb91SDenis Kirjanov }
33039fcfb91SDenis Kirjanov 
event_ebb_init(struct event * e)3313752e453SMichael Ellerman void event_ebb_init(struct event *e)
3323752e453SMichael Ellerman {
3333752e453SMichael Ellerman 	e->attr.config |= (1ull << 63);
3343752e453SMichael Ellerman }
3353752e453SMichael Ellerman 
event_bhrb_init(struct event * e,unsigned ifm)3363752e453SMichael Ellerman void event_bhrb_init(struct event *e, unsigned ifm)
3373752e453SMichael Ellerman {
3383752e453SMichael Ellerman 	e->attr.config |= (1ull << 62) | ((u64)ifm << 60);
3393752e453SMichael Ellerman }
3403752e453SMichael Ellerman 
event_leader_ebb_init(struct event * e)3413752e453SMichael Ellerman void event_leader_ebb_init(struct event *e)
3423752e453SMichael Ellerman {
3433752e453SMichael Ellerman 	event_ebb_init(e);
3443752e453SMichael Ellerman 
3453752e453SMichael Ellerman 	e->attr.exclusive = 1;
3463752e453SMichael Ellerman 	e->attr.pinned = 1;
3473752e453SMichael Ellerman }
3483752e453SMichael Ellerman 
ebb_child(union pipe read_pipe,union pipe write_pipe)3493752e453SMichael Ellerman int ebb_child(union pipe read_pipe, union pipe write_pipe)
3503752e453SMichael Ellerman {
3513752e453SMichael Ellerman 	struct event event;
3523752e453SMichael Ellerman 	uint64_t val;
3533752e453SMichael Ellerman 
3543752e453SMichael Ellerman 	FAIL_IF(wait_for_parent(read_pipe));
3553752e453SMichael Ellerman 
3563752e453SMichael Ellerman 	event_init_named(&event, 0x1001e, "cycles");
3573752e453SMichael Ellerman 	event_leader_ebb_init(&event);
3583752e453SMichael Ellerman 
3593752e453SMichael Ellerman 	event.attr.exclude_kernel = 1;
3603752e453SMichael Ellerman 	event.attr.exclude_hv = 1;
3613752e453SMichael Ellerman 	event.attr.exclude_idle = 1;
3623752e453SMichael Ellerman 
3633752e453SMichael Ellerman 	FAIL_IF(event_open(&event));
3643752e453SMichael Ellerman 
3653752e453SMichael Ellerman 	ebb_enable_pmc_counting(1);
3663752e453SMichael Ellerman 	setup_ebb_handler(standard_ebb_callee);
3673752e453SMichael Ellerman 	ebb_global_enable();
3683752e453SMichael Ellerman 
3693752e453SMichael Ellerman 	FAIL_IF(event_enable(&event));
3703752e453SMichael Ellerman 
3713752e453SMichael Ellerman 	if (event_read(&event)) {
3723752e453SMichael Ellerman 		/*
3733752e453SMichael Ellerman 		 * Some tests expect to fail here, so don't report an error on
3743752e453SMichael Ellerman 		 * this line, and return a distinguisable error code. Tell the
3753752e453SMichael Ellerman 		 * parent an error happened.
3763752e453SMichael Ellerman 		 */
3773752e453SMichael Ellerman 		notify_parent_of_error(write_pipe);
3783752e453SMichael Ellerman 		return 2;
3793752e453SMichael Ellerman 	}
3803752e453SMichael Ellerman 
3813752e453SMichael Ellerman 	mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
3823752e453SMichael Ellerman 
3833752e453SMichael Ellerman 	FAIL_IF(notify_parent(write_pipe));
3843752e453SMichael Ellerman 	FAIL_IF(wait_for_parent(read_pipe));
3853752e453SMichael Ellerman 	FAIL_IF(notify_parent(write_pipe));
3863752e453SMichael Ellerman 
3873752e453SMichael Ellerman 	while (ebb_state.stats.ebb_count < 20) {
3883752e453SMichael Ellerman 		FAIL_IF(core_busy_loop());
3893752e453SMichael Ellerman 
3903752e453SMichael Ellerman 		/* To try and hit SIGILL case */
3913752e453SMichael Ellerman 		val  = mfspr(SPRN_MMCRA);
3923752e453SMichael Ellerman 		val |= mfspr(SPRN_MMCR2);
3933752e453SMichael Ellerman 		val |= mfspr(SPRN_MMCR0);
3943752e453SMichael Ellerman 	}
3953752e453SMichael Ellerman 
3963752e453SMichael Ellerman 	ebb_global_disable();
3973752e453SMichael Ellerman 	ebb_freeze_pmcs();
3983752e453SMichael Ellerman 
3993752e453SMichael Ellerman 	dump_ebb_state();
4003752e453SMichael Ellerman 
4013752e453SMichael Ellerman 	event_close(&event);
4023752e453SMichael Ellerman 
4033752e453SMichael Ellerman 	FAIL_IF(ebb_state.stats.ebb_count == 0);
4043752e453SMichael Ellerman 
4053752e453SMichael Ellerman 	return 0;
4063752e453SMichael Ellerman }
4073752e453SMichael Ellerman 
4083752e453SMichael Ellerman static jmp_buf setjmp_env;
4093752e453SMichael Ellerman 
sigill_handler(int signal)4103752e453SMichael Ellerman static void sigill_handler(int signal)
4113752e453SMichael Ellerman {
4123752e453SMichael Ellerman 	printf("Took sigill\n");
4133752e453SMichael Ellerman 	longjmp(setjmp_env, 1);
4143752e453SMichael Ellerman }
4153752e453SMichael Ellerman 
4163752e453SMichael Ellerman static struct sigaction sigill_action = {
4173752e453SMichael Ellerman 	.sa_handler = sigill_handler,
4183752e453SMichael Ellerman };
4193752e453SMichael Ellerman 
catch_sigill(void (* func)(void))4203752e453SMichael Ellerman int catch_sigill(void (*func)(void))
4213752e453SMichael Ellerman {
4223752e453SMichael Ellerman 	if (sigaction(SIGILL, &sigill_action, NULL)) {
4233752e453SMichael Ellerman 		perror("sigaction");
4243752e453SMichael Ellerman 		return 1;
4253752e453SMichael Ellerman 	}
4263752e453SMichael Ellerman 
4273752e453SMichael Ellerman 	if (setjmp(setjmp_env) == 0) {
4283752e453SMichael Ellerman 		func();
4293752e453SMichael Ellerman 		return 1;
4303752e453SMichael Ellerman 	}
4313752e453SMichael Ellerman 
4323752e453SMichael Ellerman 	return 0;
4333752e453SMichael Ellerman }
4343752e453SMichael Ellerman 
write_pmc1(void)4353752e453SMichael Ellerman void write_pmc1(void)
4363752e453SMichael Ellerman {
4373752e453SMichael Ellerman 	mtspr(SPRN_PMC1, 0);
4383752e453SMichael Ellerman }
4393752e453SMichael Ellerman 
write_pmc(int pmc,u64 value)4403752e453SMichael Ellerman void write_pmc(int pmc, u64 value)
4413752e453SMichael Ellerman {
4423752e453SMichael Ellerman 	switch (pmc) {
4433752e453SMichael Ellerman 		case 1: mtspr(SPRN_PMC1, value); break;
4443752e453SMichael Ellerman 		case 2: mtspr(SPRN_PMC2, value); break;
4453752e453SMichael Ellerman 		case 3: mtspr(SPRN_PMC3, value); break;
4463752e453SMichael Ellerman 		case 4: mtspr(SPRN_PMC4, value); break;
4473752e453SMichael Ellerman 		case 5: mtspr(SPRN_PMC5, value); break;
4483752e453SMichael Ellerman 		case 6: mtspr(SPRN_PMC6, value); break;
4493752e453SMichael Ellerman 	}
4503752e453SMichael Ellerman }
4513752e453SMichael Ellerman 
read_pmc(int pmc)4523752e453SMichael Ellerman u64 read_pmc(int pmc)
4533752e453SMichael Ellerman {
4543752e453SMichael Ellerman 	switch (pmc) {
4553752e453SMichael Ellerman 		case 1: return mfspr(SPRN_PMC1);
4563752e453SMichael Ellerman 		case 2: return mfspr(SPRN_PMC2);
4573752e453SMichael Ellerman 		case 3: return mfspr(SPRN_PMC3);
4583752e453SMichael Ellerman 		case 4: return mfspr(SPRN_PMC4);
4593752e453SMichael Ellerman 		case 5: return mfspr(SPRN_PMC5);
4603752e453SMichael Ellerman 		case 6: return mfspr(SPRN_PMC6);
4613752e453SMichael Ellerman 	}
4623752e453SMichael Ellerman 
4633752e453SMichael Ellerman 	return 0;
4643752e453SMichael Ellerman }
4653752e453SMichael Ellerman 
term_handler(int signal)4663752e453SMichael Ellerman static void term_handler(int signal)
4673752e453SMichael Ellerman {
4683752e453SMichael Ellerman 	dump_summary_ebb_state();
4693752e453SMichael Ellerman 	dump_ebb_hw_state();
4703752e453SMichael Ellerman 	abort();
4713752e453SMichael Ellerman }
4723752e453SMichael Ellerman 
4733752e453SMichael Ellerman struct sigaction term_action = {
4743752e453SMichael Ellerman 	.sa_handler = term_handler,
4753752e453SMichael Ellerman };
4763752e453SMichael Ellerman 
ebb_init(void)4773752e453SMichael Ellerman static void __attribute__((constructor)) ebb_init(void)
4783752e453SMichael Ellerman {
4793752e453SMichael Ellerman 	clear_ebb_stats();
4803752e453SMichael Ellerman 
4813752e453SMichael Ellerman 	if (sigaction(SIGTERM, &term_action, NULL))
4823752e453SMichael Ellerman 		perror("sigaction");
4833752e453SMichael Ellerman 
4843752e453SMichael Ellerman 	ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024);
4853752e453SMichael Ellerman }
486