10cfab8ddSJoseph Koshy /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 40cfab8ddSJoseph Koshy * Copyright (c) 2008 Joseph Koshy 50cfab8ddSJoseph Koshy * All rights reserved. 60cfab8ddSJoseph Koshy * 70cfab8ddSJoseph Koshy * Redistribution and use in source and binary forms, with or without 80cfab8ddSJoseph Koshy * modification, are permitted provided that the following conditions 90cfab8ddSJoseph Koshy * are met: 100cfab8ddSJoseph Koshy * 1. Redistributions of source code must retain the above copyright 110cfab8ddSJoseph Koshy * notice, this list of conditions and the following disclaimer. 120cfab8ddSJoseph Koshy * 2. Redistributions in binary form must reproduce the above copyright 130cfab8ddSJoseph Koshy * notice, this list of conditions and the following disclaimer in the 140cfab8ddSJoseph Koshy * documentation and/or other materials provided with the distribution. 150cfab8ddSJoseph Koshy * 160cfab8ddSJoseph Koshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 170cfab8ddSJoseph Koshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 180cfab8ddSJoseph Koshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 190cfab8ddSJoseph Koshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 200cfab8ddSJoseph Koshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 210cfab8ddSJoseph Koshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 220cfab8ddSJoseph Koshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 230cfab8ddSJoseph Koshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 240cfab8ddSJoseph Koshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 250cfab8ddSJoseph Koshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 260cfab8ddSJoseph Koshy * SUCH DAMAGE. 270cfab8ddSJoseph Koshy */ 280cfab8ddSJoseph Koshy 290cfab8ddSJoseph Koshy /* 30c8517255SHiren Panchasara * Intel Core PMCs. 310cfab8ddSJoseph Koshy */ 320cfab8ddSJoseph Koshy 330cfab8ddSJoseph Koshy #include <sys/param.h> 3421157ad3SJohn Baldwin #include <sys/bus.h> 350cfab8ddSJoseph Koshy #include <sys/pmc.h> 360cfab8ddSJoseph Koshy #include <sys/pmckern.h> 3722d77084SKonstantin Belousov #include <sys/smp.h> 380cfab8ddSJoseph Koshy #include <sys/systm.h> 390cfab8ddSJoseph Koshy 4021157ad3SJohn Baldwin #include <machine/intr_machdep.h> 41e07ef9b0SJohn Baldwin #include <x86/apicvar.h> 420cfab8ddSJoseph Koshy #include <machine/cpu.h> 430cfab8ddSJoseph Koshy #include <machine/cpufunc.h> 442dde521aSFabien Thomas #include <machine/md_var.h> 450cfab8ddSJoseph Koshy #include <machine/specialreg.h> 460cfab8ddSJoseph Koshy 470cfab8ddSJoseph Koshy #define CORE_CPUID_REQUEST 0xA 480cfab8ddSJoseph Koshy #define CORE_CPUID_REQUEST_SIZE 0x4 490cfab8ddSJoseph Koshy #define CORE_CPUID_EAX 0x0 500cfab8ddSJoseph Koshy #define CORE_CPUID_EBX 0x1 510cfab8ddSJoseph Koshy #define CORE_CPUID_ECX 0x2 520cfab8ddSJoseph Koshy #define CORE_CPUID_EDX 0x3 530cfab8ddSJoseph Koshy 540cfab8ddSJoseph Koshy #define IAF_PMC_CAPS \ 5503963ef8SGeorge V. Neville-Neil (PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_INTERRUPT | \ 5603963ef8SGeorge V. Neville-Neil PMC_CAP_USER | PMC_CAP_SYSTEM) 570cfab8ddSJoseph Koshy #define IAF_RI_TO_MSR(RI) ((RI) + (1 << 30)) 580cfab8ddSJoseph Koshy 590cfab8ddSJoseph Koshy #define IAP_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | PMC_CAP_SYSTEM | \ 600cfab8ddSJoseph Koshy PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \ 610cfab8ddSJoseph Koshy PMC_CAP_INVERT | PMC_CAP_QUALIFIER | PMC_CAP_PRECISE) 620cfab8ddSJoseph Koshy 6338179e6eSDavide Italiano #define EV_IS_NOTARCH 0 6438179e6eSDavide Italiano #define EV_IS_ARCH_SUPP 1 6538179e6eSDavide Italiano #define EV_IS_ARCH_NOTSUPP -1 6638179e6eSDavide Italiano 670cfab8ddSJoseph Koshy /* 680cfab8ddSJoseph Koshy * "Architectural" events defined by Intel. The values of these 690cfab8ddSJoseph Koshy * symbols correspond to positions in the bitmask returned by 700cfab8ddSJoseph Koshy * the CPUID.0AH instruction. 710cfab8ddSJoseph Koshy */ 720cfab8ddSJoseph Koshy enum core_arch_events { 730cfab8ddSJoseph Koshy CORE_AE_BRANCH_INSTRUCTION_RETIRED = 5, 740cfab8ddSJoseph Koshy CORE_AE_BRANCH_MISSES_RETIRED = 6, 750cfab8ddSJoseph Koshy CORE_AE_INSTRUCTION_RETIRED = 1, 760cfab8ddSJoseph Koshy CORE_AE_LLC_MISSES = 4, 770cfab8ddSJoseph Koshy CORE_AE_LLC_REFERENCE = 3, 780cfab8ddSJoseph Koshy CORE_AE_UNHALTED_REFERENCE_CYCLES = 2, 790cfab8ddSJoseph Koshy CORE_AE_UNHALTED_CORE_CYCLES = 0 800cfab8ddSJoseph Koshy }; 810cfab8ddSJoseph Koshy 820cfab8ddSJoseph Koshy static enum pmc_cputype core_cputype; 8381ffb45fSAlexander Motin static int core_version; 840cfab8ddSJoseph Koshy 850cfab8ddSJoseph Koshy struct core_cpu { 860cfab8ddSJoseph Koshy volatile uint32_t pc_iafctrl; /* Fixed function control. */ 870cfab8ddSJoseph Koshy volatile uint64_t pc_globalctrl; /* Global control register. */ 880cfab8ddSJoseph Koshy struct pmc_hw pc_corepmcs[]; 890cfab8ddSJoseph Koshy }; 900cfab8ddSJoseph Koshy 910cfab8ddSJoseph Koshy static struct core_cpu **core_pcpu; 920cfab8ddSJoseph Koshy 930cfab8ddSJoseph Koshy static uint32_t core_architectural_events; 940cfab8ddSJoseph Koshy static uint64_t core_pmcmask; 950cfab8ddSJoseph Koshy 960cfab8ddSJoseph Koshy static int core_iaf_ri; /* relative index of fixed counters */ 970cfab8ddSJoseph Koshy static int core_iaf_width; 980cfab8ddSJoseph Koshy static int core_iaf_npmc; 990cfab8ddSJoseph Koshy 1000cfab8ddSJoseph Koshy static int core_iap_width; 1010cfab8ddSJoseph Koshy static int core_iap_npmc; 102411c83ccSKonstantin Belousov static int core_iap_wroffset; 1030cfab8ddSJoseph Koshy 10422d77084SKonstantin Belousov static u_int pmc_alloc_refs; 10522d77084SKonstantin Belousov static bool pmc_tsx_force_abort_set; 10622d77084SKonstantin Belousov 1070cfab8ddSJoseph Koshy static int 1080cfab8ddSJoseph Koshy core_pcpu_noop(struct pmc_mdep *md, int cpu) 1090cfab8ddSJoseph Koshy { 1100cfab8ddSJoseph Koshy (void) md; 1110cfab8ddSJoseph Koshy (void) cpu; 1120cfab8ddSJoseph Koshy return (0); 1130cfab8ddSJoseph Koshy } 1140cfab8ddSJoseph Koshy 1150cfab8ddSJoseph Koshy static int 1160cfab8ddSJoseph Koshy core_pcpu_init(struct pmc_mdep *md, int cpu) 1170cfab8ddSJoseph Koshy { 1180cfab8ddSJoseph Koshy struct pmc_cpu *pc; 1190cfab8ddSJoseph Koshy struct core_cpu *cc; 1200cfab8ddSJoseph Koshy struct pmc_hw *phw; 1210cfab8ddSJoseph Koshy int core_ri, n, npmc; 1220cfab8ddSJoseph Koshy 1230cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 1240cfab8ddSJoseph Koshy ("[iaf,%d] insane cpu number %d", __LINE__, cpu)); 1250cfab8ddSJoseph Koshy 1264a3690dfSJohn Baldwin PMCDBG1(MDP,INI,1,"core-init cpu=%d", cpu); 1270cfab8ddSJoseph Koshy 1280cfab8ddSJoseph Koshy core_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_ri; 1290cfab8ddSJoseph Koshy npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_num; 1300cfab8ddSJoseph Koshy 13181ffb45fSAlexander Motin if (core_version >= 2) 1320cfab8ddSJoseph Koshy npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF].pcd_num; 1330cfab8ddSJoseph Koshy 1340cfab8ddSJoseph Koshy cc = malloc(sizeof(struct core_cpu) + npmc * sizeof(struct pmc_hw), 1350cfab8ddSJoseph Koshy M_PMC, M_WAITOK | M_ZERO); 1360cfab8ddSJoseph Koshy 1370cfab8ddSJoseph Koshy core_pcpu[cpu] = cc; 1380cfab8ddSJoseph Koshy pc = pmc_pcpu[cpu]; 1390cfab8ddSJoseph Koshy 1400cfab8ddSJoseph Koshy KASSERT(pc != NULL && cc != NULL, 1410cfab8ddSJoseph Koshy ("[core,%d] NULL per-cpu structures cpu=%d", __LINE__, cpu)); 1420cfab8ddSJoseph Koshy 1430cfab8ddSJoseph Koshy for (n = 0, phw = cc->pc_corepmcs; n < npmc; n++, phw++) { 1440cfab8ddSJoseph Koshy phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | 1450cfab8ddSJoseph Koshy PMC_PHW_CPU_TO_STATE(cpu) | 1460cfab8ddSJoseph Koshy PMC_PHW_INDEX_TO_STATE(n + core_ri); 1470cfab8ddSJoseph Koshy phw->phw_pmc = NULL; 1480cfab8ddSJoseph Koshy pc->pc_hwpmcs[n + core_ri] = phw; 1490cfab8ddSJoseph Koshy } 1500cfab8ddSJoseph Koshy 1514e679d8aSAlexander Motin if (core_version >= 2 && vm_guest == VM_GUEST_NO) { 15281ffb45fSAlexander Motin /* Enable Freezing PMCs on PMI. */ 15381ffb45fSAlexander Motin wrmsr(MSR_DEBUGCTLMSR, rdmsr(MSR_DEBUGCTLMSR) | 0x1000); 15481ffb45fSAlexander Motin } 15581ffb45fSAlexander Motin 1560cfab8ddSJoseph Koshy return (0); 1570cfab8ddSJoseph Koshy } 1580cfab8ddSJoseph Koshy 1590cfab8ddSJoseph Koshy static int 1600cfab8ddSJoseph Koshy core_pcpu_fini(struct pmc_mdep *md, int cpu) 1610cfab8ddSJoseph Koshy { 1620cfab8ddSJoseph Koshy int core_ri, n, npmc; 1630cfab8ddSJoseph Koshy struct pmc_cpu *pc; 1640cfab8ddSJoseph Koshy struct core_cpu *cc; 1650cfab8ddSJoseph Koshy 1660cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 1670cfab8ddSJoseph Koshy ("[core,%d] insane cpu number (%d)", __LINE__, cpu)); 1680cfab8ddSJoseph Koshy 1694a3690dfSJohn Baldwin PMCDBG1(MDP,INI,1,"core-pcpu-fini cpu=%d", cpu); 1700cfab8ddSJoseph Koshy 1710cfab8ddSJoseph Koshy if ((cc = core_pcpu[cpu]) == NULL) 1720cfab8ddSJoseph Koshy return (0); 1730cfab8ddSJoseph Koshy 1740cfab8ddSJoseph Koshy core_pcpu[cpu] = NULL; 1750cfab8ddSJoseph Koshy 1760cfab8ddSJoseph Koshy pc = pmc_pcpu[cpu]; 1770cfab8ddSJoseph Koshy 1780cfab8ddSJoseph Koshy KASSERT(pc != NULL, ("[core,%d] NULL per-cpu %d state", __LINE__, 1790cfab8ddSJoseph Koshy cpu)); 1800cfab8ddSJoseph Koshy 1810cfab8ddSJoseph Koshy npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_num; 1820cfab8ddSJoseph Koshy core_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_ri; 1830cfab8ddSJoseph Koshy 18481ffb45fSAlexander Motin for (n = 0; n < npmc; n++) 18581ffb45fSAlexander Motin wrmsr(IAP_EVSEL0 + n, 0); 1860cfab8ddSJoseph Koshy 18781ffb45fSAlexander Motin if (core_version >= 2) { 18881ffb45fSAlexander Motin wrmsr(IAF_CTRL, 0); 1890cfab8ddSJoseph Koshy npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF].pcd_num; 1900cfab8ddSJoseph Koshy } 1910cfab8ddSJoseph Koshy 1920cfab8ddSJoseph Koshy for (n = 0; n < npmc; n++) 1930cfab8ddSJoseph Koshy pc->pc_hwpmcs[n + core_ri] = NULL; 1940cfab8ddSJoseph Koshy 1950cfab8ddSJoseph Koshy free(cc, M_PMC); 1960cfab8ddSJoseph Koshy 1970cfab8ddSJoseph Koshy return (0); 1980cfab8ddSJoseph Koshy } 1990cfab8ddSJoseph Koshy 2000cfab8ddSJoseph Koshy /* 2010cfab8ddSJoseph Koshy * Fixed function counters. 2020cfab8ddSJoseph Koshy */ 2030cfab8ddSJoseph Koshy 2040cfab8ddSJoseph Koshy static pmc_value_t 2050cfab8ddSJoseph Koshy iaf_perfctr_value_to_reload_count(pmc_value_t v) 2060cfab8ddSJoseph Koshy { 207a1febbf6SJohn Baldwin 208a1febbf6SJohn Baldwin /* If the PMC has overflowed, return a reload count of zero. */ 209a1febbf6SJohn Baldwin if ((v & (1ULL << (core_iaf_width - 1))) == 0) 210a1febbf6SJohn Baldwin return (0); 2110cfab8ddSJoseph Koshy v &= (1ULL << core_iaf_width) - 1; 2120cfab8ddSJoseph Koshy return (1ULL << core_iaf_width) - v; 2130cfab8ddSJoseph Koshy } 2140cfab8ddSJoseph Koshy 2150cfab8ddSJoseph Koshy static pmc_value_t 2160cfab8ddSJoseph Koshy iaf_reload_count_to_perfctr_value(pmc_value_t rlc) 2170cfab8ddSJoseph Koshy { 2180cfab8ddSJoseph Koshy return (1ULL << core_iaf_width) - rlc; 2190cfab8ddSJoseph Koshy } 2200cfab8ddSJoseph Koshy 2210cfab8ddSJoseph Koshy static int 2220cfab8ddSJoseph Koshy iaf_allocate_pmc(int cpu, int ri, struct pmc *pm, 2230cfab8ddSJoseph Koshy const struct pmc_op_pmcallocate *a) 2240cfab8ddSJoseph Koshy { 22507d80fd8SMatt Macy uint8_t ev, umask; 2261a4614a5SAlexander Motin uint32_t caps; 2271a4614a5SAlexander Motin uint64_t config, flags; 22807d80fd8SMatt Macy const struct pmc_md_iap_op_pmcallocate *iap; 2290cfab8ddSJoseph Koshy 2300cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 2310cfab8ddSJoseph Koshy ("[core,%d] illegal CPU %d", __LINE__, cpu)); 2320cfab8ddSJoseph Koshy 2334a3690dfSJohn Baldwin PMCDBG2(MDP,ALL,1, "iaf-allocate ri=%d reqcaps=0x%x", ri, pm->pm_caps); 2340cfab8ddSJoseph Koshy 2350cfab8ddSJoseph Koshy if (ri < 0 || ri > core_iaf_npmc) 2360cfab8ddSJoseph Koshy return (EINVAL); 2370cfab8ddSJoseph Koshy 2380e78510bSMitchell Horne if (a->pm_class != PMC_CLASS_IAF) 2390cfab8ddSJoseph Koshy return (EINVAL); 2400cfab8ddSJoseph Koshy 241c190fb35SMitchell Horne if ((a->pm_flags & PMC_F_EV_PMU) == 0) 242c190fb35SMitchell Horne return (EINVAL); 243c190fb35SMitchell Horne 24407d80fd8SMatt Macy iap = &a->pm_md.pm_iap; 24507d80fd8SMatt Macy config = iap->pm_iap_config; 24607d80fd8SMatt Macy ev = IAP_EVSEL_GET(config); 24707d80fd8SMatt Macy umask = IAP_UMASK_GET(config); 248e92a1350SMatt Macy 249c1e813d1SAlexander Motin if (ev == 0x0) { 250c1e813d1SAlexander Motin if (umask != ri + 1) 2510cfab8ddSJoseph Koshy return (EINVAL); 252c1e813d1SAlexander Motin } else { 253c1e813d1SAlexander Motin switch (ri) { 254c1e813d1SAlexander Motin case 0: /* INST_RETIRED.ANY */ 255c1e813d1SAlexander Motin if (ev != 0xC0 || umask != 0x00) 2560cfab8ddSJoseph Koshy return (EINVAL); 257c1e813d1SAlexander Motin break; 258c1e813d1SAlexander Motin case 1: /* CPU_CLK_UNHALTED.THREAD */ 259c1e813d1SAlexander Motin if (ev != 0x3C || umask != 0x00) 26007d80fd8SMatt Macy return (EINVAL); 261c1e813d1SAlexander Motin break; 262c1e813d1SAlexander Motin case 2: /* CPU_CLK_UNHALTED.REF */ 263c1e813d1SAlexander Motin if (ev != 0x3C || umask != 0x01) 264c1e813d1SAlexander Motin return (EINVAL); 265c1e813d1SAlexander Motin break; 266c1e813d1SAlexander Motin case 3: /* TOPDOWN.SLOTS */ 267c1e813d1SAlexander Motin if (ev != 0xA4 || umask != 0x01) 268c1e813d1SAlexander Motin return (EINVAL); 269c1e813d1SAlexander Motin break; 270c1e813d1SAlexander Motin default: 271c1e813d1SAlexander Motin return (EINVAL); 272c1e813d1SAlexander Motin } 273c1e813d1SAlexander Motin } 2749645bcabSMatt Macy 27522d77084SKonstantin Belousov pmc_alloc_refs++; 27622d77084SKonstantin Belousov if ((cpu_stdext_feature3 & CPUID_STDEXT3_TSXFA) != 0 && 27722d77084SKonstantin Belousov !pmc_tsx_force_abort_set) { 27822d77084SKonstantin Belousov pmc_tsx_force_abort_set = true; 279d0bc4b46SKonstantin Belousov x86_msr_op(MSR_TSX_FORCE_ABORT, MSR_OP_RENDEZVOUS_ALL | 280d0bc4b46SKonstantin Belousov MSR_OP_WRITE, 1, NULL); 28122d77084SKonstantin Belousov } 2820cfab8ddSJoseph Koshy 28307d80fd8SMatt Macy flags = 0; 28407d80fd8SMatt Macy if (config & IAP_OS) 28507d80fd8SMatt Macy flags |= IAF_OS; 28607d80fd8SMatt Macy if (config & IAP_USR) 28707d80fd8SMatt Macy flags |= IAF_USR; 28807d80fd8SMatt Macy if (config & IAP_ANY) 28907d80fd8SMatt Macy flags |= IAF_ANY; 29007d80fd8SMatt Macy if (config & IAP_INT) 29107d80fd8SMatt Macy flags |= IAF_PMI; 2920cfab8ddSJoseph Koshy 2930e78510bSMitchell Horne caps = a->pm_caps; 2940cfab8ddSJoseph Koshy if (caps & PMC_CAP_INTERRUPT) 2950cfab8ddSJoseph Koshy flags |= IAF_PMI; 2960cfab8ddSJoseph Koshy if (caps & PMC_CAP_SYSTEM) 2970cfab8ddSJoseph Koshy flags |= IAF_OS; 2980cfab8ddSJoseph Koshy if (caps & PMC_CAP_USER) 2990cfab8ddSJoseph Koshy flags |= IAF_USR; 3000cfab8ddSJoseph Koshy if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) 3010cfab8ddSJoseph Koshy flags |= (IAF_OS | IAF_USR); 3020cfab8ddSJoseph Koshy 3030cfab8ddSJoseph Koshy pm->pm_md.pm_iaf.pm_iaf_ctrl = (flags << (ri * 4)); 3040cfab8ddSJoseph Koshy 3054a3690dfSJohn Baldwin PMCDBG1(MDP,ALL,2, "iaf-allocate config=0x%jx", 3060cfab8ddSJoseph Koshy (uintmax_t) pm->pm_md.pm_iaf.pm_iaf_ctrl); 3070cfab8ddSJoseph Koshy 3080cfab8ddSJoseph Koshy return (0); 3090cfab8ddSJoseph Koshy } 3100cfab8ddSJoseph Koshy 3110cfab8ddSJoseph Koshy static int 3120cfab8ddSJoseph Koshy iaf_config_pmc(int cpu, int ri, struct pmc *pm) 3130cfab8ddSJoseph Koshy { 3140cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 3150cfab8ddSJoseph Koshy ("[core,%d] illegal CPU %d", __LINE__, cpu)); 3160cfab8ddSJoseph Koshy 3170cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iaf_npmc, 3180cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 3190cfab8ddSJoseph Koshy 3204a3690dfSJohn Baldwin PMCDBG3(MDP,CFG,1, "iaf-config cpu=%d ri=%d pm=%p", cpu, ri, pm); 3210cfab8ddSJoseph Koshy 3220cfab8ddSJoseph Koshy KASSERT(core_pcpu[cpu] != NULL, ("[core,%d] null per-cpu %d", __LINE__, 3230cfab8ddSJoseph Koshy cpu)); 3240cfab8ddSJoseph Koshy 3250cfab8ddSJoseph Koshy core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc = pm; 3260cfab8ddSJoseph Koshy 3270cfab8ddSJoseph Koshy return (0); 3280cfab8ddSJoseph Koshy } 3290cfab8ddSJoseph Koshy 3300cfab8ddSJoseph Koshy static int 3310cfab8ddSJoseph Koshy iaf_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 3320cfab8ddSJoseph Koshy { 3330cfab8ddSJoseph Koshy struct pmc_hw *phw; 3340cfab8ddSJoseph Koshy 3350cfab8ddSJoseph Koshy phw = &core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri]; 3360cfab8ddSJoseph Koshy 33731610e34SMitchell Horne snprintf(pi->pm_name, sizeof(pi->pm_name), "IAF-%d", ri); 3380cfab8ddSJoseph Koshy pi->pm_class = PMC_CLASS_IAF; 3390cfab8ddSJoseph Koshy 3400cfab8ddSJoseph Koshy if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 3410cfab8ddSJoseph Koshy pi->pm_enabled = TRUE; 3420cfab8ddSJoseph Koshy *ppmc = phw->phw_pmc; 3430cfab8ddSJoseph Koshy } else { 3440cfab8ddSJoseph Koshy pi->pm_enabled = FALSE; 3450cfab8ddSJoseph Koshy *ppmc = NULL; 3460cfab8ddSJoseph Koshy } 3470cfab8ddSJoseph Koshy 3480cfab8ddSJoseph Koshy return (0); 3490cfab8ddSJoseph Koshy } 3500cfab8ddSJoseph Koshy 3510cfab8ddSJoseph Koshy static int 3520cfab8ddSJoseph Koshy iaf_get_config(int cpu, int ri, struct pmc **ppm) 3530cfab8ddSJoseph Koshy { 3540cfab8ddSJoseph Koshy *ppm = core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc; 3550cfab8ddSJoseph Koshy 3560cfab8ddSJoseph Koshy return (0); 3570cfab8ddSJoseph Koshy } 3580cfab8ddSJoseph Koshy 3590cfab8ddSJoseph Koshy static int 3600cfab8ddSJoseph Koshy iaf_get_msr(int ri, uint32_t *msr) 3610cfab8ddSJoseph Koshy { 3620cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iaf_npmc, 3630cfab8ddSJoseph Koshy ("[iaf,%d] ri %d out of range", __LINE__, ri)); 3640cfab8ddSJoseph Koshy 3650cfab8ddSJoseph Koshy *msr = IAF_RI_TO_MSR(ri); 3660cfab8ddSJoseph Koshy 3670cfab8ddSJoseph Koshy return (0); 3680cfab8ddSJoseph Koshy } 3690cfab8ddSJoseph Koshy 3700cfab8ddSJoseph Koshy static int 37139f92a76SMitchell Horne iaf_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v) 3720cfab8ddSJoseph Koshy { 3730cfab8ddSJoseph Koshy pmc_value_t tmp; 3740cfab8ddSJoseph Koshy 3750cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 3760cfab8ddSJoseph Koshy ("[core,%d] illegal cpu value %d", __LINE__, cpu)); 3770cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iaf_npmc, 3780cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 3790cfab8ddSJoseph Koshy 3800cfab8ddSJoseph Koshy tmp = rdpmc(IAF_RI_TO_MSR(ri)); 3810cfab8ddSJoseph Koshy 3820cfab8ddSJoseph Koshy if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 3830cfab8ddSJoseph Koshy *v = iaf_perfctr_value_to_reload_count(tmp); 3840cfab8ddSJoseph Koshy else 3851f095f70SJohn Baldwin *v = tmp & ((1ULL << core_iaf_width) - 1); 3860cfab8ddSJoseph Koshy 3874a3690dfSJohn Baldwin PMCDBG4(MDP,REA,1, "iaf-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri, 3880cfab8ddSJoseph Koshy IAF_RI_TO_MSR(ri), *v); 3890cfab8ddSJoseph Koshy 3900cfab8ddSJoseph Koshy return (0); 3910cfab8ddSJoseph Koshy } 3920cfab8ddSJoseph Koshy 3930cfab8ddSJoseph Koshy static int 3940cfab8ddSJoseph Koshy iaf_release_pmc(int cpu, int ri, struct pmc *pmc) 3950cfab8ddSJoseph Koshy { 3964a3690dfSJohn Baldwin PMCDBG3(MDP,REL,1, "iaf-release cpu=%d ri=%d pm=%p", cpu, ri, pmc); 3970cfab8ddSJoseph Koshy 3980cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 3990cfab8ddSJoseph Koshy ("[core,%d] illegal CPU value %d", __LINE__, cpu)); 4000cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iaf_npmc, 4010cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 4020cfab8ddSJoseph Koshy 4030cfab8ddSJoseph Koshy KASSERT(core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc == NULL, 4040cfab8ddSJoseph Koshy ("[core,%d] PHW pmc non-NULL", __LINE__)); 4050cfab8ddSJoseph Koshy 40622d77084SKonstantin Belousov MPASS(pmc_alloc_refs > 0); 40722d77084SKonstantin Belousov if (pmc_alloc_refs-- == 1 && pmc_tsx_force_abort_set) { 40822d77084SKonstantin Belousov pmc_tsx_force_abort_set = false; 409d0bc4b46SKonstantin Belousov x86_msr_op(MSR_TSX_FORCE_ABORT, MSR_OP_RENDEZVOUS_ALL | 410d0bc4b46SKonstantin Belousov MSR_OP_WRITE, 0, NULL); 41122d77084SKonstantin Belousov } 41222d77084SKonstantin Belousov 4130cfab8ddSJoseph Koshy return (0); 4140cfab8ddSJoseph Koshy } 4150cfab8ddSJoseph Koshy 4160cfab8ddSJoseph Koshy static int 41739f92a76SMitchell Horne iaf_start_pmc(int cpu, int ri, struct pmc *pm) 4180cfab8ddSJoseph Koshy { 41981ffb45fSAlexander Motin struct core_cpu *cc; 4200cfab8ddSJoseph Koshy 4210cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 4220cfab8ddSJoseph Koshy ("[core,%d] illegal CPU value %d", __LINE__, cpu)); 4230cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iaf_npmc, 4240cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 4250cfab8ddSJoseph Koshy 4264a3690dfSJohn Baldwin PMCDBG2(MDP,STA,1,"iaf-start cpu=%d ri=%d", cpu, ri); 4270cfab8ddSJoseph Koshy 42881ffb45fSAlexander Motin cc = core_pcpu[cpu]; 42981ffb45fSAlexander Motin cc->pc_iafctrl |= pm->pm_md.pm_iaf.pm_iaf_ctrl; 43081ffb45fSAlexander Motin wrmsr(IAF_CTRL, cc->pc_iafctrl); 4310cfab8ddSJoseph Koshy 43281ffb45fSAlexander Motin cc->pc_globalctrl |= (1ULL << (ri + IAF_OFFSET)); 43381ffb45fSAlexander Motin wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl); 4340cfab8ddSJoseph Koshy 4354a3690dfSJohn Baldwin PMCDBG4(MDP,STA,1,"iafctrl=%x(%x) globalctrl=%jx(%jx)", 43681ffb45fSAlexander Motin cc->pc_iafctrl, (uint32_t) rdmsr(IAF_CTRL), 43781ffb45fSAlexander Motin cc->pc_globalctrl, rdmsr(IA_GLOBAL_CTRL)); 4380cfab8ddSJoseph Koshy 4390cfab8ddSJoseph Koshy return (0); 4400cfab8ddSJoseph Koshy } 4410cfab8ddSJoseph Koshy 4420cfab8ddSJoseph Koshy static int 44339f92a76SMitchell Horne iaf_stop_pmc(int cpu, int ri, struct pmc *pm) 4440cfab8ddSJoseph Koshy { 44581ffb45fSAlexander Motin struct core_cpu *cc; 4460cfab8ddSJoseph Koshy 4470cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 4480cfab8ddSJoseph Koshy ("[core,%d] illegal CPU value %d", __LINE__, cpu)); 4490cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iaf_npmc, 4500cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 4510cfab8ddSJoseph Koshy 45281ffb45fSAlexander Motin PMCDBG2(MDP,STA,1,"iaf-stop cpu=%d ri=%d", cpu, ri); 4530cfab8ddSJoseph Koshy 45481ffb45fSAlexander Motin cc = core_pcpu[cpu]; 4550cfab8ddSJoseph Koshy 45681ffb45fSAlexander Motin cc->pc_iafctrl &= ~(IAF_MASK << (ri * 4)); 45781ffb45fSAlexander Motin wrmsr(IAF_CTRL, cc->pc_iafctrl); 4580cfab8ddSJoseph Koshy 459326a8d3eSAlexander Motin /* Don't need to write IA_GLOBAL_CTRL, one disable is enough. */ 4600cfab8ddSJoseph Koshy 4614a3690dfSJohn Baldwin PMCDBG4(MDP,STO,1,"iafctrl=%x(%x) globalctrl=%jx(%jx)", 46281ffb45fSAlexander Motin cc->pc_iafctrl, (uint32_t) rdmsr(IAF_CTRL), 46381ffb45fSAlexander Motin cc->pc_globalctrl, rdmsr(IA_GLOBAL_CTRL)); 4640cfab8ddSJoseph Koshy 4650cfab8ddSJoseph Koshy return (0); 4660cfab8ddSJoseph Koshy } 4670cfab8ddSJoseph Koshy 4680cfab8ddSJoseph Koshy static int 46939f92a76SMitchell Horne iaf_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v) 4700cfab8ddSJoseph Koshy { 4710cfab8ddSJoseph Koshy struct core_cpu *cc; 4720cfab8ddSJoseph Koshy 4730cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 4740cfab8ddSJoseph Koshy ("[core,%d] illegal cpu value %d", __LINE__, cpu)); 4750cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iaf_npmc, 4760cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 4770cfab8ddSJoseph Koshy 4780cfab8ddSJoseph Koshy cc = core_pcpu[cpu]; 4790cfab8ddSJoseph Koshy 4800cfab8ddSJoseph Koshy if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 4810cfab8ddSJoseph Koshy v = iaf_reload_count_to_perfctr_value(v); 4820cfab8ddSJoseph Koshy 48381ffb45fSAlexander Motin /* Turn off the fixed counter */ 48481ffb45fSAlexander Motin wrmsr(IAF_CTRL, cc->pc_iafctrl & ~(IAF_MASK << (ri * 4))); 485ee6a0281SGeorge V. Neville-Neil 486f4a9c304SGeorge V. Neville-Neil wrmsr(IAF_CTR0 + ri, v & ((1ULL << core_iaf_width) - 1)); 487ee6a0281SGeorge V. Neville-Neil 488ee6a0281SGeorge V. Neville-Neil /* Turn on fixed counters */ 48981ffb45fSAlexander Motin wrmsr(IAF_CTRL, cc->pc_iafctrl); 4900cfab8ddSJoseph Koshy 4914a3690dfSJohn Baldwin PMCDBG6(MDP,WRI,1, "iaf-write cpu=%d ri=%d msr=0x%x v=%jx iafctrl=%jx " 4920cfab8ddSJoseph Koshy "pmc=%jx", cpu, ri, IAF_RI_TO_MSR(ri), v, 4930cfab8ddSJoseph Koshy (uintmax_t) rdmsr(IAF_CTRL), 4940cfab8ddSJoseph Koshy (uintmax_t) rdpmc(IAF_RI_TO_MSR(ri))); 4950cfab8ddSJoseph Koshy 4960cfab8ddSJoseph Koshy return (0); 4970cfab8ddSJoseph Koshy } 4980cfab8ddSJoseph Koshy 4990cfab8ddSJoseph Koshy 5000cfab8ddSJoseph Koshy static void 5010cfab8ddSJoseph Koshy iaf_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth) 5020cfab8ddSJoseph Koshy { 5030cfab8ddSJoseph Koshy struct pmc_classdep *pcd; 5040cfab8ddSJoseph Koshy 5050cfab8ddSJoseph Koshy KASSERT(md != NULL, ("[iaf,%d] md is NULL", __LINE__)); 5060cfab8ddSJoseph Koshy 5074a3690dfSJohn Baldwin PMCDBG0(MDP,INI,1, "iaf-initialize"); 5080cfab8ddSJoseph Koshy 5090cfab8ddSJoseph Koshy pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF]; 5100cfab8ddSJoseph Koshy 5110cfab8ddSJoseph Koshy pcd->pcd_caps = IAF_PMC_CAPS; 5120cfab8ddSJoseph Koshy pcd->pcd_class = PMC_CLASS_IAF; 5130cfab8ddSJoseph Koshy pcd->pcd_num = npmc; 5140cfab8ddSJoseph Koshy pcd->pcd_ri = md->pmd_npmc; 5150cfab8ddSJoseph Koshy pcd->pcd_width = pmcwidth; 5160cfab8ddSJoseph Koshy 5170cfab8ddSJoseph Koshy pcd->pcd_allocate_pmc = iaf_allocate_pmc; 5180cfab8ddSJoseph Koshy pcd->pcd_config_pmc = iaf_config_pmc; 5190cfab8ddSJoseph Koshy pcd->pcd_describe = iaf_describe; 5200cfab8ddSJoseph Koshy pcd->pcd_get_config = iaf_get_config; 5210cfab8ddSJoseph Koshy pcd->pcd_get_msr = iaf_get_msr; 5220cfab8ddSJoseph Koshy pcd->pcd_pcpu_fini = core_pcpu_noop; 5230cfab8ddSJoseph Koshy pcd->pcd_pcpu_init = core_pcpu_noop; 5240cfab8ddSJoseph Koshy pcd->pcd_read_pmc = iaf_read_pmc; 5250cfab8ddSJoseph Koshy pcd->pcd_release_pmc = iaf_release_pmc; 5260cfab8ddSJoseph Koshy pcd->pcd_start_pmc = iaf_start_pmc; 5270cfab8ddSJoseph Koshy pcd->pcd_stop_pmc = iaf_stop_pmc; 5280cfab8ddSJoseph Koshy pcd->pcd_write_pmc = iaf_write_pmc; 5290cfab8ddSJoseph Koshy 5300cfab8ddSJoseph Koshy md->pmd_npmc += npmc; 5310cfab8ddSJoseph Koshy } 5320cfab8ddSJoseph Koshy 5330cfab8ddSJoseph Koshy /* 5340cfab8ddSJoseph Koshy * Intel programmable PMCs. 5350cfab8ddSJoseph Koshy */ 5360cfab8ddSJoseph Koshy 5370cfab8ddSJoseph Koshy /* Sub fields of UMASK that this event supports. */ 5380cfab8ddSJoseph Koshy #define IAP_M_CORE (1 << 0) /* Core specificity */ 5390cfab8ddSJoseph Koshy #define IAP_M_AGENT (1 << 1) /* Agent specificity */ 5400cfab8ddSJoseph Koshy #define IAP_M_PREFETCH (1 << 2) /* Prefetch */ 5410cfab8ddSJoseph Koshy #define IAP_M_MESI (1 << 3) /* MESI */ 5420cfab8ddSJoseph Koshy #define IAP_M_SNOOPRESPONSE (1 << 4) /* Snoop response */ 5430cfab8ddSJoseph Koshy #define IAP_M_SNOOPTYPE (1 << 5) /* Snoop type */ 5440cfab8ddSJoseph Koshy #define IAP_M_TRANSITION (1 << 6) /* Transition */ 5450cfab8ddSJoseph Koshy 5460cfab8ddSJoseph Koshy #define IAP_F_CORE (0x3 << 14) /* Core specificity */ 5470cfab8ddSJoseph Koshy #define IAP_F_AGENT (0x1 << 13) /* Agent specificity */ 5480cfab8ddSJoseph Koshy #define IAP_F_PREFETCH (0x3 << 12) /* Prefetch */ 5490cfab8ddSJoseph Koshy #define IAP_F_MESI (0xF << 8) /* MESI */ 5500cfab8ddSJoseph Koshy #define IAP_F_SNOOPRESPONSE (0xB << 8) /* Snoop response */ 5510cfab8ddSJoseph Koshy #define IAP_F_SNOOPTYPE (0x3 << 8) /* Snoop type */ 5520cfab8ddSJoseph Koshy #define IAP_F_TRANSITION (0x1 << 12) /* Transition */ 5530cfab8ddSJoseph Koshy 5540cfab8ddSJoseph Koshy #define IAP_PREFETCH_RESERVED (0x2 << 12) 5550cfab8ddSJoseph Koshy #define IAP_CORE_THIS (0x1 << 14) 5560cfab8ddSJoseph Koshy #define IAP_CORE_ALL (0x3 << 14) 5570cfab8ddSJoseph Koshy #define IAP_F_CMASK 0xFF000000 5580cfab8ddSJoseph Koshy 5590cfab8ddSJoseph Koshy static pmc_value_t 5600cfab8ddSJoseph Koshy iap_perfctr_value_to_reload_count(pmc_value_t v) 5610cfab8ddSJoseph Koshy { 562a1febbf6SJohn Baldwin 563a1febbf6SJohn Baldwin /* If the PMC has overflowed, return a reload count of zero. */ 564a1febbf6SJohn Baldwin if ((v & (1ULL << (core_iap_width - 1))) == 0) 565a1febbf6SJohn Baldwin return (0); 5660cfab8ddSJoseph Koshy v &= (1ULL << core_iap_width) - 1; 5670cfab8ddSJoseph Koshy return (1ULL << core_iap_width) - v; 5680cfab8ddSJoseph Koshy } 5690cfab8ddSJoseph Koshy 5700cfab8ddSJoseph Koshy static pmc_value_t 5710cfab8ddSJoseph Koshy iap_reload_count_to_perfctr_value(pmc_value_t rlc) 5720cfab8ddSJoseph Koshy { 5730cfab8ddSJoseph Koshy return (1ULL << core_iap_width) - rlc; 5740cfab8ddSJoseph Koshy } 5750cfab8ddSJoseph Koshy 5760cfab8ddSJoseph Koshy static int 5770cfab8ddSJoseph Koshy iap_pmc_has_overflowed(int ri) 5780cfab8ddSJoseph Koshy { 5790cfab8ddSJoseph Koshy uint64_t v; 5800cfab8ddSJoseph Koshy 5810cfab8ddSJoseph Koshy /* 5820cfab8ddSJoseph Koshy * We treat a Core (i.e., Intel architecture v1) PMC as has 5830cfab8ddSJoseph Koshy * having overflowed if its MSB is zero. 5840cfab8ddSJoseph Koshy */ 5850cfab8ddSJoseph Koshy v = rdpmc(ri); 5860cfab8ddSJoseph Koshy return ((v & (1ULL << (core_iap_width - 1))) == 0); 5870cfab8ddSJoseph Koshy } 5880cfab8ddSJoseph Koshy 5890cfab8ddSJoseph Koshy static int 590959826caSMatt Macy iap_event_corei7_ok_on_counter(uint8_t evsel, int ri) 5911fa7f10bSFabien Thomas { 5921fa7f10bSFabien Thomas uint32_t mask; 5931fa7f10bSFabien Thomas 594959826caSMatt Macy switch (evsel) { 595ae57fbc7SAlexander Motin /* Events valid only on counter 0, 1. */ 596959826caSMatt Macy case 0x40: 597959826caSMatt Macy case 0x41: 598959826caSMatt Macy case 0x42: 599959826caSMatt Macy case 0x43: 600ae57fbc7SAlexander Motin case 0x4C: 601ae57fbc7SAlexander Motin case 0x4E: 602959826caSMatt Macy case 0x51: 603ae57fbc7SAlexander Motin case 0x52: 604ae57fbc7SAlexander Motin case 0x53: 605959826caSMatt Macy case 0x63: 6061fa7f10bSFabien Thomas mask = 0x3; 6071fa7f10bSFabien Thomas break; 608ae57fbc7SAlexander Motin /* Any row index is ok. */ 6091fa7f10bSFabien Thomas default: 610ae57fbc7SAlexander Motin mask = ~0; 6111fa7f10bSFabien Thomas } 6121fa7f10bSFabien Thomas 6131fa7f10bSFabien Thomas return (mask & (1 << ri)); 6141fa7f10bSFabien Thomas } 6151fa7f10bSFabien Thomas 6161fa7f10bSFabien Thomas static int 617959826caSMatt Macy iap_event_westmere_ok_on_counter(uint8_t evsel, int ri) 6181fa7f10bSFabien Thomas { 6191fa7f10bSFabien Thomas uint32_t mask; 6201fa7f10bSFabien Thomas 621959826caSMatt Macy switch (evsel) { 622ae57fbc7SAlexander Motin /* Events valid only on counter 0. */ 623959826caSMatt Macy case 0x60: 624959826caSMatt Macy case 0xB3: 6251fa7f10bSFabien Thomas mask = 0x1; 6261fa7f10bSFabien Thomas break; 6271fa7f10bSFabien Thomas 628ae57fbc7SAlexander Motin /* Events valid only on counter 0, 1. */ 629959826caSMatt Macy case 0x4C: 630959826caSMatt Macy case 0x4E: 631959826caSMatt Macy case 0x51: 632ae57fbc7SAlexander Motin case 0x52: 633959826caSMatt Macy case 0x63: 6341fa7f10bSFabien Thomas mask = 0x3; 6351fa7f10bSFabien Thomas break; 636ae57fbc7SAlexander Motin /* Any row index is ok. */ 6371fa7f10bSFabien Thomas default: 638ae57fbc7SAlexander Motin mask = ~0; 6391fa7f10bSFabien Thomas } 6401fa7f10bSFabien Thomas 6411fa7f10bSFabien Thomas return (mask & (1 << ri)); 6421fa7f10bSFabien Thomas } 6431fa7f10bSFabien Thomas 6441fa7f10bSFabien Thomas static int 645959826caSMatt Macy iap_event_sb_sbx_ib_ibx_ok_on_counter(uint8_t evsel, int ri) 64678d763a2SDavide Italiano { 64778d763a2SDavide Italiano uint32_t mask; 64878d763a2SDavide Italiano 649959826caSMatt Macy switch (evsel) { 65035db6424SFabien Thomas /* Events valid only on counter 0. */ 651959826caSMatt Macy case 0xB7: 65235db6424SFabien Thomas mask = 0x1; 65335db6424SFabien Thomas break; 65435db6424SFabien Thomas /* Events valid only on counter 1. */ 655959826caSMatt Macy case 0xC0: 65689d0633bSRyan Stone mask = 0x2; 65735db6424SFabien Thomas break; 65835db6424SFabien Thomas /* Events valid only on counter 2. */ 659959826caSMatt Macy case 0x48: 660959826caSMatt Macy case 0xA2: 661959826caSMatt Macy case 0xA3: 6621e862e5aSFabien Thomas mask = 0x4; 6631e862e5aSFabien Thomas break; 66435db6424SFabien Thomas /* Events valid only on counter 3. */ 665959826caSMatt Macy case 0xBB: 666959826caSMatt Macy case 0xCD: 66735db6424SFabien Thomas mask = 0x8; 66878d763a2SDavide Italiano break; 669ae57fbc7SAlexander Motin /* Any row index is ok. */ 67078d763a2SDavide Italiano default: 671ae57fbc7SAlexander Motin mask = ~0; 67278d763a2SDavide Italiano } 67378d763a2SDavide Italiano 67478d763a2SDavide Italiano return (mask & (1 << ri)); 67578d763a2SDavide Italiano } 67678d763a2SDavide Italiano 67778d763a2SDavide Italiano static int 678ae57fbc7SAlexander Motin iap_event_core_ok_on_counter(uint8_t evsel, int ri) 6790cfab8ddSJoseph Koshy { 6800cfab8ddSJoseph Koshy uint32_t mask; 6810cfab8ddSJoseph Koshy 682959826caSMatt Macy switch (evsel) { 6830cfab8ddSJoseph Koshy /* 6840cfab8ddSJoseph Koshy * Events valid only on counter 0. 6850cfab8ddSJoseph Koshy */ 686959826caSMatt Macy case 0x10: 687959826caSMatt Macy case 0x14: 688959826caSMatt Macy case 0x18: 689959826caSMatt Macy case 0xB3: 690959826caSMatt Macy case 0xC1: 691959826caSMatt Macy case 0xCB: 6920cfab8ddSJoseph Koshy mask = (1 << 0); 6930cfab8ddSJoseph Koshy break; 6940cfab8ddSJoseph Koshy 6950cfab8ddSJoseph Koshy /* 6960cfab8ddSJoseph Koshy * Events valid only on counter 1. 6970cfab8ddSJoseph Koshy */ 698959826caSMatt Macy case 0x11: 699959826caSMatt Macy case 0x12: 700959826caSMatt Macy case 0x13: 7010cfab8ddSJoseph Koshy mask = (1 << 1); 7020cfab8ddSJoseph Koshy break; 7030cfab8ddSJoseph Koshy 7040cfab8ddSJoseph Koshy default: 7050cfab8ddSJoseph Koshy mask = ~0; /* Any row index is ok. */ 7060cfab8ddSJoseph Koshy } 7070cfab8ddSJoseph Koshy 7080cfab8ddSJoseph Koshy return (mask & (1 << ri)); 7090cfab8ddSJoseph Koshy } 7100cfab8ddSJoseph Koshy 7110cfab8ddSJoseph Koshy static int 7120cfab8ddSJoseph Koshy iap_allocate_pmc(int cpu, int ri, struct pmc *pm, 7130cfab8ddSJoseph Koshy const struct pmc_op_pmcallocate *a) 7140cfab8ddSJoseph Koshy { 715959826caSMatt Macy uint8_t ev; 716959826caSMatt Macy const struct pmc_md_iap_op_pmcallocate *iap; 7170cfab8ddSJoseph Koshy 7180cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 7190cfab8ddSJoseph Koshy ("[core,%d] illegal CPU %d", __LINE__, cpu)); 7200cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 7210cfab8ddSJoseph Koshy ("[core,%d] illegal row-index value %d", __LINE__, ri)); 7220cfab8ddSJoseph Koshy 723315cd55dSMitchell Horne if (a->pm_class != PMC_CLASS_IAP) 724315cd55dSMitchell Horne return (EINVAL); 725315cd55dSMitchell Horne 726c190fb35SMitchell Horne if ((a->pm_flags & PMC_F_EV_PMU) == 0) 727c190fb35SMitchell Horne return (EINVAL); 728c190fb35SMitchell Horne 729959826caSMatt Macy iap = &a->pm_md.pm_iap; 730959826caSMatt Macy ev = IAP_EVSEL_GET(iap->pm_iap_config); 7312dde521aSFabien Thomas 7321fa7f10bSFabien Thomas switch (core_cputype) { 733ae57fbc7SAlexander Motin case PMC_CPU_INTEL_CORE: 734ae57fbc7SAlexander Motin case PMC_CPU_INTEL_CORE2: 735ae57fbc7SAlexander Motin case PMC_CPU_INTEL_CORE2EXTREME: 736ae57fbc7SAlexander Motin if (iap_event_core_ok_on_counter(ev, ri) == 0) 737ae57fbc7SAlexander Motin return (EINVAL); 7381fa7f10bSFabien Thomas case PMC_CPU_INTEL_COREI7: 73949fe48abSKonstantin Belousov case PMC_CPU_INTEL_NEHALEM_EX: 7401fa7f10bSFabien Thomas if (iap_event_corei7_ok_on_counter(ev, ri) == 0) 7411fa7f10bSFabien Thomas return (EINVAL); 7421fa7f10bSFabien Thomas break; 7431fa7f10bSFabien Thomas case PMC_CPU_INTEL_WESTMERE: 74449fe48abSKonstantin Belousov case PMC_CPU_INTEL_WESTMERE_EX: 7451fa7f10bSFabien Thomas if (iap_event_westmere_ok_on_counter(ev, ri) == 0) 7461fa7f10bSFabien Thomas return (EINVAL); 7471fa7f10bSFabien Thomas break; 748ae57fbc7SAlexander Motin case PMC_CPU_INTEL_SANDYBRIDGE: 749ae57fbc7SAlexander Motin case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 750ae57fbc7SAlexander Motin case PMC_CPU_INTEL_IVYBRIDGE: 751ae57fbc7SAlexander Motin case PMC_CPU_INTEL_IVYBRIDGE_XEON: 752ae57fbc7SAlexander Motin case PMC_CPU_INTEL_HASWELL: 753ae57fbc7SAlexander Motin case PMC_CPU_INTEL_HASWELL_XEON: 754ae57fbc7SAlexander Motin case PMC_CPU_INTEL_BROADWELL: 755ae57fbc7SAlexander Motin case PMC_CPU_INTEL_BROADWELL_XEON: 756ae57fbc7SAlexander Motin if (iap_event_sb_sbx_ib_ibx_ok_on_counter(ev, ri) == 0) 7570cfab8ddSJoseph Koshy return (EINVAL); 758ae57fbc7SAlexander Motin break; 759ae57fbc7SAlexander Motin case PMC_CPU_INTEL_ATOM: 760ae57fbc7SAlexander Motin case PMC_CPU_INTEL_ATOM_SILVERMONT: 761ae57fbc7SAlexander Motin case PMC_CPU_INTEL_ATOM_GOLDMONT: 76213260178SAlexander Motin case PMC_CPU_INTEL_ATOM_GOLDMONT_P: 76313260178SAlexander Motin case PMC_CPU_INTEL_ATOM_TREMONT: 764ae57fbc7SAlexander Motin case PMC_CPU_INTEL_SKYLAKE: 765ae57fbc7SAlexander Motin case PMC_CPU_INTEL_SKYLAKE_XEON: 766ae57fbc7SAlexander Motin case PMC_CPU_INTEL_ICELAKE: 767ae57fbc7SAlexander Motin case PMC_CPU_INTEL_ICELAKE_XEON: 768fe109d31SAlexander Motin case PMC_CPU_INTEL_ALDERLAKE: 769ae57fbc7SAlexander Motin default: 770ae57fbc7SAlexander Motin break; 7711fa7f10bSFabien Thomas } 7720cfab8ddSJoseph Koshy 773959826caSMatt Macy pm->pm_md.pm_iap.pm_iap_evsel = iap->pm_iap_config; 7740cfab8ddSJoseph Koshy return (0); 7750cfab8ddSJoseph Koshy } 7760cfab8ddSJoseph Koshy 7770cfab8ddSJoseph Koshy static int 7780cfab8ddSJoseph Koshy iap_config_pmc(int cpu, int ri, struct pmc *pm) 7790cfab8ddSJoseph Koshy { 7800cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 7810cfab8ddSJoseph Koshy ("[core,%d] illegal CPU %d", __LINE__, cpu)); 7820cfab8ddSJoseph Koshy 7830cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 7840cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 7850cfab8ddSJoseph Koshy 7864a3690dfSJohn Baldwin PMCDBG3(MDP,CFG,1, "iap-config cpu=%d ri=%d pm=%p", cpu, ri, pm); 7870cfab8ddSJoseph Koshy 7880cfab8ddSJoseph Koshy KASSERT(core_pcpu[cpu] != NULL, ("[core,%d] null per-cpu %d", __LINE__, 7890cfab8ddSJoseph Koshy cpu)); 7900cfab8ddSJoseph Koshy 7910cfab8ddSJoseph Koshy core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc = pm; 7920cfab8ddSJoseph Koshy 7930cfab8ddSJoseph Koshy return (0); 7940cfab8ddSJoseph Koshy } 7950cfab8ddSJoseph Koshy 7960cfab8ddSJoseph Koshy static int 7970cfab8ddSJoseph Koshy iap_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 7980cfab8ddSJoseph Koshy { 7990cfab8ddSJoseph Koshy struct pmc_hw *phw; 8000cfab8ddSJoseph Koshy 8010cfab8ddSJoseph Koshy phw = &core_pcpu[cpu]->pc_corepmcs[ri]; 8020cfab8ddSJoseph Koshy 80331610e34SMitchell Horne snprintf(pi->pm_name, sizeof(pi->pm_name), "IAP-%d", ri); 8040cfab8ddSJoseph Koshy pi->pm_class = PMC_CLASS_IAP; 8050cfab8ddSJoseph Koshy 8060cfab8ddSJoseph Koshy if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 8070cfab8ddSJoseph Koshy pi->pm_enabled = TRUE; 8080cfab8ddSJoseph Koshy *ppmc = phw->phw_pmc; 8090cfab8ddSJoseph Koshy } else { 8100cfab8ddSJoseph Koshy pi->pm_enabled = FALSE; 8110cfab8ddSJoseph Koshy *ppmc = NULL; 8120cfab8ddSJoseph Koshy } 8130cfab8ddSJoseph Koshy 8140cfab8ddSJoseph Koshy return (0); 8150cfab8ddSJoseph Koshy } 8160cfab8ddSJoseph Koshy 8170cfab8ddSJoseph Koshy static int 8180cfab8ddSJoseph Koshy iap_get_config(int cpu, int ri, struct pmc **ppm) 8190cfab8ddSJoseph Koshy { 8200cfab8ddSJoseph Koshy *ppm = core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc; 8210cfab8ddSJoseph Koshy 8220cfab8ddSJoseph Koshy return (0); 8230cfab8ddSJoseph Koshy } 8240cfab8ddSJoseph Koshy 8250cfab8ddSJoseph Koshy static int 8260cfab8ddSJoseph Koshy iap_get_msr(int ri, uint32_t *msr) 8270cfab8ddSJoseph Koshy { 8280cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 8290cfab8ddSJoseph Koshy ("[iap,%d] ri %d out of range", __LINE__, ri)); 8300cfab8ddSJoseph Koshy 8310cfab8ddSJoseph Koshy *msr = ri; 8320cfab8ddSJoseph Koshy 8330cfab8ddSJoseph Koshy return (0); 8340cfab8ddSJoseph Koshy } 8350cfab8ddSJoseph Koshy 8360cfab8ddSJoseph Koshy static int 83739f92a76SMitchell Horne iap_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v) 8380cfab8ddSJoseph Koshy { 8390cfab8ddSJoseph Koshy pmc_value_t tmp; 8400cfab8ddSJoseph Koshy 8410cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 8420cfab8ddSJoseph Koshy ("[core,%d] illegal cpu value %d", __LINE__, cpu)); 8430cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 8440cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 8450cfab8ddSJoseph Koshy 8460cfab8ddSJoseph Koshy tmp = rdpmc(ri); 8470cfab8ddSJoseph Koshy if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 8480cfab8ddSJoseph Koshy *v = iap_perfctr_value_to_reload_count(tmp); 8490cfab8ddSJoseph Koshy else 850a7ef8bbbSGeorge V. Neville-Neil *v = tmp & ((1ULL << core_iap_width) - 1); 8510cfab8ddSJoseph Koshy 8524a3690dfSJohn Baldwin PMCDBG4(MDP,REA,1, "iap-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri, 853411c83ccSKonstantin Belousov IAP_PMC0 + ri, *v); 8540cfab8ddSJoseph Koshy 8550cfab8ddSJoseph Koshy return (0); 8560cfab8ddSJoseph Koshy } 8570cfab8ddSJoseph Koshy 8580cfab8ddSJoseph Koshy static int 8590cfab8ddSJoseph Koshy iap_release_pmc(int cpu, int ri, struct pmc *pm) 8600cfab8ddSJoseph Koshy { 8610cfab8ddSJoseph Koshy (void) pm; 8620cfab8ddSJoseph Koshy 8634a3690dfSJohn Baldwin PMCDBG3(MDP,REL,1, "iap-release cpu=%d ri=%d pm=%p", cpu, ri, 8640cfab8ddSJoseph Koshy pm); 8650cfab8ddSJoseph Koshy 8660cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 8670cfab8ddSJoseph Koshy ("[core,%d] illegal CPU value %d", __LINE__, cpu)); 8680cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 8690cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 8700cfab8ddSJoseph Koshy 8710cfab8ddSJoseph Koshy KASSERT(core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc 8720cfab8ddSJoseph Koshy == NULL, ("[core,%d] PHW pmc non-NULL", __LINE__)); 8730cfab8ddSJoseph Koshy 8740cfab8ddSJoseph Koshy return (0); 8750cfab8ddSJoseph Koshy } 8760cfab8ddSJoseph Koshy 8770cfab8ddSJoseph Koshy static int 87839f92a76SMitchell Horne iap_start_pmc(int cpu, int ri, struct pmc *pm) 8790cfab8ddSJoseph Koshy { 8801a4614a5SAlexander Motin uint64_t evsel; 8810cfab8ddSJoseph Koshy struct core_cpu *cc; 8820cfab8ddSJoseph Koshy 8830cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 8840cfab8ddSJoseph Koshy ("[core,%d] illegal CPU value %d", __LINE__, cpu)); 8850cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 8860cfab8ddSJoseph Koshy ("[core,%d] illegal row-index %d", __LINE__, ri)); 8870cfab8ddSJoseph Koshy 8880cfab8ddSJoseph Koshy cc = core_pcpu[cpu]; 8890cfab8ddSJoseph Koshy 8904a3690dfSJohn Baldwin PMCDBG2(MDP,STA,1, "iap-start cpu=%d ri=%d", cpu, ri); 8910cfab8ddSJoseph Koshy 8920cfab8ddSJoseph Koshy evsel = pm->pm_md.pm_iap.pm_iap_evsel; 8930cfab8ddSJoseph Koshy 8944a3690dfSJohn Baldwin PMCDBG4(MDP,STA,2, "iap-start/2 cpu=%d ri=%d evselmsr=0x%x evsel=0x%x", 8950cfab8ddSJoseph Koshy cpu, ri, IAP_EVSEL0 + ri, evsel); 8960cfab8ddSJoseph Koshy 8971fa7f10bSFabien Thomas /* Event specific configuration. */ 898959826caSMatt Macy 899959826caSMatt Macy switch (IAP_EVSEL_GET(evsel)) { 900959826caSMatt Macy case 0xB7: 9011fa7f10bSFabien Thomas wrmsr(IA_OFFCORE_RSP0, pm->pm_md.pm_iap.pm_iap_rsp); 9021fa7f10bSFabien Thomas break; 903959826caSMatt Macy case 0xBB: 9041fa7f10bSFabien Thomas wrmsr(IA_OFFCORE_RSP1, pm->pm_md.pm_iap.pm_iap_rsp); 9051fa7f10bSFabien Thomas break; 9061fa7f10bSFabien Thomas default: 9071fa7f10bSFabien Thomas break; 9081fa7f10bSFabien Thomas } 9091fa7f10bSFabien Thomas 9100cfab8ddSJoseph Koshy wrmsr(IAP_EVSEL0 + ri, evsel | IAP_EN); 9110cfab8ddSJoseph Koshy 91281ffb45fSAlexander Motin if (core_version >= 2) { 9130cfab8ddSJoseph Koshy cc->pc_globalctrl |= (1ULL << ri); 9140cfab8ddSJoseph Koshy wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl); 91581ffb45fSAlexander Motin } 9160cfab8ddSJoseph Koshy 9170cfab8ddSJoseph Koshy return (0); 9180cfab8ddSJoseph Koshy } 9190cfab8ddSJoseph Koshy 9200cfab8ddSJoseph Koshy static int 92139f92a76SMitchell Horne iap_stop_pmc(int cpu, int ri, struct pmc *pm __unused) 9220cfab8ddSJoseph Koshy { 9230cfab8ddSJoseph Koshy 9240cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 9250cfab8ddSJoseph Koshy ("[core,%d] illegal cpu value %d", __LINE__, cpu)); 9260cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 9270cfab8ddSJoseph Koshy ("[core,%d] illegal row index %d", __LINE__, ri)); 9280cfab8ddSJoseph Koshy 9294a3690dfSJohn Baldwin PMCDBG2(MDP,STO,1, "iap-stop cpu=%d ri=%d", cpu, ri); 9300cfab8ddSJoseph Koshy 93181ffb45fSAlexander Motin wrmsr(IAP_EVSEL0 + ri, 0); 9320cfab8ddSJoseph Koshy 933326a8d3eSAlexander Motin /* Don't need to write IA_GLOBAL_CTRL, one disable is enough. */ 9340cfab8ddSJoseph Koshy 9350cfab8ddSJoseph Koshy return (0); 9360cfab8ddSJoseph Koshy } 9370cfab8ddSJoseph Koshy 9380cfab8ddSJoseph Koshy static int 93939f92a76SMitchell Horne iap_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v) 9400cfab8ddSJoseph Koshy { 9410cfab8ddSJoseph Koshy 9420cfab8ddSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 9430cfab8ddSJoseph Koshy ("[core,%d] illegal cpu value %d", __LINE__, cpu)); 9440cfab8ddSJoseph Koshy KASSERT(ri >= 0 && ri < core_iap_npmc, 9450cfab8ddSJoseph Koshy ("[core,%d] illegal row index %d", __LINE__, ri)); 9460cfab8ddSJoseph Koshy 9470cfab8ddSJoseph Koshy if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 9480cfab8ddSJoseph Koshy v = iap_reload_count_to_perfctr_value(v); 9490cfab8ddSJoseph Koshy 950411c83ccSKonstantin Belousov v &= (1ULL << core_iap_width) - 1; 951411c83ccSKonstantin Belousov 952411c83ccSKonstantin Belousov PMCDBG4(MDP,WRI,1, "iap-write cpu=%d ri=%d msr=0x%x v=%jx", cpu, ri, 953411c83ccSKonstantin Belousov IAP_PMC0 + ri, v); 954411c83ccSKonstantin Belousov 9550cfab8ddSJoseph Koshy /* 956411c83ccSKonstantin Belousov * Write the new value to the counter (or it's alias). The 957411c83ccSKonstantin Belousov * counter will be in a stopped state when the pcd_write() 958411c83ccSKonstantin Belousov * entry point is called. 9590cfab8ddSJoseph Koshy */ 960411c83ccSKonstantin Belousov wrmsr(core_iap_wroffset + IAP_PMC0 + ri, v); 9610cfab8ddSJoseph Koshy return (0); 9620cfab8ddSJoseph Koshy } 9630cfab8ddSJoseph Koshy 9640cfab8ddSJoseph Koshy 9650cfab8ddSJoseph Koshy static void 9660cfab8ddSJoseph Koshy iap_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth, 9670cfab8ddSJoseph Koshy int flags) 9680cfab8ddSJoseph Koshy { 9690cfab8ddSJoseph Koshy struct pmc_classdep *pcd; 9700cfab8ddSJoseph Koshy 9710cfab8ddSJoseph Koshy KASSERT(md != NULL, ("[iap,%d] md is NULL", __LINE__)); 9720cfab8ddSJoseph Koshy 9734a3690dfSJohn Baldwin PMCDBG0(MDP,INI,1, "iap-initialize"); 9740cfab8ddSJoseph Koshy 9750cfab8ddSJoseph Koshy /* Remember the set of architectural events supported. */ 9760cfab8ddSJoseph Koshy core_architectural_events = ~flags; 9770cfab8ddSJoseph Koshy 9780cfab8ddSJoseph Koshy pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP]; 9790cfab8ddSJoseph Koshy 9800cfab8ddSJoseph Koshy pcd->pcd_caps = IAP_PMC_CAPS; 9810cfab8ddSJoseph Koshy pcd->pcd_class = PMC_CLASS_IAP; 9820cfab8ddSJoseph Koshy pcd->pcd_num = npmc; 9830cfab8ddSJoseph Koshy pcd->pcd_ri = md->pmd_npmc; 9840cfab8ddSJoseph Koshy pcd->pcd_width = pmcwidth; 9850cfab8ddSJoseph Koshy 9860cfab8ddSJoseph Koshy pcd->pcd_allocate_pmc = iap_allocate_pmc; 9870cfab8ddSJoseph Koshy pcd->pcd_config_pmc = iap_config_pmc; 9880cfab8ddSJoseph Koshy pcd->pcd_describe = iap_describe; 9890cfab8ddSJoseph Koshy pcd->pcd_get_config = iap_get_config; 9900cfab8ddSJoseph Koshy pcd->pcd_get_msr = iap_get_msr; 9910cfab8ddSJoseph Koshy pcd->pcd_pcpu_fini = core_pcpu_fini; 9920cfab8ddSJoseph Koshy pcd->pcd_pcpu_init = core_pcpu_init; 9930cfab8ddSJoseph Koshy pcd->pcd_read_pmc = iap_read_pmc; 9940cfab8ddSJoseph Koshy pcd->pcd_release_pmc = iap_release_pmc; 9950cfab8ddSJoseph Koshy pcd->pcd_start_pmc = iap_start_pmc; 9960cfab8ddSJoseph Koshy pcd->pcd_stop_pmc = iap_stop_pmc; 9970cfab8ddSJoseph Koshy pcd->pcd_write_pmc = iap_write_pmc; 9980cfab8ddSJoseph Koshy 9990cfab8ddSJoseph Koshy md->pmd_npmc += npmc; 10000cfab8ddSJoseph Koshy } 10010cfab8ddSJoseph Koshy 10020cfab8ddSJoseph Koshy static int 1003eb7c9019SMatt Macy core_intr(struct trapframe *tf) 10040cfab8ddSJoseph Koshy { 10050cfab8ddSJoseph Koshy pmc_value_t v; 10060cfab8ddSJoseph Koshy struct pmc *pm; 10070cfab8ddSJoseph Koshy struct core_cpu *cc; 10080cfab8ddSJoseph Koshy int error, found_interrupt, ri; 10090cfab8ddSJoseph Koshy 10102075d00fSEd Maste PMCDBG3(MDP,INT, 1, "cpu=%d tf=%p um=%d", curcpu, (void *) tf, 10110cfab8ddSJoseph Koshy TRAPF_USERMODE(tf)); 10120cfab8ddSJoseph Koshy 10138d8b1740SJoseph Koshy found_interrupt = 0; 1014eb7c9019SMatt Macy cc = core_pcpu[curcpu]; 10150cfab8ddSJoseph Koshy 10160cfab8ddSJoseph Koshy for (ri = 0; ri < core_iap_npmc; ri++) { 10170cfab8ddSJoseph Koshy 10180cfab8ddSJoseph Koshy if ((pm = cc->pc_corepmcs[ri].phw_pmc) == NULL || 10190cfab8ddSJoseph Koshy !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 10200cfab8ddSJoseph Koshy continue; 10210cfab8ddSJoseph Koshy 10228d8b1740SJoseph Koshy if (!iap_pmc_has_overflowed(ri)) 10238d8b1740SJoseph Koshy continue; 10248d8b1740SJoseph Koshy 10250cfab8ddSJoseph Koshy found_interrupt = 1; 10260cfab8ddSJoseph Koshy 10270cfab8ddSJoseph Koshy if (pm->pm_state != PMC_STATE_RUNNING) 10280cfab8ddSJoseph Koshy continue; 10290cfab8ddSJoseph Koshy 1030eb7c9019SMatt Macy error = pmc_process_interrupt(PMC_HR, pm, tf); 10310cfab8ddSJoseph Koshy 10320cfab8ddSJoseph Koshy v = pm->pm_sc.pm_reloadcount; 10332b1df86cSJohn Baldwin v = iap_reload_count_to_perfctr_value(v); 10340cfab8ddSJoseph Koshy 10350cfab8ddSJoseph Koshy /* 10360cfab8ddSJoseph Koshy * Stop the counter, reload it but only restart it if 10370cfab8ddSJoseph Koshy * the PMC is not stalled. 10380cfab8ddSJoseph Koshy */ 103981ffb45fSAlexander Motin wrmsr(IAP_EVSEL0 + ri, pm->pm_md.pm_iap.pm_iap_evsel); 1040411c83ccSKonstantin Belousov wrmsr(core_iap_wroffset + IAP_PMC0 + ri, v); 10410cfab8ddSJoseph Koshy 104281ffb45fSAlexander Motin if (__predict_false(error)) 10430cfab8ddSJoseph Koshy continue; 10440cfab8ddSJoseph Koshy 104581ffb45fSAlexander Motin wrmsr(IAP_EVSEL0 + ri, pm->pm_md.pm_iap.pm_iap_evsel | IAP_EN); 10460cfab8ddSJoseph Koshy } 10470cfab8ddSJoseph Koshy 10480cfab8ddSJoseph Koshy if (found_interrupt) 1049e6b475e0SMatt Macy counter_u64_add(pmc_stats.pm_intr_processed, 1); 1050e6b475e0SMatt Macy else 1051e6b475e0SMatt Macy counter_u64_add(pmc_stats.pm_intr_ignored, 1); 10520cfab8ddSJoseph Koshy 105381ffb45fSAlexander Motin if (found_interrupt) 1054*04e83267SBojan Novković lapic_reenable_pcint(); 105581ffb45fSAlexander Motin 10560cfab8ddSJoseph Koshy return (found_interrupt); 10570cfab8ddSJoseph Koshy } 10580cfab8ddSJoseph Koshy 10590cfab8ddSJoseph Koshy static int 1060eb7c9019SMatt Macy core2_intr(struct trapframe *tf) 10610cfab8ddSJoseph Koshy { 106281ffb45fSAlexander Motin int error, found_interrupt = 0, n, cpu; 106381ffb45fSAlexander Motin uint64_t flag, intrstatus, intrdisable = 0; 10640cfab8ddSJoseph Koshy struct pmc *pm; 10650cfab8ddSJoseph Koshy struct core_cpu *cc; 10660cfab8ddSJoseph Koshy pmc_value_t v; 10670cfab8ddSJoseph Koshy 106897891010SMatt Macy cpu = curcpu; 10694a3690dfSJohn Baldwin PMCDBG3(MDP,INT, 1, "cpu=%d tf=0x%p um=%d", cpu, (void *) tf, 10700cfab8ddSJoseph Koshy TRAPF_USERMODE(tf)); 10710cfab8ddSJoseph Koshy 10720cfab8ddSJoseph Koshy /* 10730cfab8ddSJoseph Koshy * The IA_GLOBAL_STATUS (MSR 0x38E) register indicates which 10740cfab8ddSJoseph Koshy * PMCs have a pending PMI interrupt. We take a 'snapshot' of 10750cfab8ddSJoseph Koshy * the current set of interrupting PMCs and process these 10760cfab8ddSJoseph Koshy * after stopping them. 10770cfab8ddSJoseph Koshy */ 10780cfab8ddSJoseph Koshy intrstatus = rdmsr(IA_GLOBAL_STATUS); 10794a3690dfSJohn Baldwin PMCDBG2(MDP,INT, 1, "cpu=%d intrstatus=%jx", cpu, 10800cfab8ddSJoseph Koshy (uintmax_t) intrstatus); 10810cfab8ddSJoseph Koshy 10820cfab8ddSJoseph Koshy /* 108381ffb45fSAlexander Motin * Stop PMCs unless hardware already done it. 10840cfab8ddSJoseph Koshy */ 108581ffb45fSAlexander Motin if ((intrstatus & IA_GLOBAL_STATUS_FLAG_CTR_FRZ) == 0) 108681ffb45fSAlexander Motin wrmsr(IA_GLOBAL_CTRL, 0); 108781ffb45fSAlexander Motin 108881ffb45fSAlexander Motin cc = core_pcpu[cpu]; 108981ffb45fSAlexander Motin KASSERT(cc != NULL, ("[core,%d] null pcpu", __LINE__)); 10900cfab8ddSJoseph Koshy 10910cfab8ddSJoseph Koshy /* 10920cfab8ddSJoseph Koshy * Look for interrupts from fixed function PMCs. 10930cfab8ddSJoseph Koshy */ 10940cfab8ddSJoseph Koshy for (n = 0, flag = (1ULL << IAF_OFFSET); n < core_iaf_npmc; 10950cfab8ddSJoseph Koshy n++, flag <<= 1) { 10960cfab8ddSJoseph Koshy 10970cfab8ddSJoseph Koshy if ((intrstatus & flag) == 0) 10980cfab8ddSJoseph Koshy continue; 10990cfab8ddSJoseph Koshy 11000cfab8ddSJoseph Koshy found_interrupt = 1; 11010cfab8ddSJoseph Koshy 11020cfab8ddSJoseph Koshy pm = cc->pc_corepmcs[n + core_iaf_ri].phw_pmc; 11030cfab8ddSJoseph Koshy if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING || 11040cfab8ddSJoseph Koshy !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 11050cfab8ddSJoseph Koshy continue; 11060cfab8ddSJoseph Koshy 1107eb7c9019SMatt Macy error = pmc_process_interrupt(PMC_HR, pm, tf); 110881ffb45fSAlexander Motin if (__predict_false(error)) 110981ffb45fSAlexander Motin intrdisable |= flag; 11100cfab8ddSJoseph Koshy 11110cfab8ddSJoseph Koshy v = iaf_reload_count_to_perfctr_value(pm->pm_sc.pm_reloadcount); 11120cfab8ddSJoseph Koshy 11130cfab8ddSJoseph Koshy /* Reload sampling count. */ 11140cfab8ddSJoseph Koshy wrmsr(IAF_CTR0 + n, v); 11150cfab8ddSJoseph Koshy 1116eb7c9019SMatt Macy PMCDBG4(MDP,INT, 1, "iaf-intr cpu=%d error=%d v=%jx(%jx)", curcpu, 11174b226201SSean Bruno error, (uintmax_t) v, (uintmax_t) rdpmc(IAF_RI_TO_MSR(n))); 11180cfab8ddSJoseph Koshy } 11190cfab8ddSJoseph Koshy 11200cfab8ddSJoseph Koshy /* 11210cfab8ddSJoseph Koshy * Process interrupts from the programmable counters. 11220cfab8ddSJoseph Koshy */ 11230cfab8ddSJoseph Koshy for (n = 0, flag = 1; n < core_iap_npmc; n++, flag <<= 1) { 11240cfab8ddSJoseph Koshy if ((intrstatus & flag) == 0) 11250cfab8ddSJoseph Koshy continue; 11260cfab8ddSJoseph Koshy 11270cfab8ddSJoseph Koshy found_interrupt = 1; 11280cfab8ddSJoseph Koshy 11290cfab8ddSJoseph Koshy pm = cc->pc_corepmcs[n].phw_pmc; 11300cfab8ddSJoseph Koshy if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING || 11310cfab8ddSJoseph Koshy !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 11320cfab8ddSJoseph Koshy continue; 11330cfab8ddSJoseph Koshy 1134eb7c9019SMatt Macy error = pmc_process_interrupt(PMC_HR, pm, tf); 113581ffb45fSAlexander Motin if (__predict_false(error)) 113681ffb45fSAlexander Motin intrdisable |= flag; 11370cfab8ddSJoseph Koshy 11380cfab8ddSJoseph Koshy v = iap_reload_count_to_perfctr_value(pm->pm_sc.pm_reloadcount); 11390cfab8ddSJoseph Koshy 11404a3690dfSJohn Baldwin PMCDBG3(MDP,INT, 1, "iap-intr cpu=%d error=%d v=%jx", cpu, error, 11410cfab8ddSJoseph Koshy (uintmax_t) v); 11420cfab8ddSJoseph Koshy 11430cfab8ddSJoseph Koshy /* Reload sampling count. */ 1144411c83ccSKonstantin Belousov wrmsr(core_iap_wroffset + IAP_PMC0 + n, v); 11450cfab8ddSJoseph Koshy } 11460cfab8ddSJoseph Koshy 1147e6b475e0SMatt Macy if (found_interrupt) 1148e6b475e0SMatt Macy counter_u64_add(pmc_stats.pm_intr_processed, 1); 1149e6b475e0SMatt Macy else 1150e6b475e0SMatt Macy counter_u64_add(pmc_stats.pm_intr_ignored, 1); 11510cfab8ddSJoseph Koshy 1152f9e62419SAlexander Motin if (found_interrupt) 1153*04e83267SBojan Novković lapic_reenable_pcint(); 1154f9e62419SAlexander Motin 115581ffb45fSAlexander Motin /* 115681ffb45fSAlexander Motin * Reenable all non-stalled PMCs. 115781ffb45fSAlexander Motin */ 115881ffb45fSAlexander Motin if ((intrstatus & IA_GLOBAL_STATUS_FLAG_CTR_FRZ) == 0) { 115981ffb45fSAlexander Motin wrmsr(IA_GLOBAL_OVF_CTRL, intrstatus); 116081ffb45fSAlexander Motin cc->pc_globalctrl &= ~intrdisable; 116181ffb45fSAlexander Motin wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl); 116281ffb45fSAlexander Motin } else { 116381ffb45fSAlexander Motin if (__predict_false(intrdisable)) { 116481ffb45fSAlexander Motin cc->pc_globalctrl &= ~intrdisable; 116581ffb45fSAlexander Motin wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl); 116681ffb45fSAlexander Motin } 116781ffb45fSAlexander Motin wrmsr(IA_GLOBAL_OVF_CTRL, intrstatus); 116881ffb45fSAlexander Motin } 116981ffb45fSAlexander Motin 117081ffb45fSAlexander Motin PMCDBG4(MDP, INT, 1, "cpu=%d fixedctrl=%jx globalctrl=%jx status=%jx", 117181ffb45fSAlexander Motin cpu, (uintmax_t) rdmsr(IAF_CTRL), 117281ffb45fSAlexander Motin (uintmax_t) rdmsr(IA_GLOBAL_CTRL), 117381ffb45fSAlexander Motin (uintmax_t) rdmsr(IA_GLOBAL_STATUS)); 117481ffb45fSAlexander Motin 11750cfab8ddSJoseph Koshy return (found_interrupt); 11760cfab8ddSJoseph Koshy } 11770cfab8ddSJoseph Koshy 11780cfab8ddSJoseph Koshy int 1179026346c8SAttilio Rao pmc_core_initialize(struct pmc_mdep *md, int maxcpu, int version_override) 11800cfab8ddSJoseph Koshy { 11810cfab8ddSJoseph Koshy int cpuid[CORE_CPUID_REQUEST_SIZE]; 118281ffb45fSAlexander Motin int flags, nflags; 11830cfab8ddSJoseph Koshy 11840cfab8ddSJoseph Koshy do_cpuid(CORE_CPUID_REQUEST, cpuid); 11850cfab8ddSJoseph Koshy 1186026346c8SAttilio Rao core_cputype = md->pmd_cputype; 118781ffb45fSAlexander Motin core_version = (version_override > 0) ? version_override : 118881ffb45fSAlexander Motin cpuid[CORE_CPUID_EAX] & 0xFF; 11890cfab8ddSJoseph Koshy 119081ffb45fSAlexander Motin PMCDBG3(MDP,INI,1,"core-init cputype=%d ncpu=%d version=%d", 119181ffb45fSAlexander Motin core_cputype, maxcpu, core_version); 11920cfab8ddSJoseph Koshy 119381ffb45fSAlexander Motin if (core_version < 1 || core_version > 5 || 119481ffb45fSAlexander Motin (core_cputype != PMC_CPU_INTEL_CORE && core_version == 1)) { 1195ef902782SOleksandr Tymoshenko /* Unknown PMC architecture. */ 119656da525bSMark Johnston printf("hwpmc_core: unknown PMC architecture: %d\n", 119781ffb45fSAlexander Motin core_version); 11980cfab8ddSJoseph Koshy return (EPROGMISMATCH); 1199ef902782SOleksandr Tymoshenko } 12000cfab8ddSJoseph Koshy 1201411c83ccSKonstantin Belousov core_iap_wroffset = 0; 1202411c83ccSKonstantin Belousov if (cpu_feature2 & CPUID2_PDCM) { 1203411c83ccSKonstantin Belousov if (rdmsr(IA32_PERF_CAPABILITIES) & PERFCAP_FW_WRITE) { 1204411c83ccSKonstantin Belousov PMCDBG0(MDP, INI, 1, 1205411c83ccSKonstantin Belousov "core-init full-width write supported"); 1206411c83ccSKonstantin Belousov core_iap_wroffset = IAP_A_PMC0 - IAP_PMC0; 1207411c83ccSKonstantin Belousov } else 1208411c83ccSKonstantin Belousov PMCDBG0(MDP, INI, 1, 1209411c83ccSKonstantin Belousov "core-init full-width write NOT supported"); 1210411c83ccSKonstantin Belousov } else 1211411c83ccSKonstantin Belousov PMCDBG0(MDP, INI, 1, "core-init pdcm not supported"); 1212411c83ccSKonstantin Belousov 12130cfab8ddSJoseph Koshy core_pmcmask = 0; 12140cfab8ddSJoseph Koshy 12150cfab8ddSJoseph Koshy /* 12160cfab8ddSJoseph Koshy * Initialize programmable counters. 12170cfab8ddSJoseph Koshy */ 12180cfab8ddSJoseph Koshy core_iap_npmc = (cpuid[CORE_CPUID_EAX] >> 8) & 0xFF; 12190cfab8ddSJoseph Koshy core_iap_width = (cpuid[CORE_CPUID_EAX] >> 16) & 0xFF; 12200cfab8ddSJoseph Koshy 12210cfab8ddSJoseph Koshy core_pmcmask |= ((1ULL << core_iap_npmc) - 1); 12220cfab8ddSJoseph Koshy 12230cfab8ddSJoseph Koshy nflags = (cpuid[CORE_CPUID_EAX] >> 24) & 0xFF; 12240cfab8ddSJoseph Koshy flags = cpuid[CORE_CPUID_EBX] & ((1 << nflags) - 1); 12250cfab8ddSJoseph Koshy 12260cfab8ddSJoseph Koshy iap_initialize(md, maxcpu, core_iap_npmc, core_iap_width, flags); 12270cfab8ddSJoseph Koshy 12280cfab8ddSJoseph Koshy /* 12290cfab8ddSJoseph Koshy * Initialize fixed function counters, if present. 12300cfab8ddSJoseph Koshy */ 123181ffb45fSAlexander Motin if (core_version >= 2) { 12320cfab8ddSJoseph Koshy core_iaf_ri = core_iap_npmc; 12330cfab8ddSJoseph Koshy core_iaf_npmc = cpuid[CORE_CPUID_EDX] & 0x1F; 12340cfab8ddSJoseph Koshy core_iaf_width = (cpuid[CORE_CPUID_EDX] >> 5) & 0xFF; 12350cfab8ddSJoseph Koshy 12362aef9dd6SFabien Thomas iaf_initialize(md, maxcpu, core_iaf_npmc, core_iaf_width); 12372aef9dd6SFabien Thomas core_pmcmask |= ((1ULL << core_iaf_npmc) - 1) << IAF_OFFSET; 12380cfab8ddSJoseph Koshy } 12390cfab8ddSJoseph Koshy 12404a3690dfSJohn Baldwin PMCDBG2(MDP,INI,1,"core-init pmcmask=0x%jx iafri=%d", core_pmcmask, 12410cfab8ddSJoseph Koshy core_iaf_ri); 12420cfab8ddSJoseph Koshy 124377937873SEitan Adler core_pcpu = malloc(sizeof(*core_pcpu) * maxcpu, M_PMC, 12440cfab8ddSJoseph Koshy M_ZERO | M_WAITOK); 12450cfab8ddSJoseph Koshy 12460cfab8ddSJoseph Koshy /* 12470cfab8ddSJoseph Koshy * Choose the appropriate interrupt handler. 12480cfab8ddSJoseph Koshy */ 124981ffb45fSAlexander Motin if (core_version >= 2) 12500cfab8ddSJoseph Koshy md->pmd_intr = core2_intr; 125181ffb45fSAlexander Motin else 125281ffb45fSAlexander Motin md->pmd_intr = core_intr; 12530cfab8ddSJoseph Koshy 12540cfab8ddSJoseph Koshy return (0); 12550cfab8ddSJoseph Koshy } 12560cfab8ddSJoseph Koshy 12570cfab8ddSJoseph Koshy void 12580cfab8ddSJoseph Koshy pmc_core_finalize(struct pmc_mdep *md) 12590cfab8ddSJoseph Koshy { 12604a3690dfSJohn Baldwin PMCDBG0(MDP,INI,1, "core-finalize"); 12610cfab8ddSJoseph Koshy 126290a6ea5cSMitchell Horne for (int i = 0; i < pmc_cpu_max(); i++) 126390a6ea5cSMitchell Horne KASSERT(core_pcpu[i] == NULL, 126490a6ea5cSMitchell Horne ("[core,%d] non-null pcpu cpu %d", __LINE__, i)); 126590a6ea5cSMitchell Horne 12660cfab8ddSJoseph Koshy free(core_pcpu, M_PMC); 12670cfab8ddSJoseph Koshy core_pcpu = NULL; 12680cfab8ddSJoseph Koshy } 1269