162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2014, Michael Ellerman, IBM Corp.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define _GNU_SOURCE	/* For CPU_ZERO etc. */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <sched.h>
962306a36Sopenharmony_ci#include <sys/wait.h>
1062306a36Sopenharmony_ci#include <setjmp.h>
1162306a36Sopenharmony_ci#include <signal.h>
1262306a36Sopenharmony_ci#include <stdio.h>
1362306a36Sopenharmony_ci#include <stdlib.h>
1462306a36Sopenharmony_ci#include <string.h>
1562306a36Sopenharmony_ci#include <sys/ioctl.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "trace.h"
1862306a36Sopenharmony_ci#include "ebb.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_civoid (*ebb_user_func)(void);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_civoid ebb_hook(void)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	if (ebb_user_func)
2662306a36Sopenharmony_ci		ebb_user_func();
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistruct ebb_state ebb_state;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciu64 sample_period = 0x40000000ull;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_civoid reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	u64 val;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	/* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */
3862306a36Sopenharmony_ci	/* 3) set MMCR0[PMAE]	- docs say BESCR[PME] should do this */
3962306a36Sopenharmony_ci	val = mfspr(SPRN_MMCR0);
4062306a36Sopenharmony_ci	mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	/* 4) clear BESCR[PMEO] */
4362306a36Sopenharmony_ci	mtspr(SPRN_BESCRR, BESCR_PMEO);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* 5) set BESCR[PME] */
4662306a36Sopenharmony_ci	mtspr(SPRN_BESCRS, BESCR_PME);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	/* 6) rfebb 1 - done in our caller */
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_civoid reset_ebb(void)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Called outside of the EBB handler to check MMCR0 is sane */
5762306a36Sopenharmony_ciint ebb_check_mmcr0(void)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	u64 val;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	val = mfspr(SPRN_MMCR0);
6262306a36Sopenharmony_ci	if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) {
6362306a36Sopenharmony_ci		/* It's OK if we see FC & PMAO, but not FC by itself */
6462306a36Sopenharmony_ci		printf("Outside of loop, only FC set 0x%llx\n", val);
6562306a36Sopenharmony_ci		return 1;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cibool ebb_check_count(int pmc, u64 sample_period, int fudge)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	u64 count, upper, lower;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)];
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	lower = ebb_state.stats.ebb_count * (sample_period - fudge);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (count < lower) {
8062306a36Sopenharmony_ci		printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n",
8162306a36Sopenharmony_ci			pmc, count, lower, lower - count);
8262306a36Sopenharmony_ci		return false;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	upper = ebb_state.stats.ebb_count * (sample_period + fudge);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (count > upper) {
8862306a36Sopenharmony_ci		printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n",
8962306a36Sopenharmony_ci			pmc, count, upper, count - upper);
9062306a36Sopenharmony_ci		return false;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n",
9462306a36Sopenharmony_ci		pmc, count, lower, upper, count - lower, upper - count);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return true;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_civoid standard_ebb_callee(void)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	int found, i;
10262306a36Sopenharmony_ci	u64 val;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	val = mfspr(SPRN_BESCR);
10562306a36Sopenharmony_ci	if (!(val & BESCR_PMEO)) {
10662306a36Sopenharmony_ci		ebb_state.stats.spurious++;
10762306a36Sopenharmony_ci		goto out;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ebb_state.stats.ebb_count++;
11162306a36Sopenharmony_ci	trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	val = mfspr(SPRN_MMCR0);
11462306a36Sopenharmony_ci	trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	found = 0;
11762306a36Sopenharmony_ci	for (i = 1; i <= 6; i++) {
11862306a36Sopenharmony_ci		if (ebb_state.pmc_enable[PMC_INDEX(i)])
11962306a36Sopenharmony_ci			found += count_pmc(i, sample_period);
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	if (!found)
12362306a36Sopenharmony_ci		ebb_state.stats.no_overflow++;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciout:
12662306a36Sopenharmony_ci	reset_ebb();
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciextern void ebb_handler(void);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_civoid setup_ebb_handler(void (*callee)(void))
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	u64 entry;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#if defined(_CALL_ELF) && _CALL_ELF == 2
13662306a36Sopenharmony_ci	entry = (u64)ebb_handler;
13762306a36Sopenharmony_ci#else
13862306a36Sopenharmony_ci	struct opd
13962306a36Sopenharmony_ci	{
14062306a36Sopenharmony_ci	    u64 entry;
14162306a36Sopenharmony_ci	    u64 toc;
14262306a36Sopenharmony_ci	} *opd;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	opd = (struct opd *)ebb_handler;
14562306a36Sopenharmony_ci	entry = opd->entry;
14662306a36Sopenharmony_ci#endif
14762306a36Sopenharmony_ci	printf("EBB Handler is at %#llx\n", entry);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	ebb_user_func = callee;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* Ensure ebb_user_func is set before we set the handler */
15262306a36Sopenharmony_ci	mb();
15362306a36Sopenharmony_ci	mtspr(SPRN_EBBHR, entry);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* Make sure the handler is set before we return */
15662306a36Sopenharmony_ci	mb();
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_civoid clear_ebb_stats(void)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	memset(&ebb_state.stats, 0, sizeof(ebb_state.stats));
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_civoid dump_summary_ebb_state(void)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	printf("ebb_state:\n"			\
16762306a36Sopenharmony_ci	       "  ebb_count    = %d\n"		\
16862306a36Sopenharmony_ci	       "  spurious     = %d\n"		\
16962306a36Sopenharmony_ci	       "  negative     = %d\n"		\
17062306a36Sopenharmony_ci	       "  no_overflow  = %d\n"		\
17162306a36Sopenharmony_ci	       "  pmc[1] count = 0x%llx\n"	\
17262306a36Sopenharmony_ci	       "  pmc[2] count = 0x%llx\n"	\
17362306a36Sopenharmony_ci	       "  pmc[3] count = 0x%llx\n"	\
17462306a36Sopenharmony_ci	       "  pmc[4] count = 0x%llx\n"	\
17562306a36Sopenharmony_ci	       "  pmc[5] count = 0x%llx\n"	\
17662306a36Sopenharmony_ci	       "  pmc[6] count = 0x%llx\n",
17762306a36Sopenharmony_ci		ebb_state.stats.ebb_count, ebb_state.stats.spurious,
17862306a36Sopenharmony_ci		ebb_state.stats.negative, ebb_state.stats.no_overflow,
17962306a36Sopenharmony_ci		ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1],
18062306a36Sopenharmony_ci		ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3],
18162306a36Sopenharmony_ci		ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic char *decode_mmcr0(u32 value)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	static char buf[16];
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	buf[0] = '\0';
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (value & (1 << 31))
19162306a36Sopenharmony_ci		strcat(buf, "FC ");
19262306a36Sopenharmony_ci	if (value & (1 << 26))
19362306a36Sopenharmony_ci		strcat(buf, "PMAE ");
19462306a36Sopenharmony_ci	if (value & (1 << 7))
19562306a36Sopenharmony_ci		strcat(buf, "PMAO ");
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return buf;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic char *decode_bescr(u64 value)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	static char buf[16];
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	buf[0] = '\0';
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (value & (1ull << 63))
20762306a36Sopenharmony_ci		strcat(buf, "GE ");
20862306a36Sopenharmony_ci	if (value & (1ull << 32))
20962306a36Sopenharmony_ci		strcat(buf, "PMAE ");
21062306a36Sopenharmony_ci	if (value & 1)
21162306a36Sopenharmony_ci		strcat(buf, "PMAO ");
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return buf;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_civoid dump_ebb_hw_state(void)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	u64 bescr;
21962306a36Sopenharmony_ci	u32 mmcr0;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	mmcr0 = mfspr(SPRN_MMCR0);
22262306a36Sopenharmony_ci	bescr = mfspr(SPRN_BESCR);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	printf("HW state:\n"		\
22562306a36Sopenharmony_ci	       "MMCR0 0x%016x %s\n"	\
22662306a36Sopenharmony_ci	       "MMCR2 0x%016lx\n"	\
22762306a36Sopenharmony_ci	       "EBBHR 0x%016lx\n"	\
22862306a36Sopenharmony_ci	       "BESCR 0x%016llx %s\n"	\
22962306a36Sopenharmony_ci	       "PMC1  0x%016lx\n"	\
23062306a36Sopenharmony_ci	       "PMC2  0x%016lx\n"	\
23162306a36Sopenharmony_ci	       "PMC3  0x%016lx\n"	\
23262306a36Sopenharmony_ci	       "PMC4  0x%016lx\n"	\
23362306a36Sopenharmony_ci	       "PMC5  0x%016lx\n"	\
23462306a36Sopenharmony_ci	       "PMC6  0x%016lx\n"	\
23562306a36Sopenharmony_ci	       "SIAR  0x%016lx\n",
23662306a36Sopenharmony_ci	       mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2),
23762306a36Sopenharmony_ci	       mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr),
23862306a36Sopenharmony_ci	       mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3),
23962306a36Sopenharmony_ci	       mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6),
24062306a36Sopenharmony_ci	       mfspr(SPRN_SIAR));
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_civoid dump_ebb_state(void)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	dump_summary_ebb_state();
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	dump_ebb_hw_state();
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	trace_buffer_print(ebb_state.trace);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ciint count_pmc(int pmc, uint32_t sample_period)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	uint32_t start_value;
25562306a36Sopenharmony_ci	u64 val;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* 0) Read PMC */
25862306a36Sopenharmony_ci	start_value = pmc_sample_period(sample_period);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	val = read_pmc(pmc);
26162306a36Sopenharmony_ci	if (val < start_value)
26262306a36Sopenharmony_ci		ebb_state.stats.negative++;
26362306a36Sopenharmony_ci	else
26462306a36Sopenharmony_ci		ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* 1) Reset PMC */
26962306a36Sopenharmony_ci	write_pmc(pmc, start_value);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Report if we overflowed */
27262306a36Sopenharmony_ci	return val >= COUNTER_OVERFLOW;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ciint ebb_event_enable(struct event *e)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	int rc;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Ensure any SPR writes are ordered vs us */
28062306a36Sopenharmony_ci	mb();
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
28362306a36Sopenharmony_ci	if (rc)
28462306a36Sopenharmony_ci		return rc;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	rc = event_read(e);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* Ditto */
28962306a36Sopenharmony_ci	mb();
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return rc;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_civoid ebb_freeze_pmcs(void)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
29762306a36Sopenharmony_ci	mb();
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_civoid ebb_unfreeze_pmcs(void)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	/* Unfreeze counters */
30362306a36Sopenharmony_ci	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
30462306a36Sopenharmony_ci	mb();
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_civoid ebb_global_enable(void)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	/* Enable EBBs globally and PMU EBBs */
31062306a36Sopenharmony_ci	mtspr(SPRN_BESCR, 0x8000000100000000ull);
31162306a36Sopenharmony_ci	mb();
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_civoid ebb_global_disable(void)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	/* Disable EBBs & freeze counters, events are still scheduled */
31762306a36Sopenharmony_ci	mtspr(SPRN_BESCRR, BESCR_PME);
31862306a36Sopenharmony_ci	mb();
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cibool ebb_is_supported(void)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci#ifdef PPC_FEATURE2_EBB
32462306a36Sopenharmony_ci	/* EBB requires at least POWER8 */
32562306a36Sopenharmony_ci	return have_hwcap2(PPC_FEATURE2_EBB);
32662306a36Sopenharmony_ci#else
32762306a36Sopenharmony_ci	return false;
32862306a36Sopenharmony_ci#endif
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_civoid event_ebb_init(struct event *e)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	e->attr.config |= (1ull << 63);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_civoid event_bhrb_init(struct event *e, unsigned ifm)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	e->attr.config |= (1ull << 62) | ((u64)ifm << 60);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_civoid event_leader_ebb_init(struct event *e)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	event_ebb_init(e);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	e->attr.exclusive = 1;
34662306a36Sopenharmony_ci	e->attr.pinned = 1;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ciint ebb_child(union pipe read_pipe, union pipe write_pipe)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct event event;
35262306a36Sopenharmony_ci	uint64_t val;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	FAIL_IF(wait_for_parent(read_pipe));
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	event_init_named(&event, 0x1001e, "cycles");
35762306a36Sopenharmony_ci	event_leader_ebb_init(&event);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	event.attr.exclude_kernel = 1;
36062306a36Sopenharmony_ci	event.attr.exclude_hv = 1;
36162306a36Sopenharmony_ci	event.attr.exclude_idle = 1;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	FAIL_IF(event_open(&event));
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	ebb_enable_pmc_counting(1);
36662306a36Sopenharmony_ci	setup_ebb_handler(standard_ebb_callee);
36762306a36Sopenharmony_ci	ebb_global_enable();
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	FAIL_IF(event_enable(&event));
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (event_read(&event)) {
37262306a36Sopenharmony_ci		/*
37362306a36Sopenharmony_ci		 * Some tests expect to fail here, so don't report an error on
37462306a36Sopenharmony_ci		 * this line, and return a distinguisable error code. Tell the
37562306a36Sopenharmony_ci		 * parent an error happened.
37662306a36Sopenharmony_ci		 */
37762306a36Sopenharmony_ci		notify_parent_of_error(write_pipe);
37862306a36Sopenharmony_ci		return 2;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	FAIL_IF(notify_parent(write_pipe));
38462306a36Sopenharmony_ci	FAIL_IF(wait_for_parent(read_pipe));
38562306a36Sopenharmony_ci	FAIL_IF(notify_parent(write_pipe));
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	while (ebb_state.stats.ebb_count < 20) {
38862306a36Sopenharmony_ci		FAIL_IF(core_busy_loop());
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		/* To try and hit SIGILL case */
39162306a36Sopenharmony_ci		val  = mfspr(SPRN_MMCRA);
39262306a36Sopenharmony_ci		val |= mfspr(SPRN_MMCR2);
39362306a36Sopenharmony_ci		val |= mfspr(SPRN_MMCR0);
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ebb_global_disable();
39762306a36Sopenharmony_ci	ebb_freeze_pmcs();
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	dump_ebb_state();
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	event_close(&event);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	FAIL_IF(ebb_state.stats.ebb_count == 0);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return 0;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic jmp_buf setjmp_env;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic void sigill_handler(int signal)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	printf("Took sigill\n");
41362306a36Sopenharmony_ci	longjmp(setjmp_env, 1);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic struct sigaction sigill_action = {
41762306a36Sopenharmony_ci	.sa_handler = sigill_handler,
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ciint catch_sigill(void (*func)(void))
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	if (sigaction(SIGILL, &sigill_action, NULL)) {
42362306a36Sopenharmony_ci		perror("sigaction");
42462306a36Sopenharmony_ci		return 1;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (setjmp(setjmp_env) == 0) {
42862306a36Sopenharmony_ci		func();
42962306a36Sopenharmony_ci		return 1;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return 0;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_civoid write_pmc1(void)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	mtspr(SPRN_PMC1, 0);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_civoid write_pmc(int pmc, u64 value)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	switch (pmc) {
44362306a36Sopenharmony_ci		case 1: mtspr(SPRN_PMC1, value); break;
44462306a36Sopenharmony_ci		case 2: mtspr(SPRN_PMC2, value); break;
44562306a36Sopenharmony_ci		case 3: mtspr(SPRN_PMC3, value); break;
44662306a36Sopenharmony_ci		case 4: mtspr(SPRN_PMC4, value); break;
44762306a36Sopenharmony_ci		case 5: mtspr(SPRN_PMC5, value); break;
44862306a36Sopenharmony_ci		case 6: mtspr(SPRN_PMC6, value); break;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciu64 read_pmc(int pmc)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	switch (pmc) {
45562306a36Sopenharmony_ci		case 1: return mfspr(SPRN_PMC1);
45662306a36Sopenharmony_ci		case 2: return mfspr(SPRN_PMC2);
45762306a36Sopenharmony_ci		case 3: return mfspr(SPRN_PMC3);
45862306a36Sopenharmony_ci		case 4: return mfspr(SPRN_PMC4);
45962306a36Sopenharmony_ci		case 5: return mfspr(SPRN_PMC5);
46062306a36Sopenharmony_ci		case 6: return mfspr(SPRN_PMC6);
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return 0;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic void term_handler(int signal)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	dump_summary_ebb_state();
46962306a36Sopenharmony_ci	dump_ebb_hw_state();
47062306a36Sopenharmony_ci	abort();
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistruct sigaction term_action = {
47462306a36Sopenharmony_ci	.sa_handler = term_handler,
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic void __attribute__((constructor)) ebb_init(void)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	clear_ebb_stats();
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (sigaction(SIGTERM, &term_action, NULL))
48262306a36Sopenharmony_ci		perror("sigaction");
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024);
48562306a36Sopenharmony_ci}
486