| 
									
										
										
										
											2014-06-10 22:23:10 +10:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright 2014, Michael Ellerman, IBM Corp. | 
					
						
							|  |  |  |  * Licensed under GPLv2. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define _GNU_SOURCE	/* For CPU_ZERO etc. */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sched.h>
 | 
					
						
							|  |  |  | #include <sys/wait.h>
 | 
					
						
							|  |  |  | #include <setjmp.h>
 | 
					
						
							|  |  |  | #include <signal.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <sys/ioctl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "trace.h"
 | 
					
						
							|  |  |  | #include "reg.h"
 | 
					
						
							|  |  |  | #include "ebb.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void (*ebb_user_func)(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ebb_hook(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (ebb_user_func) | 
					
						
							|  |  |  | 		ebb_user_func(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ebb_state ebb_state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u64 sample_period = 0x40000000ull; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */ | 
					
						
							|  |  |  | 	/* 3) set MMCR0[PMAE]	- docs say BESCR[PME] should do this */ | 
					
						
							|  |  |  | 	val = mfspr(SPRN_MMCR0); | 
					
						
							|  |  |  | 	mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 4) clear BESCR[PMEO] */ | 
					
						
							|  |  |  | 	mtspr(SPRN_BESCRR, BESCR_PMEO); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 5) set BESCR[PME] */ | 
					
						
							|  |  |  | 	mtspr(SPRN_BESCRS, BESCR_PME); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 6) rfebb 1 - done in our caller */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void reset_ebb(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Called outside of the EBB handler to check MMCR0 is sane */ | 
					
						
							|  |  |  | int ebb_check_mmcr0(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = mfspr(SPRN_MMCR0); | 
					
						
							|  |  |  | 	if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) { | 
					
						
							|  |  |  | 		/* It's OK if we see FC & PMAO, but not FC by itself */ | 
					
						
							|  |  |  | 		printf("Outside of loop, only FC set 0x%llx\n", val); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ebb_check_count(int pmc, u64 sample_period, int fudge) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 count, upper, lower; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lower = ebb_state.stats.ebb_count * (sample_period - fudge); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (count < lower) { | 
					
						
							|  |  |  | 		printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n", | 
					
						
							|  |  |  | 			pmc, count, lower, lower - count); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	upper = ebb_state.stats.ebb_count * (sample_period + fudge); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (count > upper) { | 
					
						
							|  |  |  | 		printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n", | 
					
						
							|  |  |  | 			pmc, count, upper, count - upper); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n", | 
					
						
							|  |  |  | 		pmc, count, lower, upper, count - lower, upper - count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void standard_ebb_callee(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int found, i; | 
					
						
							|  |  |  | 	u64 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = mfspr(SPRN_BESCR); | 
					
						
							|  |  |  | 	if (!(val & BESCR_PMEO)) { | 
					
						
							|  |  |  | 		ebb_state.stats.spurious++; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ebb_state.stats.ebb_count++; | 
					
						
							|  |  |  | 	trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = mfspr(SPRN_MMCR0); | 
					
						
							|  |  |  | 	trace_log_reg(ebb_state.trace, SPRN_MMCR0, val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	found = 0; | 
					
						
							|  |  |  | 	for (i = 1; i <= 6; i++) { | 
					
						
							|  |  |  | 		if (ebb_state.pmc_enable[PMC_INDEX(i)]) | 
					
						
							|  |  |  | 			found += count_pmc(i, sample_period); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!found) | 
					
						
							|  |  |  | 		ebb_state.stats.no_overflow++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	reset_ebb(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern void ebb_handler(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void setup_ebb_handler(void (*callee)(void)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 entry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(_CALL_ELF) && _CALL_ELF == 2
 | 
					
						
							|  |  |  | 	entry = (u64)ebb_handler; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	struct opd | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    u64 entry; | 
					
						
							|  |  |  | 	    u64 toc; | 
					
						
							|  |  |  | 	} *opd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	opd = (struct opd *)ebb_handler; | 
					
						
							|  |  |  | 	entry = opd->entry; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	printf("EBB Handler is at %#llx\n", entry); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ebb_user_func = callee; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Ensure ebb_user_func is set before we set the handler */ | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 	mtspr(SPRN_EBBHR, entry); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure the handler is set before we return */ | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void clear_ebb_stats(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	memset(&ebb_state.stats, 0, sizeof(ebb_state.stats)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dump_summary_ebb_state(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	printf("ebb_state:\n"			\ | 
					
						
							|  |  |  | 	       "  ebb_count    = %d\n"		\ | 
					
						
							|  |  |  | 	       "  spurious     = %d\n"		\ | 
					
						
							|  |  |  | 	       "  negative     = %d\n"		\ | 
					
						
							|  |  |  | 	       "  no_overflow  = %d\n"		\ | 
					
						
							|  |  |  | 	       "  pmc[1] count = 0x%llx\n"	\ | 
					
						
							|  |  |  | 	       "  pmc[2] count = 0x%llx\n"	\ | 
					
						
							|  |  |  | 	       "  pmc[3] count = 0x%llx\n"	\ | 
					
						
							|  |  |  | 	       "  pmc[4] count = 0x%llx\n"	\ | 
					
						
							|  |  |  | 	       "  pmc[5] count = 0x%llx\n"	\ | 
					
						
							|  |  |  | 	       "  pmc[6] count = 0x%llx\n", | 
					
						
							|  |  |  | 		ebb_state.stats.ebb_count, ebb_state.stats.spurious, | 
					
						
							|  |  |  | 		ebb_state.stats.negative, ebb_state.stats.no_overflow, | 
					
						
							|  |  |  | 		ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1], | 
					
						
							|  |  |  | 		ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3], | 
					
						
							|  |  |  | 		ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char *decode_mmcr0(u32 value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static char buf[16]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf[0] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (value & (1 << 31)) | 
					
						
							|  |  |  | 		strcat(buf, "FC "); | 
					
						
							|  |  |  | 	if (value & (1 << 26)) | 
					
						
							|  |  |  | 		strcat(buf, "PMAE "); | 
					
						
							|  |  |  | 	if (value & (1 << 7)) | 
					
						
							|  |  |  | 		strcat(buf, "PMAO "); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char *decode_bescr(u64 value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static char buf[16]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf[0] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (value & (1ull << 63)) | 
					
						
							|  |  |  | 		strcat(buf, "GE "); | 
					
						
							|  |  |  | 	if (value & (1ull << 32)) | 
					
						
							|  |  |  | 		strcat(buf, "PMAE "); | 
					
						
							|  |  |  | 	if (value & 1) | 
					
						
							|  |  |  | 		strcat(buf, "PMAO "); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dump_ebb_hw_state(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 bescr; | 
					
						
							|  |  |  | 	u32 mmcr0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mmcr0 = mfspr(SPRN_MMCR0); | 
					
						
							|  |  |  | 	bescr = mfspr(SPRN_BESCR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printf("HW state:\n"		\ | 
					
						
							|  |  |  | 	       "MMCR0 0x%016x %s\n"	\ | 
					
						
							| 
									
										
										
										
											2014-07-23 17:31:37 +10:00
										 |  |  | 	       "MMCR2 0x%016lx\n"	\ | 
					
						
							| 
									
										
										
										
											2014-06-10 22:23:10 +10:00
										 |  |  | 	       "EBBHR 0x%016lx\n"	\ | 
					
						
							|  |  |  | 	       "BESCR 0x%016llx %s\n"	\ | 
					
						
							|  |  |  | 	       "PMC1  0x%016lx\n"	\ | 
					
						
							|  |  |  | 	       "PMC2  0x%016lx\n"	\ | 
					
						
							|  |  |  | 	       "PMC3  0x%016lx\n"	\ | 
					
						
							|  |  |  | 	       "PMC4  0x%016lx\n"	\ | 
					
						
							|  |  |  | 	       "PMC5  0x%016lx\n"	\ | 
					
						
							|  |  |  | 	       "PMC6  0x%016lx\n"	\ | 
					
						
							|  |  |  | 	       "SIAR  0x%016lx\n", | 
					
						
							| 
									
										
										
										
											2014-07-23 17:31:37 +10:00
										 |  |  | 	       mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2), | 
					
						
							|  |  |  | 	       mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr), | 
					
						
							|  |  |  | 	       mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3), | 
					
						
							|  |  |  | 	       mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6), | 
					
						
							|  |  |  | 	       mfspr(SPRN_SIAR)); | 
					
						
							| 
									
										
										
										
											2014-06-10 22:23:10 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dump_ebb_state(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dump_summary_ebb_state(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dump_ebb_hw_state(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	trace_buffer_print(ebb_state.trace); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int count_pmc(int pmc, uint32_t sample_period) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t start_value; | 
					
						
							|  |  |  | 	u64 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 0) Read PMC */ | 
					
						
							|  |  |  | 	start_value = pmc_sample_period(sample_period); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = read_pmc(pmc); | 
					
						
							|  |  |  | 	if (val < start_value) | 
					
						
							|  |  |  | 		ebb_state.stats.negative++; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 1) Reset PMC */ | 
					
						
							|  |  |  | 	write_pmc(pmc, start_value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Report if we overflowed */ | 
					
						
							|  |  |  | 	return val >= COUNTER_OVERFLOW; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ebb_event_enable(struct event *e) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Ensure any SPR writes are ordered vs us */ | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE); | 
					
						
							|  |  |  | 	if (rc) | 
					
						
							|  |  |  | 		return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = event_read(e); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Ditto */ | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ebb_freeze_pmcs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ebb_unfreeze_pmcs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Unfreeze counters */ | 
					
						
							|  |  |  | 	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ebb_global_enable(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Enable EBBs globally and PMU EBBs */ | 
					
						
							|  |  |  | 	mtspr(SPRN_BESCR, 0x8000000100000000ull); | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ebb_global_disable(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Disable EBBs & freeze counters, events are still scheduled */ | 
					
						
							|  |  |  | 	mtspr(SPRN_BESCRR, BESCR_PME); | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void event_ebb_init(struct event *e) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	e->attr.config |= (1ull << 63); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void event_bhrb_init(struct event *e, unsigned ifm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	e->attr.config |= (1ull << 62) | ((u64)ifm << 60); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void event_leader_ebb_init(struct event *e) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	event_ebb_init(e); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	e->attr.exclusive = 1; | 
					
						
							|  |  |  | 	e->attr.pinned = 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ebb_child(union pipe read_pipe, union pipe write_pipe) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct event event; | 
					
						
							|  |  |  | 	uint64_t val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FAIL_IF(wait_for_parent(read_pipe)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	event_init_named(&event, 0x1001e, "cycles"); | 
					
						
							|  |  |  | 	event_leader_ebb_init(&event); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	event.attr.exclude_kernel = 1; | 
					
						
							|  |  |  | 	event.attr.exclude_hv = 1; | 
					
						
							|  |  |  | 	event.attr.exclude_idle = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FAIL_IF(event_open(&event)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ebb_enable_pmc_counting(1); | 
					
						
							|  |  |  | 	setup_ebb_handler(standard_ebb_callee); | 
					
						
							|  |  |  | 	ebb_global_enable(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FAIL_IF(event_enable(&event)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (event_read(&event)) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Some tests expect to fail here, so don't report an error on | 
					
						
							|  |  |  | 		 * this line, and return a distinguisable error code. Tell the | 
					
						
							|  |  |  | 		 * parent an error happened. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		notify_parent_of_error(write_pipe); | 
					
						
							|  |  |  | 		return 2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FAIL_IF(notify_parent(write_pipe)); | 
					
						
							|  |  |  | 	FAIL_IF(wait_for_parent(read_pipe)); | 
					
						
							|  |  |  | 	FAIL_IF(notify_parent(write_pipe)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (ebb_state.stats.ebb_count < 20) { | 
					
						
							|  |  |  | 		FAIL_IF(core_busy_loop()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* To try and hit SIGILL case */ | 
					
						
							|  |  |  | 		val  = mfspr(SPRN_MMCRA); | 
					
						
							|  |  |  | 		val |= mfspr(SPRN_MMCR2); | 
					
						
							|  |  |  | 		val |= mfspr(SPRN_MMCR0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ebb_global_disable(); | 
					
						
							|  |  |  | 	ebb_freeze_pmcs(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	count_pmc(1, sample_period); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dump_ebb_state(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	event_close(&event); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FAIL_IF(ebb_state.stats.ebb_count == 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static jmp_buf setjmp_env; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void sigill_handler(int signal) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	printf("Took sigill\n"); | 
					
						
							|  |  |  | 	longjmp(setjmp_env, 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct sigaction sigill_action = { | 
					
						
							|  |  |  | 	.sa_handler = sigill_handler, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int catch_sigill(void (*func)(void)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (sigaction(SIGILL, &sigill_action, NULL)) { | 
					
						
							|  |  |  | 		perror("sigaction"); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (setjmp(setjmp_env) == 0) { | 
					
						
							|  |  |  | 		func(); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void write_pmc1(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	mtspr(SPRN_PMC1, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void write_pmc(int pmc, u64 value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (pmc) { | 
					
						
							|  |  |  | 		case 1: mtspr(SPRN_PMC1, value); break; | 
					
						
							|  |  |  | 		case 2: mtspr(SPRN_PMC2, value); break; | 
					
						
							|  |  |  | 		case 3: mtspr(SPRN_PMC3, value); break; | 
					
						
							|  |  |  | 		case 4: mtspr(SPRN_PMC4, value); break; | 
					
						
							|  |  |  | 		case 5: mtspr(SPRN_PMC5, value); break; | 
					
						
							|  |  |  | 		case 6: mtspr(SPRN_PMC6, value); break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u64 read_pmc(int pmc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (pmc) { | 
					
						
							|  |  |  | 		case 1: return mfspr(SPRN_PMC1); | 
					
						
							|  |  |  | 		case 2: return mfspr(SPRN_PMC2); | 
					
						
							|  |  |  | 		case 3: return mfspr(SPRN_PMC3); | 
					
						
							|  |  |  | 		case 4: return mfspr(SPRN_PMC4); | 
					
						
							|  |  |  | 		case 5: return mfspr(SPRN_PMC5); | 
					
						
							|  |  |  | 		case 6: return mfspr(SPRN_PMC6); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void term_handler(int signal) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dump_summary_ebb_state(); | 
					
						
							|  |  |  | 	dump_ebb_hw_state(); | 
					
						
							|  |  |  | 	abort(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct sigaction term_action = { | 
					
						
							|  |  |  | 	.sa_handler = term_handler, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __attribute__((constructor)) ebb_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	clear_ebb_stats(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sigaction(SIGTERM, &term_action, NULL)) | 
					
						
							|  |  |  | 		perror("sigaction"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024); | 
					
						
							|  |  |  | } |