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