18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2014, Michael Ellerman, IBM Corp. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define _GNU_SOURCE /* For CPU_ZERO etc. */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <sched.h> 98c2ecf20Sopenharmony_ci#include <sys/wait.h> 108c2ecf20Sopenharmony_ci#include <setjmp.h> 118c2ecf20Sopenharmony_ci#include <signal.h> 128c2ecf20Sopenharmony_ci#include <stdio.h> 138c2ecf20Sopenharmony_ci#include <stdlib.h> 148c2ecf20Sopenharmony_ci#include <string.h> 158c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "trace.h" 188c2ecf20Sopenharmony_ci#include "ebb.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_civoid (*ebb_user_func)(void); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_civoid ebb_hook(void) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (ebb_user_func) 268c2ecf20Sopenharmony_ci ebb_user_func(); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct ebb_state ebb_state; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciu64 sample_period = 0x40000000ull; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_civoid reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci u64 val; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci /* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */ 388c2ecf20Sopenharmony_ci /* 3) set MMCR0[PMAE] - docs say BESCR[PME] should do this */ 398c2ecf20Sopenharmony_ci val = mfspr(SPRN_MMCR0); 408c2ecf20Sopenharmony_ci mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* 4) clear BESCR[PMEO] */ 438c2ecf20Sopenharmony_ci mtspr(SPRN_BESCRR, BESCR_PMEO); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* 5) set BESCR[PME] */ 468c2ecf20Sopenharmony_ci mtspr(SPRN_BESCRS, BESCR_PME); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 6) rfebb 1 - done in our caller */ 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_civoid reset_ebb(void) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* Called outside of the EBB handler to check MMCR0 is sane */ 578c2ecf20Sopenharmony_ciint ebb_check_mmcr0(void) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci u64 val; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci val = mfspr(SPRN_MMCR0); 628c2ecf20Sopenharmony_ci if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) { 638c2ecf20Sopenharmony_ci /* It's OK if we see FC & PMAO, but not FC by itself */ 648c2ecf20Sopenharmony_ci printf("Outside of loop, only FC set 0x%llx\n", val); 658c2ecf20Sopenharmony_ci return 1; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cibool ebb_check_count(int pmc, u64 sample_period, int fudge) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci u64 count, upper, lower; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)]; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci lower = ebb_state.stats.ebb_count * (sample_period - fudge); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (count < lower) { 808c2ecf20Sopenharmony_ci printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n", 818c2ecf20Sopenharmony_ci pmc, count, lower, lower - count); 828c2ecf20Sopenharmony_ci return false; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci upper = ebb_state.stats.ebb_count * (sample_period + fudge); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (count > upper) { 888c2ecf20Sopenharmony_ci printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n", 898c2ecf20Sopenharmony_ci pmc, count, upper, count - upper); 908c2ecf20Sopenharmony_ci return false; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n", 948c2ecf20Sopenharmony_ci pmc, count, lower, upper, count - lower, upper - count); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return true; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_civoid standard_ebb_callee(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci int found, i; 1028c2ecf20Sopenharmony_ci u64 val; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci val = mfspr(SPRN_BESCR); 1058c2ecf20Sopenharmony_ci if (!(val & BESCR_PMEO)) { 1068c2ecf20Sopenharmony_ci ebb_state.stats.spurious++; 1078c2ecf20Sopenharmony_ci goto out; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci ebb_state.stats.ebb_count++; 1118c2ecf20Sopenharmony_ci trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci val = mfspr(SPRN_MMCR0); 1148c2ecf20Sopenharmony_ci trace_log_reg(ebb_state.trace, SPRN_MMCR0, val); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci found = 0; 1178c2ecf20Sopenharmony_ci for (i = 1; i <= 6; i++) { 1188c2ecf20Sopenharmony_ci if (ebb_state.pmc_enable[PMC_INDEX(i)]) 1198c2ecf20Sopenharmony_ci found += count_pmc(i, sample_period); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (!found) 1238c2ecf20Sopenharmony_ci ebb_state.stats.no_overflow++; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciout: 1268c2ecf20Sopenharmony_ci reset_ebb(); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciextern void ebb_handler(void); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid setup_ebb_handler(void (*callee)(void)) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci u64 entry; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#if defined(_CALL_ELF) && _CALL_ELF == 2 1368c2ecf20Sopenharmony_ci entry = (u64)ebb_handler; 1378c2ecf20Sopenharmony_ci#else 1388c2ecf20Sopenharmony_ci struct opd 1398c2ecf20Sopenharmony_ci { 1408c2ecf20Sopenharmony_ci u64 entry; 1418c2ecf20Sopenharmony_ci u64 toc; 1428c2ecf20Sopenharmony_ci } *opd; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci opd = (struct opd *)ebb_handler; 1458c2ecf20Sopenharmony_ci entry = opd->entry; 1468c2ecf20Sopenharmony_ci#endif 1478c2ecf20Sopenharmony_ci printf("EBB Handler is at %#llx\n", entry); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ebb_user_func = callee; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Ensure ebb_user_func is set before we set the handler */ 1528c2ecf20Sopenharmony_ci mb(); 1538c2ecf20Sopenharmony_ci mtspr(SPRN_EBBHR, entry); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Make sure the handler is set before we return */ 1568c2ecf20Sopenharmony_ci mb(); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_civoid clear_ebb_stats(void) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci memset(&ebb_state.stats, 0, sizeof(ebb_state.stats)); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_civoid dump_summary_ebb_state(void) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci printf("ebb_state:\n" \ 1678c2ecf20Sopenharmony_ci " ebb_count = %d\n" \ 1688c2ecf20Sopenharmony_ci " spurious = %d\n" \ 1698c2ecf20Sopenharmony_ci " negative = %d\n" \ 1708c2ecf20Sopenharmony_ci " no_overflow = %d\n" \ 1718c2ecf20Sopenharmony_ci " pmc[1] count = 0x%llx\n" \ 1728c2ecf20Sopenharmony_ci " pmc[2] count = 0x%llx\n" \ 1738c2ecf20Sopenharmony_ci " pmc[3] count = 0x%llx\n" \ 1748c2ecf20Sopenharmony_ci " pmc[4] count = 0x%llx\n" \ 1758c2ecf20Sopenharmony_ci " pmc[5] count = 0x%llx\n" \ 1768c2ecf20Sopenharmony_ci " pmc[6] count = 0x%llx\n", 1778c2ecf20Sopenharmony_ci ebb_state.stats.ebb_count, ebb_state.stats.spurious, 1788c2ecf20Sopenharmony_ci ebb_state.stats.negative, ebb_state.stats.no_overflow, 1798c2ecf20Sopenharmony_ci ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1], 1808c2ecf20Sopenharmony_ci ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3], 1818c2ecf20Sopenharmony_ci ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic char *decode_mmcr0(u32 value) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci static char buf[16]; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci buf[0] = '\0'; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (value & (1 << 31)) 1918c2ecf20Sopenharmony_ci strcat(buf, "FC "); 1928c2ecf20Sopenharmony_ci if (value & (1 << 26)) 1938c2ecf20Sopenharmony_ci strcat(buf, "PMAE "); 1948c2ecf20Sopenharmony_ci if (value & (1 << 7)) 1958c2ecf20Sopenharmony_ci strcat(buf, "PMAO "); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return buf; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic char *decode_bescr(u64 value) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci static char buf[16]; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci buf[0] = '\0'; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (value & (1ull << 63)) 2078c2ecf20Sopenharmony_ci strcat(buf, "GE "); 2088c2ecf20Sopenharmony_ci if (value & (1ull << 32)) 2098c2ecf20Sopenharmony_ci strcat(buf, "PMAE "); 2108c2ecf20Sopenharmony_ci if (value & 1) 2118c2ecf20Sopenharmony_ci strcat(buf, "PMAO "); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return buf; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_civoid dump_ebb_hw_state(void) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci u64 bescr; 2198c2ecf20Sopenharmony_ci u32 mmcr0; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci mmcr0 = mfspr(SPRN_MMCR0); 2228c2ecf20Sopenharmony_ci bescr = mfspr(SPRN_BESCR); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci printf("HW state:\n" \ 2258c2ecf20Sopenharmony_ci "MMCR0 0x%016x %s\n" \ 2268c2ecf20Sopenharmony_ci "MMCR2 0x%016lx\n" \ 2278c2ecf20Sopenharmony_ci "EBBHR 0x%016lx\n" \ 2288c2ecf20Sopenharmony_ci "BESCR 0x%016llx %s\n" \ 2298c2ecf20Sopenharmony_ci "PMC1 0x%016lx\n" \ 2308c2ecf20Sopenharmony_ci "PMC2 0x%016lx\n" \ 2318c2ecf20Sopenharmony_ci "PMC3 0x%016lx\n" \ 2328c2ecf20Sopenharmony_ci "PMC4 0x%016lx\n" \ 2338c2ecf20Sopenharmony_ci "PMC5 0x%016lx\n" \ 2348c2ecf20Sopenharmony_ci "PMC6 0x%016lx\n" \ 2358c2ecf20Sopenharmony_ci "SIAR 0x%016lx\n", 2368c2ecf20Sopenharmony_ci mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2), 2378c2ecf20Sopenharmony_ci mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr), 2388c2ecf20Sopenharmony_ci mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3), 2398c2ecf20Sopenharmony_ci mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6), 2408c2ecf20Sopenharmony_ci mfspr(SPRN_SIAR)); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_civoid dump_ebb_state(void) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci dump_summary_ebb_state(); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci dump_ebb_hw_state(); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci trace_buffer_print(ebb_state.trace); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ciint count_pmc(int pmc, uint32_t sample_period) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci uint32_t start_value; 2558c2ecf20Sopenharmony_ci u64 val; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* 0) Read PMC */ 2588c2ecf20Sopenharmony_ci start_value = pmc_sample_period(sample_period); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci val = read_pmc(pmc); 2618c2ecf20Sopenharmony_ci if (val < start_value) 2628c2ecf20Sopenharmony_ci ebb_state.stats.negative++; 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 1) Reset PMC */ 2698c2ecf20Sopenharmony_ci write_pmc(pmc, start_value); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Report if we overflowed */ 2728c2ecf20Sopenharmony_ci return val >= COUNTER_OVERFLOW; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciint ebb_event_enable(struct event *e) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int rc; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Ensure any SPR writes are ordered vs us */ 2808c2ecf20Sopenharmony_ci mb(); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE); 2838c2ecf20Sopenharmony_ci if (rc) 2848c2ecf20Sopenharmony_ci return rc; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci rc = event_read(e); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Ditto */ 2898c2ecf20Sopenharmony_ci mb(); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return rc; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_civoid ebb_freeze_pmcs(void) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); 2978c2ecf20Sopenharmony_ci mb(); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_civoid ebb_unfreeze_pmcs(void) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci /* Unfreeze counters */ 3038c2ecf20Sopenharmony_ci mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); 3048c2ecf20Sopenharmony_ci mb(); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_civoid ebb_global_enable(void) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci /* Enable EBBs globally and PMU EBBs */ 3108c2ecf20Sopenharmony_ci mtspr(SPRN_BESCR, 0x8000000100000000ull); 3118c2ecf20Sopenharmony_ci mb(); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_civoid ebb_global_disable(void) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci /* Disable EBBs & freeze counters, events are still scheduled */ 3178c2ecf20Sopenharmony_ci mtspr(SPRN_BESCRR, BESCR_PME); 3188c2ecf20Sopenharmony_ci mb(); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cibool ebb_is_supported(void) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci#ifdef PPC_FEATURE2_EBB 3248c2ecf20Sopenharmony_ci /* EBB requires at least POWER8 */ 3258c2ecf20Sopenharmony_ci return have_hwcap2(PPC_FEATURE2_EBB); 3268c2ecf20Sopenharmony_ci#else 3278c2ecf20Sopenharmony_ci return false; 3288c2ecf20Sopenharmony_ci#endif 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_civoid event_ebb_init(struct event *e) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci e->attr.config |= (1ull << 63); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_civoid event_bhrb_init(struct event *e, unsigned ifm) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci e->attr.config |= (1ull << 62) | ((u64)ifm << 60); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_civoid event_leader_ebb_init(struct event *e) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci event_ebb_init(e); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci e->attr.exclusive = 1; 3468c2ecf20Sopenharmony_ci e->attr.pinned = 1; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ciint ebb_child(union pipe read_pipe, union pipe write_pipe) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct event event; 3528c2ecf20Sopenharmony_ci uint64_t val; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci FAIL_IF(wait_for_parent(read_pipe)); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci event_init_named(&event, 0x1001e, "cycles"); 3578c2ecf20Sopenharmony_ci event_leader_ebb_init(&event); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci event.attr.exclude_kernel = 1; 3608c2ecf20Sopenharmony_ci event.attr.exclude_hv = 1; 3618c2ecf20Sopenharmony_ci event.attr.exclude_idle = 1; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci FAIL_IF(event_open(&event)); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci ebb_enable_pmc_counting(1); 3668c2ecf20Sopenharmony_ci setup_ebb_handler(standard_ebb_callee); 3678c2ecf20Sopenharmony_ci ebb_global_enable(); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci FAIL_IF(event_enable(&event)); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (event_read(&event)) { 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * Some tests expect to fail here, so don't report an error on 3748c2ecf20Sopenharmony_ci * this line, and return a distinguisable error code. Tell the 3758c2ecf20Sopenharmony_ci * parent an error happened. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci notify_parent_of_error(write_pipe); 3788c2ecf20Sopenharmony_ci return 2; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci FAIL_IF(notify_parent(write_pipe)); 3848c2ecf20Sopenharmony_ci FAIL_IF(wait_for_parent(read_pipe)); 3858c2ecf20Sopenharmony_ci FAIL_IF(notify_parent(write_pipe)); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci while (ebb_state.stats.ebb_count < 20) { 3888c2ecf20Sopenharmony_ci FAIL_IF(core_busy_loop()); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* To try and hit SIGILL case */ 3918c2ecf20Sopenharmony_ci val = mfspr(SPRN_MMCRA); 3928c2ecf20Sopenharmony_ci val |= mfspr(SPRN_MMCR2); 3938c2ecf20Sopenharmony_ci val |= mfspr(SPRN_MMCR0); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ebb_global_disable(); 3978c2ecf20Sopenharmony_ci ebb_freeze_pmcs(); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci dump_ebb_state(); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci event_close(&event); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci FAIL_IF(ebb_state.stats.ebb_count == 0); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic jmp_buf setjmp_env; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic void sigill_handler(int signal) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci printf("Took sigill\n"); 4138c2ecf20Sopenharmony_ci longjmp(setjmp_env, 1); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic struct sigaction sigill_action = { 4178c2ecf20Sopenharmony_ci .sa_handler = sigill_handler, 4188c2ecf20Sopenharmony_ci}; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ciint catch_sigill(void (*func)(void)) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci if (sigaction(SIGILL, &sigill_action, NULL)) { 4238c2ecf20Sopenharmony_ci perror("sigaction"); 4248c2ecf20Sopenharmony_ci return 1; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (setjmp(setjmp_env) == 0) { 4288c2ecf20Sopenharmony_ci func(); 4298c2ecf20Sopenharmony_ci return 1; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_civoid write_pmc1(void) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci mtspr(SPRN_PMC1, 0); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_civoid write_pmc(int pmc, u64 value) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci switch (pmc) { 4438c2ecf20Sopenharmony_ci case 1: mtspr(SPRN_PMC1, value); break; 4448c2ecf20Sopenharmony_ci case 2: mtspr(SPRN_PMC2, value); break; 4458c2ecf20Sopenharmony_ci case 3: mtspr(SPRN_PMC3, value); break; 4468c2ecf20Sopenharmony_ci case 4: mtspr(SPRN_PMC4, value); break; 4478c2ecf20Sopenharmony_ci case 5: mtspr(SPRN_PMC5, value); break; 4488c2ecf20Sopenharmony_ci case 6: mtspr(SPRN_PMC6, value); break; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ciu64 read_pmc(int pmc) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci switch (pmc) { 4558c2ecf20Sopenharmony_ci case 1: return mfspr(SPRN_PMC1); 4568c2ecf20Sopenharmony_ci case 2: return mfspr(SPRN_PMC2); 4578c2ecf20Sopenharmony_ci case 3: return mfspr(SPRN_PMC3); 4588c2ecf20Sopenharmony_ci case 4: return mfspr(SPRN_PMC4); 4598c2ecf20Sopenharmony_ci case 5: return mfspr(SPRN_PMC5); 4608c2ecf20Sopenharmony_ci case 6: return mfspr(SPRN_PMC6); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic void term_handler(int signal) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci dump_summary_ebb_state(); 4698c2ecf20Sopenharmony_ci dump_ebb_hw_state(); 4708c2ecf20Sopenharmony_ci abort(); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistruct sigaction term_action = { 4748c2ecf20Sopenharmony_ci .sa_handler = term_handler, 4758c2ecf20Sopenharmony_ci}; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic void __attribute__((constructor)) ebb_init(void) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci clear_ebb_stats(); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (sigaction(SIGTERM, &term_action, NULL)) 4828c2ecf20Sopenharmony_ci perror("sigaction"); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024); 4858c2ecf20Sopenharmony_ci} 486