hwpmc_uncore.c revision 234046
159743Sgroudier/*- 259743Sgroudier * Copyright (c) 2010 Fabien Thomas 359743Sgroudier * All rights reserved. 459743Sgroudier * 559743Sgroudier * Redistribution and use in source and binary forms, with or without 659743Sgroudier * modification, are permitted provided that the following conditions 759743Sgroudier * are met: 859743Sgroudier * 1. Redistributions of source code must retain the above copyright 959743Sgroudier * notice, this list of conditions and the following disclaimer. 1059743Sgroudier * 2. Redistributions in binary form must reproduce the above copyright 1159743Sgroudier * notice, this list of conditions and the following disclaimer in the 1259743Sgroudier * documentation and/or other materials provided with the distribution. 1359743Sgroudier * 1459743Sgroudier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559743Sgroudier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659743Sgroudier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759743Sgroudier * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859743Sgroudier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959743Sgroudier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059743Sgroudier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159743Sgroudier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259743Sgroudier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359743Sgroudier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459743Sgroudier * SUCH DAMAGE. 2559743Sgroudier */ 2659743Sgroudier 2759743Sgroudier/* 2859743Sgroudier * Intel Uncore PMCs. 2959743Sgroudier */ 3059743Sgroudier 3159743Sgroudier#include <sys/cdefs.h> 3259743Sgroudier__FBSDID("$FreeBSD: stable/9/sys/dev/hwpmc/hwpmc_uncore.c 234046 2012-04-08 21:29:48Z davide $"); 3359743Sgroudier 3459743Sgroudier#include <sys/param.h> 3559743Sgroudier#include <sys/bus.h> 3659743Sgroudier#include <sys/pmc.h> 3759743Sgroudier#include <sys/pmckern.h> 3859743Sgroudier#include <sys/systm.h> 3959743Sgroudier 4059743Sgroudier#include <machine/intr_machdep.h> 4159743Sgroudier#include <machine/apicvar.h> 4259743Sgroudier#include <machine/cpu.h> 4359743Sgroudier#include <machine/cpufunc.h> 4459743Sgroudier#include <machine/specialreg.h> 4559743Sgroudier 4659743Sgroudier#define UCF_PMC_CAPS \ 4759743Sgroudier (PMC_CAP_READ | PMC_CAP_WRITE) 4859743Sgroudier 4959743Sgroudier#define UCP_PMC_CAPS \ 5059743Sgroudier (PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \ 5159743Sgroudier PMC_CAP_INVERT | PMC_CAP_QUALIFIER | PMC_CAP_PRECISE) 5259743Sgroudier 5359743Sgroudier#define SELECTSEL(x) \ 5459743Sgroudier (((x) == PMC_CPU_INTEL_SANDYBRIDGE) ? UCP_CB0_EVSEL0 : UCP_EVSEL0) 5559743Sgroudier 5659743Sgroudier#define SELECTOFF(x) \ 5759743Sgroudier (((x) == PMC_CPU_INTEL_SANDYBRIDGE) ? UCF_OFFSET_SB : UCF_OFFSET) 5859743Sgroudier 5959743Sgroudierstatic enum pmc_cputype uncore_cputype; 6059743Sgroudier 6159743Sgroudierstruct uncore_cpu { 6259743Sgroudier volatile uint32_t pc_resync; 6359743Sgroudier volatile uint32_t pc_ucfctrl; /* Fixed function control. */ 6459743Sgroudier volatile uint64_t pc_globalctrl; /* Global control register. */ 6559743Sgroudier struct pmc_hw pc_uncorepmcs[]; 6659743Sgroudier}; 6759743Sgroudier 6859743Sgroudierstatic struct uncore_cpu **uncore_pcpu; 6959743Sgroudier 7059743Sgroudierstatic uint64_t uncore_pmcmask; 7159743Sgroudier 7259743Sgroudierstatic int uncore_ucf_ri; /* relative index of fixed counters */ 7359743Sgroudierstatic int uncore_ucf_width; 7459743Sgroudierstatic int uncore_ucf_npmc; 7559743Sgroudier 7659743Sgroudierstatic int uncore_ucp_width; 7759743Sgroudierstatic int uncore_ucp_npmc; 7859743Sgroudier 7959743Sgroudierstatic int 8059743Sgroudieruncore_pcpu_noop(struct pmc_mdep *md, int cpu) 8160134Sgroudier{ 8259743Sgroudier (void) md; 8359743Sgroudier (void) cpu; 8459743Sgroudier return (0); 8559743Sgroudier} 8659743Sgroudier 8759743Sgroudierstatic int 8859743Sgroudieruncore_pcpu_init(struct pmc_mdep *md, int cpu) 8959743Sgroudier{ 9059743Sgroudier struct pmc_cpu *pc; 9159743Sgroudier struct uncore_cpu *cc; 9259743Sgroudier struct pmc_hw *phw; 9359743Sgroudier int uncore_ri, n, npmc; 9459743Sgroudier 9559743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 9659743Sgroudier ("[ucf,%d] insane cpu number %d", __LINE__, cpu)); 9760134Sgroudier 9859743Sgroudier PMCDBG(MDP,INI,1,"uncore-init cpu=%d", cpu); 9959743Sgroudier 10059743Sgroudier uncore_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_ri; 10159743Sgroudier npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_num; 10259743Sgroudier npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCF].pcd_num; 10359743Sgroudier 10459743Sgroudier cc = malloc(sizeof(struct uncore_cpu) + npmc * sizeof(struct pmc_hw), 10559743Sgroudier M_PMC, M_WAITOK | M_ZERO); 10659743Sgroudier 10759743Sgroudier uncore_pcpu[cpu] = cc; 10859743Sgroudier pc = pmc_pcpu[cpu]; 10959743Sgroudier 11059743Sgroudier KASSERT(pc != NULL && cc != NULL, 11159743Sgroudier ("[uncore,%d] NULL per-cpu structures cpu=%d", __LINE__, cpu)); 11259743Sgroudier 11359743Sgroudier for (n = 0, phw = cc->pc_uncorepmcs; n < npmc; n++, phw++) { 11459743Sgroudier phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | 11559743Sgroudier PMC_PHW_CPU_TO_STATE(cpu) | 11659743Sgroudier PMC_PHW_INDEX_TO_STATE(n + uncore_ri); 11759743Sgroudier phw->phw_pmc = NULL; 11859743Sgroudier pc->pc_hwpmcs[n + uncore_ri] = phw; 11959743Sgroudier } 12059743Sgroudier 12159743Sgroudier return (0); 12259743Sgroudier} 12359743Sgroudier 12459743Sgroudierstatic int 12559743Sgroudieruncore_pcpu_fini(struct pmc_mdep *md, int cpu) 12659743Sgroudier{ 12759743Sgroudier int uncore_ri, n, npmc; 12859743Sgroudier struct pmc_cpu *pc; 12959743Sgroudier struct uncore_cpu *cc; 13059743Sgroudier 13159743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 13259743Sgroudier ("[uncore,%d] insane cpu number (%d)", __LINE__, cpu)); 13359743Sgroudier 13459743Sgroudier PMCDBG(MDP,INI,1,"uncore-pcpu-fini cpu=%d", cpu); 13559743Sgroudier 13659743Sgroudier if ((cc = uncore_pcpu[cpu]) == NULL) 13759743Sgroudier return (0); 13859743Sgroudier 13959743Sgroudier uncore_pcpu[cpu] = NULL; 14059743Sgroudier 14159743Sgroudier pc = pmc_pcpu[cpu]; 14259743Sgroudier 14359743Sgroudier KASSERT(pc != NULL, ("[uncore,%d] NULL per-cpu %d state", __LINE__, 14459743Sgroudier cpu)); 14559743Sgroudier 14659743Sgroudier npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_num; 14759743Sgroudier uncore_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_ri; 14859743Sgroudier 14959743Sgroudier for (n = 0; n < npmc; n++) 15059743Sgroudier wrmsr(SELECTSEL(uncore_cputype) + n, 0); 15159743Sgroudier 15259743Sgroudier wrmsr(UCF_CTRL, 0); 15359743Sgroudier npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCF].pcd_num; 15459743Sgroudier 15559743Sgroudier for (n = 0; n < npmc; n++) 15659743Sgroudier pc->pc_hwpmcs[n + uncore_ri] = NULL; 15759743Sgroudier 15859743Sgroudier free(cc, M_PMC); 15959743Sgroudier 16059743Sgroudier return (0); 16159743Sgroudier} 16259743Sgroudier 16359743Sgroudier/* 16459743Sgroudier * Fixed function counters. 16559743Sgroudier */ 16659743Sgroudier 16759743Sgroudierstatic pmc_value_t 16859743Sgroudierucf_perfctr_value_to_reload_count(pmc_value_t v) 16959743Sgroudier{ 17059743Sgroudier v &= (1ULL << uncore_ucf_width) - 1; 17159743Sgroudier return (1ULL << uncore_ucf_width) - v; 17259743Sgroudier} 17359743Sgroudier 17459743Sgroudierstatic pmc_value_t 17559743Sgroudierucf_reload_count_to_perfctr_value(pmc_value_t rlc) 17659743Sgroudier{ 17759743Sgroudier return (1ULL << uncore_ucf_width) - rlc; 17859743Sgroudier} 17959743Sgroudier 18059743Sgroudierstatic int 18159743Sgroudierucf_allocate_pmc(int cpu, int ri, struct pmc *pm, 18259743Sgroudier const struct pmc_op_pmcallocate *a) 18359743Sgroudier{ 18459743Sgroudier enum pmc_event ev; 18559743Sgroudier uint32_t caps, flags; 18659743Sgroudier 18759743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 18859743Sgroudier ("[uncore,%d] illegal CPU %d", __LINE__, cpu)); 18959743Sgroudier 19059743Sgroudier PMCDBG(MDP,ALL,1, "ucf-allocate ri=%d reqcaps=0x%x", ri, pm->pm_caps); 19159743Sgroudier 19259743Sgroudier if (ri < 0 || ri > uncore_ucf_npmc) 19359743Sgroudier return (EINVAL); 19459743Sgroudier 19559743Sgroudier caps = a->pm_caps; 19659743Sgroudier 19759743Sgroudier if (a->pm_class != PMC_CLASS_UCF || 19859743Sgroudier (caps & UCF_PMC_CAPS) != caps) 19959743Sgroudier return (EINVAL); 20059743Sgroudier 20159743Sgroudier ev = pm->pm_event; 20259743Sgroudier if (ev < PMC_EV_UCF_FIRST || ev > PMC_EV_UCF_LAST) 20359743Sgroudier return (EINVAL); 20459743Sgroudier 20559743Sgroudier flags = UCF_EN; 20659743Sgroudier 20759743Sgroudier pm->pm_md.pm_ucf.pm_ucf_ctrl = (flags << (ri * 4)); 20859743Sgroudier 20959743Sgroudier PMCDBG(MDP,ALL,2, "ucf-allocate config=0x%jx", 21059743Sgroudier (uintmax_t) pm->pm_md.pm_ucf.pm_ucf_ctrl); 21159743Sgroudier 21259743Sgroudier return (0); 21359743Sgroudier} 21459743Sgroudier 21559743Sgroudierstatic int 21659743Sgroudierucf_config_pmc(int cpu, int ri, struct pmc *pm) 21759743Sgroudier{ 21859743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 21959743Sgroudier ("[uncore,%d] illegal CPU %d", __LINE__, cpu)); 22059743Sgroudier 22159743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucf_npmc, 22259743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 22359743Sgroudier 22459743Sgroudier PMCDBG(MDP,CFG,1, "ucf-config cpu=%d ri=%d pm=%p", cpu, ri, pm); 22559743Sgroudier 22659743Sgroudier KASSERT(uncore_pcpu[cpu] != NULL, ("[uncore,%d] null per-cpu %d", __LINE__, 22759743Sgroudier cpu)); 22859743Sgroudier 22959743Sgroudier uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc = pm; 23059743Sgroudier 23159743Sgroudier return (0); 23259743Sgroudier} 23359743Sgroudier 23459743Sgroudierstatic int 23559743Sgroudierucf_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 23659743Sgroudier{ 23759743Sgroudier int error; 23859743Sgroudier struct pmc_hw *phw; 23959743Sgroudier char ucf_name[PMC_NAME_MAX]; 24059743Sgroudier 24159743Sgroudier phw = &uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri]; 24259743Sgroudier 24359743Sgroudier (void) snprintf(ucf_name, sizeof(ucf_name), "UCF-%d", ri); 24459743Sgroudier if ((error = copystr(ucf_name, pi->pm_name, PMC_NAME_MAX, 24559743Sgroudier NULL)) != 0) 24659743Sgroudier return (error); 24759743Sgroudier 24859743Sgroudier pi->pm_class = PMC_CLASS_UCF; 24959743Sgroudier 25059743Sgroudier if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 25159743Sgroudier pi->pm_enabled = TRUE; 25259743Sgroudier *ppmc = phw->phw_pmc; 25359743Sgroudier } else { 25459743Sgroudier pi->pm_enabled = FALSE; 25559743Sgroudier *ppmc = NULL; 25659743Sgroudier } 25759743Sgroudier 25859743Sgroudier return (0); 25959743Sgroudier} 26059743Sgroudier 26159743Sgroudierstatic int 26259743Sgroudierucf_get_config(int cpu, int ri, struct pmc **ppm) 26359743Sgroudier{ 26459743Sgroudier *ppm = uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc; 26559743Sgroudier 26659743Sgroudier return (0); 26759743Sgroudier} 26859743Sgroudier 26959743Sgroudierstatic int 27059743Sgroudierucf_read_pmc(int cpu, int ri, pmc_value_t *v) 27159743Sgroudier{ 27259743Sgroudier struct pmc *pm; 27359743Sgroudier pmc_value_t tmp; 27459743Sgroudier 27559743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 27659743Sgroudier ("[uncore,%d] illegal cpu value %d", __LINE__, cpu)); 27759743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucf_npmc, 27859743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 27959743Sgroudier 28059743Sgroudier pm = uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc; 28159743Sgroudier 28259743Sgroudier KASSERT(pm, 28359743Sgroudier ("[uncore,%d] cpu %d ri %d(%d) pmc not configured", __LINE__, cpu, 28459743Sgroudier ri, ri + uncore_ucf_ri)); 28559743Sgroudier 28659743Sgroudier tmp = rdmsr(UCF_CTR0 + ri); 28759743Sgroudier 28859743Sgroudier if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 28959743Sgroudier *v = ucf_perfctr_value_to_reload_count(tmp); 29059743Sgroudier else 29159743Sgroudier *v = tmp; 29259743Sgroudier 29359743Sgroudier PMCDBG(MDP,REA,1, "ucf-read cpu=%d ri=%d -> v=%jx", cpu, ri, *v); 29459743Sgroudier 29559743Sgroudier return (0); 29659743Sgroudier} 29759743Sgroudier 29859743Sgroudierstatic int 29959743Sgroudierucf_release_pmc(int cpu, int ri, struct pmc *pmc) 30059743Sgroudier{ 30159743Sgroudier PMCDBG(MDP,REL,1, "ucf-release cpu=%d ri=%d pm=%p", cpu, ri, pmc); 30259743Sgroudier 30359743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 30459743Sgroudier ("[uncore,%d] illegal CPU value %d", __LINE__, cpu)); 30559743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucf_npmc, 30659743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 30759743Sgroudier 30859743Sgroudier KASSERT(uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc == NULL, 30959743Sgroudier ("[uncore,%d] PHW pmc non-NULL", __LINE__)); 31059743Sgroudier 31159743Sgroudier return (0); 31259743Sgroudier} 31359743Sgroudier 31459743Sgroudierstatic int 31559743Sgroudierucf_start_pmc(int cpu, int ri) 31659743Sgroudier{ 31759743Sgroudier struct pmc *pm; 31859743Sgroudier struct uncore_cpu *ucfc; 31959743Sgroudier 32059743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 32159743Sgroudier ("[uncore,%d] illegal CPU value %d", __LINE__, cpu)); 32259743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucf_npmc, 32359743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 32459743Sgroudier 32559743Sgroudier PMCDBG(MDP,STA,1,"ucf-start cpu=%d ri=%d", cpu, ri); 32660134Sgroudier 32760134Sgroudier ucfc = uncore_pcpu[cpu]; 32860134Sgroudier pm = ucfc->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc; 32960134Sgroudier 33060134Sgroudier ucfc->pc_ucfctrl |= pm->pm_md.pm_ucf.pm_ucf_ctrl; 33160134Sgroudier 33260134Sgroudier wrmsr(UCF_CTRL, ucfc->pc_ucfctrl); 33360134Sgroudier 33460134Sgroudier do { 33560134Sgroudier ucfc->pc_resync = 0; 33659743Sgroudier ucfc->pc_globalctrl |= (1ULL << (ri + SELECTOFF(uncore_cputype))); 33759743Sgroudier wrmsr(UC_GLOBAL_CTRL, ucfc->pc_globalctrl); 33859743Sgroudier } while (ucfc->pc_resync != 0); 33959743Sgroudier 34059743Sgroudier PMCDBG(MDP,STA,1,"ucfctrl=%x(%x) globalctrl=%jx(%jx)", 34159743Sgroudier ucfc->pc_ucfctrl, (uint32_t) rdmsr(UCF_CTRL), 34259743Sgroudier ucfc->pc_globalctrl, rdmsr(UC_GLOBAL_CTRL)); 34359743Sgroudier 34459743Sgroudier return (0); 34559743Sgroudier} 34659743Sgroudier 34759743Sgroudierstatic int 34859743Sgroudierucf_stop_pmc(int cpu, int ri) 34959743Sgroudier{ 35059743Sgroudier uint32_t fc; 35159743Sgroudier struct uncore_cpu *ucfc; 35259743Sgroudier 35359743Sgroudier PMCDBG(MDP,STO,1,"ucf-stop cpu=%d ri=%d", cpu, ri); 35459743Sgroudier 35559743Sgroudier ucfc = uncore_pcpu[cpu]; 35659743Sgroudier 35759743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 35859743Sgroudier ("[uncore,%d] illegal CPU value %d", __LINE__, cpu)); 35959743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucf_npmc, 36059743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 36159743Sgroudier 36259743Sgroudier fc = (UCF_MASK << (ri * 4)); 36359743Sgroudier 36459743Sgroudier ucfc->pc_ucfctrl &= ~fc; 36559743Sgroudier 36659743Sgroudier PMCDBG(MDP,STO,1,"ucf-stop ucfctrl=%x", ucfc->pc_ucfctrl); 36759743Sgroudier wrmsr(UCF_CTRL, ucfc->pc_ucfctrl); 36859743Sgroudier 36959743Sgroudier do { 37059743Sgroudier ucfc->pc_resync = 0; 37159743Sgroudier ucfc->pc_globalctrl &= ~(1ULL << (ri + SELECTOFF(uncore_cputype))); 37259743Sgroudier wrmsr(UC_GLOBAL_CTRL, ucfc->pc_globalctrl); 37359743Sgroudier } while (ucfc->pc_resync != 0); 37459743Sgroudier 37559743Sgroudier PMCDBG(MDP,STO,1,"ucfctrl=%x(%x) globalctrl=%jx(%jx)", 37659743Sgroudier ucfc->pc_ucfctrl, (uint32_t) rdmsr(UCF_CTRL), 37759743Sgroudier ucfc->pc_globalctrl, rdmsr(UC_GLOBAL_CTRL)); 37859743Sgroudier 37959743Sgroudier return (0); 38059743Sgroudier} 38159743Sgroudier 38259743Sgroudierstatic int 38359743Sgroudierucf_write_pmc(int cpu, int ri, pmc_value_t v) 38459743Sgroudier{ 38559743Sgroudier struct uncore_cpu *cc; 38659743Sgroudier struct pmc *pm; 38759743Sgroudier 38859743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 38959743Sgroudier ("[uncore,%d] illegal cpu value %d", __LINE__, cpu)); 39059743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucf_npmc, 39159743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 39259743Sgroudier 39359743Sgroudier cc = uncore_pcpu[cpu]; 39459743Sgroudier pm = cc->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc; 39559743Sgroudier 39659743Sgroudier KASSERT(pm, 39759743Sgroudier ("[uncore,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); 39859743Sgroudier 39959743Sgroudier if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 40059743Sgroudier v = ucf_reload_count_to_perfctr_value(v); 40159743Sgroudier 40259743Sgroudier wrmsr(UCF_CTRL, 0); /* Turn off fixed counters */ 40359743Sgroudier wrmsr(UCF_CTR0 + ri, v); 40459743Sgroudier wrmsr(UCF_CTRL, cc->pc_ucfctrl); 40559743Sgroudier 40659743Sgroudier PMCDBG(MDP,WRI,1, "ucf-write cpu=%d ri=%d v=%jx ucfctrl=%jx ", 40759743Sgroudier cpu, ri, v, (uintmax_t) rdmsr(UCF_CTRL)); 40859743Sgroudier 40959743Sgroudier return (0); 41059743Sgroudier} 41159743Sgroudier 41259743Sgroudier 41359743Sgroudierstatic void 41459743Sgroudierucf_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth) 41559743Sgroudier{ 41659743Sgroudier struct pmc_classdep *pcd; 41759743Sgroudier 41859743Sgroudier KASSERT(md != NULL, ("[ucf,%d] md is NULL", __LINE__)); 41959743Sgroudier 42059743Sgroudier PMCDBG(MDP,INI,1, "%s", "ucf-initialize"); 42159743Sgroudier 42259743Sgroudier pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCF]; 42359743Sgroudier 42459743Sgroudier pcd->pcd_caps = UCF_PMC_CAPS; 42559743Sgroudier pcd->pcd_class = PMC_CLASS_UCF; 42659743Sgroudier pcd->pcd_num = npmc; 42759743Sgroudier pcd->pcd_ri = md->pmd_npmc; 42859743Sgroudier pcd->pcd_width = pmcwidth; 42959743Sgroudier 43059743Sgroudier pcd->pcd_allocate_pmc = ucf_allocate_pmc; 43159743Sgroudier pcd->pcd_config_pmc = ucf_config_pmc; 43259743Sgroudier pcd->pcd_describe = ucf_describe; 43359743Sgroudier pcd->pcd_get_config = ucf_get_config; 43459743Sgroudier pcd->pcd_get_msr = NULL; 43559743Sgroudier pcd->pcd_pcpu_fini = uncore_pcpu_noop; 43659743Sgroudier pcd->pcd_pcpu_init = uncore_pcpu_noop; 43759743Sgroudier pcd->pcd_read_pmc = ucf_read_pmc; 43859743Sgroudier pcd->pcd_release_pmc = ucf_release_pmc; 43959743Sgroudier pcd->pcd_start_pmc = ucf_start_pmc; 44059743Sgroudier pcd->pcd_stop_pmc = ucf_stop_pmc; 44159743Sgroudier pcd->pcd_write_pmc = ucf_write_pmc; 44259743Sgroudier 44359743Sgroudier md->pmd_npmc += npmc; 44459743Sgroudier} 44559743Sgroudier 44659743Sgroudier/* 44759743Sgroudier * Intel programmable PMCs. 44859743Sgroudier */ 44959743Sgroudier 45059743Sgroudier/* 45159743Sgroudier * Event descriptor tables. 45259743Sgroudier * 45359743Sgroudier * For each event id, we track: 45459743Sgroudier * 45559743Sgroudier * 1. The CPUs that the event is valid for. 45659743Sgroudier * 45759743Sgroudier * 2. If the event uses a fixed UMASK, the value of the umask field. 45859743Sgroudier * If the event doesn't use a fixed UMASK, a mask of legal bits 45959743Sgroudier * to check against. 46059743Sgroudier */ 46159743Sgroudier 46259743Sgroudierstruct ucp_event_descr { 46359743Sgroudier enum pmc_event ucp_ev; 46459743Sgroudier unsigned char ucp_evcode; 46559743Sgroudier unsigned char ucp_umask; 46659743Sgroudier unsigned char ucp_flags; 46759743Sgroudier}; 46859743Sgroudier 46959743Sgroudier#define UCP_F_I7 (1 << 0) /* CPU: Core i7 */ 47059743Sgroudier#define UCP_F_WM (1 << 1) /* CPU: Westmere */ 47159743Sgroudier#define UCP_F_SB (1 << 2) /* CPU: Sandy Bridge */ 47259743Sgroudier#define UCP_F_FM (1 << 3) /* Fixed mask */ 47359743Sgroudier 47459743Sgroudier#define UCP_F_ALLCPUS \ 47559743Sgroudier (UCP_F_I7 | UCP_F_WM) 47659743Sgroudier 47759743Sgroudier#define UCP_F_CMASK 0xFF000000 47859743Sgroudier 47959743Sgroudierstatic struct ucp_event_descr ucp_events[] = { 48059743Sgroudier#undef UCPDESCR 48159743Sgroudier#define UCPDESCR(N,EV,UM,FLAGS) { \ 48259743Sgroudier .ucp_ev = PMC_EV_UCP_EVENT_##N, \ 48359743Sgroudier .ucp_evcode = (EV), \ 48459743Sgroudier .ucp_umask = (UM), \ 48559743Sgroudier .ucp_flags = (FLAGS) \ 48659743Sgroudier } 48759743Sgroudier 48859743Sgroudier UCPDESCR(00H_01H, 0x00, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 48959743Sgroudier UCPDESCR(00H_02H, 0x00, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49059743Sgroudier UCPDESCR(00H_04H, 0x00, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49159743Sgroudier 49259743Sgroudier UCPDESCR(01H_01H, 0x01, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49359743Sgroudier UCPDESCR(01H_02H, 0x01, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49459743Sgroudier UCPDESCR(01H_04H, 0x01, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49559743Sgroudier 49659743Sgroudier UCPDESCR(02H_01H, 0x02, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49759743Sgroudier UCPDESCR(03H_01H, 0x03, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49859743Sgroudier UCPDESCR(03H_02H, 0x03, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 49959743Sgroudier UCPDESCR(03H_04H, 0x03, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50059743Sgroudier UCPDESCR(03H_08H, 0x03, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50159743Sgroudier UCPDESCR(03H_10H, 0x03, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50259743Sgroudier UCPDESCR(03H_20H, 0x03, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50359743Sgroudier UCPDESCR(03H_40H, 0x03, 0x40, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50459743Sgroudier 50559743Sgroudier UCPDESCR(04H_01H, 0x04, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50659743Sgroudier UCPDESCR(04H_02H, 0x04, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50759743Sgroudier UCPDESCR(04H_04H, 0x04, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50859743Sgroudier UCPDESCR(04H_08H, 0x04, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 50959743Sgroudier UCPDESCR(04H_10H, 0x04, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51059743Sgroudier 51159743Sgroudier UCPDESCR(05H_01H, 0x05, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51259743Sgroudier UCPDESCR(05H_02H, 0x05, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51359743Sgroudier UCPDESCR(05H_04H, 0x05, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51459743Sgroudier 51559743Sgroudier UCPDESCR(06H_01H, 0x06, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51659743Sgroudier UCPDESCR(06H_02H, 0x06, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51759743Sgroudier UCPDESCR(06H_04H, 0x06, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51859743Sgroudier UCPDESCR(06H_08H, 0x06, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 51959743Sgroudier UCPDESCR(06H_10H, 0x06, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52059743Sgroudier UCPDESCR(06H_20H, 0x06, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52159743Sgroudier 52259743Sgroudier UCPDESCR(07H_01H, 0x07, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52359743Sgroudier UCPDESCR(07H_02H, 0x07, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52459743Sgroudier UCPDESCR(07H_04H, 0x07, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52559743Sgroudier UCPDESCR(07H_08H, 0x07, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52659743Sgroudier UCPDESCR(07H_10H, 0x07, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52759743Sgroudier UCPDESCR(07H_20H, 0x07, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52859743Sgroudier UCPDESCR(07H_24H, 0x07, 0x24, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 52959743Sgroudier 53059743Sgroudier UCPDESCR(08H_01H, 0x08, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53159743Sgroudier UCPDESCR(08H_02H, 0x08, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53259743Sgroudier UCPDESCR(08H_04H, 0x08, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53359743Sgroudier UCPDESCR(08H_03H, 0x08, 0x03, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53459743Sgroudier 53559743Sgroudier UCPDESCR(09H_01H, 0x09, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53659743Sgroudier UCPDESCR(09H_02H, 0x09, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53759743Sgroudier UCPDESCR(09H_04H, 0x09, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53859743Sgroudier UCPDESCR(09H_03H, 0x09, 0x03, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 53959743Sgroudier 54059743Sgroudier UCPDESCR(0AH_01H, 0x0A, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54159743Sgroudier UCPDESCR(0AH_02H, 0x0A, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54259743Sgroudier UCPDESCR(0AH_04H, 0x0A, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54359743Sgroudier UCPDESCR(0AH_08H, 0x0A, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54459743Sgroudier UCPDESCR(0AH_0FH, 0x0A, 0x0F, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54559743Sgroudier 54659743Sgroudier UCPDESCR(0BH_01H, 0x0B, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54759743Sgroudier UCPDESCR(0BH_02H, 0x0B, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54859743Sgroudier UCPDESCR(0BH_04H, 0x0B, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 54959743Sgroudier UCPDESCR(0BH_08H, 0x0B, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 55059743Sgroudier UCPDESCR(0BH_10H, 0x0B, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 55159743Sgroudier UCPDESCR(0BH_1FH, 0x0B, 0x1F, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 55260134Sgroudier 55360134Sgroudier UCPDESCR(0CH_01H, 0x0C, 0x01, UCP_F_FM | UCP_F_WM), 55461051Sgroudier UCPDESCR(0CH_02H, 0x0C, 0x02, UCP_F_FM | UCP_F_WM), 55561051Sgroudier UCPDESCR(0CH_04H_E, 0x0C, 0x04, UCP_F_FM | UCP_F_WM), 55660134Sgroudier UCPDESCR(0CH_04H_F, 0x0C, 0x04, UCP_F_FM | UCP_F_WM), 55760134Sgroudier UCPDESCR(0CH_04H_M, 0x0C, 0x04, UCP_F_FM | UCP_F_WM), 55861051Sgroudier UCPDESCR(0CH_04H_S, 0x0C, 0x04, UCP_F_FM | UCP_F_WM), 55961051Sgroudier UCPDESCR(0CH_08H_E, 0x0C, 0x08, UCP_F_FM | UCP_F_WM), 56059743Sgroudier UCPDESCR(0CH_08H_F, 0x0C, 0x08, UCP_F_FM | UCP_F_WM), 56159743Sgroudier UCPDESCR(0CH_08H_M, 0x0C, 0x08, UCP_F_FM | UCP_F_WM), 56259743Sgroudier UCPDESCR(0CH_08H_S, 0x0C, 0x08, UCP_F_FM | UCP_F_WM), 56359743Sgroudier 56459743Sgroudier UCPDESCR(20H_01H, 0x20, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 56559743Sgroudier UCPDESCR(20H_02H, 0x20, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 56659743Sgroudier UCPDESCR(20H_04H, 0x20, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 56759743Sgroudier UCPDESCR(20H_08H, 0x20, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 56859743Sgroudier UCPDESCR(20H_10H, 0x20, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 56959743Sgroudier UCPDESCR(20H_20H, 0x20, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 57059743Sgroudier 57159743Sgroudier UCPDESCR(21H_01H, 0x21, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 57259743Sgroudier UCPDESCR(21H_02H, 0x21, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 57359743Sgroudier UCPDESCR(21H_04H, 0x21, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 57459743Sgroudier 57559743Sgroudier UCPDESCR(22H_01H, 0x22, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM | 57659743Sgroudier UCP_F_SB), 57759743Sgroudier UCPDESCR(22H_02H, 0x22, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM | 57859743Sgroudier UCP_F_SB), 57959743Sgroudier UCPDESCR(22H_04H, 0x22, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM | 58059743Sgroudier UCP_F_SB), 58159743Sgroudier UCPDESCR(22H_08H, 0x22, 0x08, UCP_F_FM | UCP_F_SB), 58259743Sgroudier UCPDESCR(22H_20H, 0x22, 0x20, UCP_F_FM | UCP_F_SB), 58359743Sgroudier UCPDESCR(22H_40H, 0x22, 0x40, UCP_F_FM | UCP_F_SB), 58459743Sgroudier UCPDESCR(22H_80H, 0x22, 0x80, UCP_F_FM | UCP_F_SB), 58559743Sgroudier 58659743Sgroudier UCPDESCR(23H_01H, 0x23, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 58759743Sgroudier UCPDESCR(23H_02H, 0x23, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 58859743Sgroudier UCPDESCR(23H_04H, 0x23, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 58959743Sgroudier 59059743Sgroudier UCPDESCR(24H_02H, 0x24, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 59159743Sgroudier UCPDESCR(24H_04H, 0x24, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 59259743Sgroudier 59359743Sgroudier UCPDESCR(25H_01H, 0x25, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 59459743Sgroudier UCPDESCR(25H_02H, 0x25, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 59559743Sgroudier UCPDESCR(25H_04H, 0x25, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 59659743Sgroudier 59759743Sgroudier UCPDESCR(26H_01H, 0x26, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 59859743Sgroudier 59959743Sgroudier UCPDESCR(27H_01H, 0x27, 0x01, UCP_F_FM | UCP_F_I7), 60059743Sgroudier UCPDESCR(27H_02H, 0x27, 0x02, UCP_F_FM | UCP_F_I7), 60159743Sgroudier UCPDESCR(27H_04H, 0x27, 0x04, UCP_F_FM | UCP_F_I7), 60259743Sgroudier UCPDESCR(27H_08H, 0x27, 0x08, UCP_F_FM | UCP_F_I7), 60359743Sgroudier UCPDESCR(27H_10H, 0x27, 0x10, UCP_F_FM | UCP_F_I7), 60459743Sgroudier UCPDESCR(27H_20H, 0x27, 0x20, UCP_F_FM | UCP_F_I7), 60559743Sgroudier 60659743Sgroudier UCPDESCR(28H_01H, 0x28, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 60759743Sgroudier UCPDESCR(28H_02H, 0x28, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 60859743Sgroudier UCPDESCR(28H_04H, 0x28, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 60959743Sgroudier UCPDESCR(28H_08H, 0x28, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61059743Sgroudier UCPDESCR(28H_10H, 0x28, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61159743Sgroudier UCPDESCR(28H_20H, 0x28, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61259743Sgroudier 61359743Sgroudier UCPDESCR(29H_01H, 0x29, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61459743Sgroudier UCPDESCR(29H_02H, 0x29, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61559743Sgroudier UCPDESCR(29H_04H, 0x29, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61659743Sgroudier UCPDESCR(29H_08H, 0x29, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61759743Sgroudier UCPDESCR(29H_10H, 0x29, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61859743Sgroudier UCPDESCR(29H_20H, 0x29, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 61959743Sgroudier 62059743Sgroudier UCPDESCR(2AH_01H, 0x2A, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 62159743Sgroudier UCPDESCR(2AH_02H, 0x2A, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 62259743Sgroudier UCPDESCR(2AH_04H, 0x2A, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 62359743Sgroudier UCPDESCR(2AH_07H, 0x2A, 0x07, UCP_F_FM | UCP_F_WM), 62459743Sgroudier 62559743Sgroudier UCPDESCR(2BH_01H, 0x2B, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 62659743Sgroudier UCPDESCR(2BH_02H, 0x2B, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 62759743Sgroudier UCPDESCR(2BH_04H, 0x2B, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 62859743Sgroudier UCPDESCR(2BH_07H, 0x2B, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 62959743Sgroudier 63059743Sgroudier UCPDESCR(2CH_01H, 0x2C, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63159743Sgroudier UCPDESCR(2CH_02H, 0x2C, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63259743Sgroudier UCPDESCR(2CH_04H, 0x2C, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63359743Sgroudier UCPDESCR(2CH_07H, 0x2C, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63459743Sgroudier 63559743Sgroudier UCPDESCR(2DH_01H, 0x2D, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63659743Sgroudier UCPDESCR(2DH_02H, 0x2D, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63759743Sgroudier UCPDESCR(2DH_04H, 0x2D, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63859743Sgroudier UCPDESCR(2DH_07H, 0x2D, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 63959743Sgroudier 64059743Sgroudier UCPDESCR(2EH_01H, 0x2E, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64159743Sgroudier UCPDESCR(2EH_02H, 0x2E, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64259743Sgroudier UCPDESCR(2EH_04H, 0x2E, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64359743Sgroudier UCPDESCR(2EH_07H, 0x2E, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64459743Sgroudier 64559743Sgroudier UCPDESCR(2FH_01H, 0x2F, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64659743Sgroudier UCPDESCR(2FH_02H, 0x2F, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64759743Sgroudier UCPDESCR(2FH_04H, 0x2F, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64859743Sgroudier UCPDESCR(2FH_07H, 0x2F, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 64959743Sgroudier UCPDESCR(2FH_08H, 0x2F, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65059743Sgroudier UCPDESCR(2FH_10H, 0x2F, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65159743Sgroudier UCPDESCR(2FH_20H, 0x2F, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65259743Sgroudier UCPDESCR(2FH_38H, 0x2F, 0x38, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65359743Sgroudier 65459743Sgroudier UCPDESCR(30H_01H, 0x30, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65559743Sgroudier UCPDESCR(30H_02H, 0x30, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65659743Sgroudier UCPDESCR(30H_04H, 0x30, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65759743Sgroudier UCPDESCR(30H_07H, 0x30, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 65859743Sgroudier 65959743Sgroudier UCPDESCR(31H_01H, 0x31, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 66059743Sgroudier UCPDESCR(31H_02H, 0x31, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 66159743Sgroudier UCPDESCR(31H_04H, 0x31, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 66259743Sgroudier UCPDESCR(31H_07H, 0x31, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 66359743Sgroudier 66459743Sgroudier UCPDESCR(32H_01H, 0x32, 0x01, UCP_F_FM | UCP_F_WM), 66559743Sgroudier UCPDESCR(32H_02H, 0x32, 0x02, UCP_F_FM | UCP_F_WM), 66659743Sgroudier UCPDESCR(32H_04H, 0x32, 0x04, UCP_F_FM | UCP_F_WM), 66759743Sgroudier UCPDESCR(32H_07H, 0x32, 0x07, UCP_F_FM | UCP_F_WM), 66859743Sgroudier 66959743Sgroudier UCPDESCR(33H_01H, 0x33, 0x01, UCP_F_FM | UCP_F_WM), 67059743Sgroudier UCPDESCR(33H_02H, 0x33, 0x02, UCP_F_FM | UCP_F_WM), 67159743Sgroudier UCPDESCR(33H_04H, 0x33, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 67259743Sgroudier UCPDESCR(33H_07H, 0x33, 0x07, UCP_F_FM | UCP_F_WM), 67359743Sgroudier 67459743Sgroudier UCPDESCR(34H_01H, 0x34, 0x01, UCP_F_FM | UCP_F_WM | UCP_F_SB), 67559743Sgroudier UCPDESCR(34H_02H, 0x34, 0x02, UCP_F_FM | UCP_F_WM | UCP_F_SB), 67659743Sgroudier UCPDESCR(34H_04H, 0x34, 0x04, UCP_F_FM | UCP_F_WM | UCP_F_SB), 67759743Sgroudier UCPDESCR(34H_08H, 0x34, 0x08, UCP_F_FM | UCP_F_WM | UCP_F_SB), 67859743Sgroudier UCPDESCR(34H_10H, 0x34, 0x10, UCP_F_FM | UCP_F_WM | UCP_F_SB), 67959743Sgroudier UCPDESCR(34H_20H, 0x34, 0x20, UCP_F_FM | UCP_F_WM | UCP_F_SB), 68059743Sgroudier UCPDESCR(34H_40H, 0x34, 0x40, UCP_F_FM | UCP_F_SB), 68159743Sgroudier UCPDESCR(34H_80H, 0x34, 0x80, UCP_F_FM | UCP_F_SB), 68259743Sgroudier 68359743Sgroudier UCPDESCR(35H_01H, 0x35, 0x01, UCP_F_FM | UCP_F_WM), 68459743Sgroudier UCPDESCR(35H_02H, 0x35, 0x02, UCP_F_FM | UCP_F_WM), 68559743Sgroudier UCPDESCR(35H_04H, 0x35, 0x04, UCP_F_FM | UCP_F_WM), 68659743Sgroudier 68759743Sgroudier UCPDESCR(40H_01H, 0x40, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 68859743Sgroudier UCPDESCR(40H_02H, 0x40, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 68959743Sgroudier UCPDESCR(40H_04H, 0x40, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69059743Sgroudier UCPDESCR(40H_08H, 0x40, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69159743Sgroudier UCPDESCR(40H_10H, 0x40, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69259743Sgroudier UCPDESCR(40H_20H, 0x40, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69359743Sgroudier UCPDESCR(40H_07H, 0x40, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69459743Sgroudier UCPDESCR(40H_38H, 0x40, 0x38, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69559743Sgroudier 69659743Sgroudier UCPDESCR(41H_01H, 0x41, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69759743Sgroudier UCPDESCR(41H_02H, 0x41, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69859743Sgroudier UCPDESCR(41H_04H, 0x41, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 69959743Sgroudier UCPDESCR(41H_08H, 0x41, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 70059743Sgroudier UCPDESCR(41H_10H, 0x41, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 70159743Sgroudier UCPDESCR(41H_20H, 0x41, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 70259743Sgroudier UCPDESCR(41H_07H, 0x41, 0x07, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 70359743Sgroudier UCPDESCR(41H_38H, 0x41, 0x38, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 70459743Sgroudier 70559743Sgroudier UCPDESCR(42H_01H, 0x42, 0x01, UCP_F_FM | UCP_F_WM), 70659743Sgroudier UCPDESCR(42H_02H, 0x42, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 70759743Sgroudier UCPDESCR(42H_04H, 0x42, 0x04, UCP_F_FM | UCP_F_WM), 70859743Sgroudier UCPDESCR(42H_08H, 0x42, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 70959743Sgroudier 71059743Sgroudier UCPDESCR(43H_01H, 0x43, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 71159743Sgroudier UCPDESCR(43H_02H, 0x43, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 71259743Sgroudier 71359743Sgroudier UCPDESCR(60H_01H, 0x60, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 71459743Sgroudier UCPDESCR(60H_02H, 0x60, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 71559743Sgroudier UCPDESCR(60H_04H, 0x60, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 71659743Sgroudier 71759743Sgroudier UCPDESCR(61H_01H, 0x61, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 71859743Sgroudier UCPDESCR(61H_02H, 0x61, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 71959743Sgroudier UCPDESCR(61H_04H, 0x61, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72059743Sgroudier 72159743Sgroudier UCPDESCR(62H_01H, 0x62, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72259743Sgroudier UCPDESCR(62H_02H, 0x62, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72359743Sgroudier UCPDESCR(62H_04H, 0x62, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72459743Sgroudier 72559743Sgroudier UCPDESCR(63H_01H, 0x63, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72659743Sgroudier UCPDESCR(63H_02H, 0x63, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72759743Sgroudier UCPDESCR(63H_04H, 0x63, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72859743Sgroudier UCPDESCR(63H_08H, 0x63, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 72959743Sgroudier UCPDESCR(63H_10H, 0x63, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73059743Sgroudier UCPDESCR(63H_20H, 0x63, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73159743Sgroudier 73259743Sgroudier UCPDESCR(64H_01H, 0x64, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73359743Sgroudier UCPDESCR(64H_02H, 0x64, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73459743Sgroudier UCPDESCR(64H_04H, 0x64, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73559743Sgroudier UCPDESCR(64H_08H, 0x64, 0x08, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73659743Sgroudier UCPDESCR(64H_10H, 0x64, 0x10, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73759743Sgroudier UCPDESCR(64H_20H, 0x64, 0x20, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 73859743Sgroudier 73959743Sgroudier UCPDESCR(65H_01H, 0x65, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 74059743Sgroudier UCPDESCR(65H_02H, 0x65, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 74159743Sgroudier UCPDESCR(65H_04H, 0x65, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 74259743Sgroudier 74359743Sgroudier UCPDESCR(66H_01H, 0x66, 0x01, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 74459743Sgroudier UCPDESCR(66H_02H, 0x66, 0x02, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 74559743Sgroudier UCPDESCR(66H_04H, 0x66, 0x04, UCP_F_FM | UCP_F_I7 | UCP_F_WM), 74659743Sgroudier 74759743Sgroudier UCPDESCR(67H_01H, 0x67, 0x01, UCP_F_FM | UCP_F_WM), 74859743Sgroudier 74959743Sgroudier UCPDESCR(80H_01H, 0x80, 0x01, UCP_F_FM | UCP_F_WM | UCP_F_SB), 75059743Sgroudier UCPDESCR(80H_02H, 0x80, 0x02, UCP_F_FM | UCP_F_WM), 75159743Sgroudier UCPDESCR(80H_04H, 0x80, 0x04, UCP_F_FM | UCP_F_WM), 75259743Sgroudier UCPDESCR(80H_08H, 0x80, 0x08, UCP_F_FM | UCP_F_WM), 75359743Sgroudier 75459743Sgroudier UCPDESCR(81H_01H, 0x81, 0x01, UCP_F_FM | UCP_F_WM | UCP_F_SB), 75559743Sgroudier UCPDESCR(81H_02H, 0x81, 0x02, UCP_F_FM | UCP_F_WM), 75659743Sgroudier UCPDESCR(81H_04H, 0x81, 0x04, UCP_F_FM | UCP_F_WM), 75759743Sgroudier UCPDESCR(81H_08H, 0x81, 0x08, UCP_F_FM | UCP_F_WM), 75859743Sgroudier UCPDESCR(81H_20H, 0x81, 0x20, UCP_F_FM | UCP_F_SB), 75959743Sgroudier UCPDESCR(81H_80H, 0x81, 0x80, UCP_F_FM | UCP_F_SB), 76059743Sgroudier 76159743Sgroudier UCPDESCR(82H_01H, 0x82, 0x01, UCP_F_FM | UCP_F_WM), 76259743Sgroudier 76359743Sgroudier UCPDESCR(83H_01H, 0x83, 0x01, UCP_F_FM | UCP_F_WM | UCP_F_SB), 76459743Sgroudier UCPDESCR(83H_02H, 0x83, 0x02, UCP_F_FM | UCP_F_WM), 76559743Sgroudier UCPDESCR(83H_04H, 0x83, 0x04, UCP_F_FM | UCP_F_WM), 76659743Sgroudier UCPDESCR(83H_08H, 0x83, 0x08, UCP_F_FM | UCP_F_WM), 76759743Sgroudier 76859743Sgroudier UCPDESCR(84H_01H, 0x84, 0x01, UCP_F_FM | UCP_F_WM | UCP_F_SB), 76959743Sgroudier UCPDESCR(84H_02H, 0x84, 0x02, UCP_F_FM | UCP_F_WM), 77059743Sgroudier UCPDESCR(84H_04H, 0x84, 0x04, UCP_F_FM | UCP_F_WM), 77159743Sgroudier UCPDESCR(84H_08H, 0x84, 0x08, UCP_F_FM | UCP_F_WM), 77259743Sgroudier UCPDESCR(85H_02H, 0x85, 0x02, UCP_F_FM | UCP_F_WM), 77359743Sgroudier UCPDESCR(86H_01H, 0x86, 0x01, UCP_F_FM | UCP_F_WM) 77459743Sgroudier}; 77559743Sgroudier 77659743Sgroudierstatic const int nucp_events = sizeof(ucp_events) / sizeof(ucp_events[0]); 77759743Sgroudier 77859743Sgroudierstatic pmc_value_t 77959743Sgroudierucp_perfctr_value_to_reload_count(pmc_value_t v) 78059743Sgroudier{ 78159743Sgroudier v &= (1ULL << uncore_ucp_width) - 1; 78259743Sgroudier return (1ULL << uncore_ucp_width) - v; 78359743Sgroudier} 78459743Sgroudier 78559743Sgroudierstatic pmc_value_t 78659743Sgroudierucp_reload_count_to_perfctr_value(pmc_value_t rlc) 78759743Sgroudier{ 78859743Sgroudier return (1ULL << uncore_ucp_width) - rlc; 78959743Sgroudier} 79059743Sgroudier 79159743Sgroudierstatic int 79259743Sgroudierucp_event_sandybridge_ok_on_counter(enum pmc_event pe, int ri) 79359743Sgroudier{ 79459743Sgroudier uint32_t mask; 79559743Sgroudier 79659743Sgroudier switch (pe) { 79759743Sgroudier /* 79859743Sgroudier * Events valid only on counter 0. 79959743Sgroudier */ 80059743Sgroudier case PMC_EV_UCP_EVENT_80H_01H: 80159743Sgroudier case PMC_EV_UCP_EVENT_83H_01H: 80259743Sgroudier mask = (1 << 0); 80359743Sgroudier break; 80459743Sgroudier 80559743Sgroudier default: 80659743Sgroudier mask = ~0; /* Any row index is ok. */ 80759743Sgroudier } 80859743Sgroudier 80959743Sgroudier return (mask & (1 << ri)); 81059743Sgroudier} 81159743Sgroudier 81259743Sgroudierstatic int 81359743Sgroudierucp_allocate_pmc(int cpu, int ri, struct pmc *pm, 81459743Sgroudier const struct pmc_op_pmcallocate *a) 81559743Sgroudier{ 81659743Sgroudier int n; 81759743Sgroudier enum pmc_event ev; 81859743Sgroudier struct ucp_event_descr *ie; 81959743Sgroudier uint32_t caps, config, cpuflag, evsel; 82059743Sgroudier 82159743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 82259743Sgroudier ("[uncore,%d] illegal CPU %d", __LINE__, cpu)); 82359743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucp_npmc, 82459743Sgroudier ("[uncore,%d] illegal row-index value %d", __LINE__, ri)); 82559743Sgroudier 82659743Sgroudier /* check requested capabilities */ 82759743Sgroudier caps = a->pm_caps; 82859743Sgroudier if ((UCP_PMC_CAPS & caps) != caps) 82959743Sgroudier return (EPERM); 83059743Sgroudier 83159743Sgroudier ev = pm->pm_event; 83259743Sgroudier 83359743Sgroudier switch (uncore_cputype) { 83459743Sgroudier case PMC_CPU_INTEL_SANDYBRIDGE: 83559743Sgroudier if (ucp_event_sandybridge_ok_on_counter(ev, ri) == 0) 83659743Sgroudier return (EINVAL); 83759743Sgroudier break; 83859743Sgroudier default: 83959743Sgroudier break; 84059743Sgroudier } 84159743Sgroudier 84259743Sgroudier 84359743Sgroudier /* 84459743Sgroudier * Look for an event descriptor with matching CPU and event id 84559743Sgroudier * fields. 84659743Sgroudier */ 84759743Sgroudier 84859743Sgroudier switch (uncore_cputype) { 84959743Sgroudier case PMC_CPU_INTEL_COREI7: 85059743Sgroudier cpuflag = UCP_F_I7; 85159743Sgroudier break; 85259743Sgroudier case PMC_CPU_INTEL_SANDYBRIDGE: 85359743Sgroudier cpuflag = UCP_F_SB; 85459743Sgroudier break; 85559743Sgroudier case PMC_CPU_INTEL_WESTMERE: 85659743Sgroudier cpuflag = UCP_F_WM; 85759743Sgroudier break; 85859743Sgroudier default: 85959743Sgroudier return (EINVAL); 86059743Sgroudier } 86159743Sgroudier 86259743Sgroudier for (n = 0, ie = ucp_events; n < nucp_events; n++, ie++) 86359743Sgroudier if (ie->ucp_ev == ev && ie->ucp_flags & cpuflag) 86459743Sgroudier break; 86559743Sgroudier 86659743Sgroudier if (n == nucp_events) 86759743Sgroudier return (EINVAL); 86859743Sgroudier 86959743Sgroudier /* 87059743Sgroudier * A matching event descriptor has been found, so start 87159743Sgroudier * assembling the contents of the event select register. 87259743Sgroudier */ 87359743Sgroudier evsel = ie->ucp_evcode | UCP_EN; 87459743Sgroudier 87559743Sgroudier config = a->pm_md.pm_ucp.pm_ucp_config & ~UCP_F_CMASK; 87659743Sgroudier 87759743Sgroudier /* 87859743Sgroudier * If the event uses a fixed umask value, reject any umask 87959743Sgroudier * bits set by the user. 88059743Sgroudier */ 88159743Sgroudier if (ie->ucp_flags & UCP_F_FM) { 88259743Sgroudier 88359743Sgroudier if (UCP_UMASK(config) != 0) 88459743Sgroudier return (EINVAL); 88559743Sgroudier 88659743Sgroudier evsel |= (ie->ucp_umask << 8); 88759743Sgroudier 88859743Sgroudier } else 88959743Sgroudier return (EINVAL); 89059743Sgroudier 89159743Sgroudier if (caps & PMC_CAP_THRESHOLD) 89259743Sgroudier evsel |= (a->pm_md.pm_ucp.pm_ucp_config & UCP_F_CMASK); 89359743Sgroudier if (caps & PMC_CAP_EDGE) 89459743Sgroudier evsel |= UCP_EDGE; 89559743Sgroudier if (caps & PMC_CAP_INVERT) 89659743Sgroudier evsel |= UCP_INV; 89759743Sgroudier 89859743Sgroudier pm->pm_md.pm_ucp.pm_ucp_evsel = evsel; 89959743Sgroudier 90059743Sgroudier return (0); 90159743Sgroudier} 90259743Sgroudier 90359743Sgroudierstatic int 90459743Sgroudierucp_config_pmc(int cpu, int ri, struct pmc *pm) 90559743Sgroudier{ 90659743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 90759743Sgroudier ("[uncore,%d] illegal CPU %d", __LINE__, cpu)); 90859743Sgroudier 90959743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucp_npmc, 91059743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 91159743Sgroudier 91259743Sgroudier PMCDBG(MDP,CFG,1, "ucp-config cpu=%d ri=%d pm=%p", cpu, ri, pm); 91359743Sgroudier 91459743Sgroudier KASSERT(uncore_pcpu[cpu] != NULL, ("[uncore,%d] null per-cpu %d", __LINE__, 91559743Sgroudier cpu)); 91659743Sgroudier 91759743Sgroudier uncore_pcpu[cpu]->pc_uncorepmcs[ri].phw_pmc = pm; 91859743Sgroudier 91959743Sgroudier return (0); 92059743Sgroudier} 92159743Sgroudier 92259743Sgroudierstatic int 92359743Sgroudierucp_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 92459743Sgroudier{ 92559743Sgroudier int error; 92659743Sgroudier struct pmc_hw *phw; 92759743Sgroudier char ucp_name[PMC_NAME_MAX]; 92859743Sgroudier 92959743Sgroudier phw = &uncore_pcpu[cpu]->pc_uncorepmcs[ri]; 93059743Sgroudier 93159743Sgroudier (void) snprintf(ucp_name, sizeof(ucp_name), "UCP-%d", ri); 93259743Sgroudier if ((error = copystr(ucp_name, pi->pm_name, PMC_NAME_MAX, 93359743Sgroudier NULL)) != 0) 93459743Sgroudier return (error); 93559743Sgroudier 93659743Sgroudier pi->pm_class = PMC_CLASS_UCP; 93759743Sgroudier 93859743Sgroudier if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 93959743Sgroudier pi->pm_enabled = TRUE; 94060134Sgroudier *ppmc = phw->phw_pmc; 94159743Sgroudier } else { 94259743Sgroudier pi->pm_enabled = FALSE; 94359743Sgroudier *ppmc = NULL; 94459743Sgroudier } 94559743Sgroudier 94659743Sgroudier return (0); 94759743Sgroudier} 94859743Sgroudier 94959743Sgroudierstatic int 95059743Sgroudierucp_get_config(int cpu, int ri, struct pmc **ppm) 95159743Sgroudier{ 95259743Sgroudier *ppm = uncore_pcpu[cpu]->pc_uncorepmcs[ri].phw_pmc; 95359743Sgroudier 95459743Sgroudier return (0); 95559743Sgroudier} 95659743Sgroudier 95759743Sgroudierstatic int 95859743Sgroudierucp_read_pmc(int cpu, int ri, pmc_value_t *v) 95959743Sgroudier{ 96059743Sgroudier struct pmc *pm; 96159743Sgroudier pmc_value_t tmp; 96259743Sgroudier 96359743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 96459743Sgroudier ("[uncore,%d] illegal cpu value %d", __LINE__, cpu)); 96559743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucp_npmc, 96659743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 96759743Sgroudier 96859743Sgroudier pm = uncore_pcpu[cpu]->pc_uncorepmcs[ri].phw_pmc; 96959743Sgroudier 97059743Sgroudier KASSERT(pm, 97159743Sgroudier ("[uncore,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, 97259743Sgroudier ri)); 97359743Sgroudier 97459743Sgroudier tmp = rdmsr(UCP_PMC0 + ri); 97559743Sgroudier if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 97659743Sgroudier *v = ucp_perfctr_value_to_reload_count(tmp); 97759743Sgroudier else 97859743Sgroudier *v = tmp; 97959743Sgroudier 98059743Sgroudier PMCDBG(MDP,REA,1, "ucp-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri, 98159743Sgroudier ri, *v); 98259743Sgroudier 98359743Sgroudier return (0); 98459743Sgroudier} 98559743Sgroudier 98659743Sgroudierstatic int 98759743Sgroudierucp_release_pmc(int cpu, int ri, struct pmc *pm) 98859743Sgroudier{ 98959743Sgroudier (void) pm; 99059743Sgroudier 99159743Sgroudier PMCDBG(MDP,REL,1, "ucp-release cpu=%d ri=%d pm=%p", cpu, ri, 99259743Sgroudier pm); 99359743Sgroudier 99459743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 99559743Sgroudier ("[uncore,%d] illegal CPU value %d", __LINE__, cpu)); 99659743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucp_npmc, 99759743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 99859743Sgroudier 99959743Sgroudier KASSERT(uncore_pcpu[cpu]->pc_uncorepmcs[ri].phw_pmc 100059743Sgroudier == NULL, ("[uncore,%d] PHW pmc non-NULL", __LINE__)); 100159743Sgroudier 100259743Sgroudier return (0); 100359743Sgroudier} 100459743Sgroudier 100559743Sgroudierstatic int 100659743Sgroudierucp_start_pmc(int cpu, int ri) 100759743Sgroudier{ 100859743Sgroudier struct pmc *pm; 100959743Sgroudier uint32_t evsel; 101059743Sgroudier struct uncore_cpu *cc; 101159743Sgroudier 101259743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 101359743Sgroudier ("[uncore,%d] illegal CPU value %d", __LINE__, cpu)); 101459743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucp_npmc, 101559743Sgroudier ("[uncore,%d] illegal row-index %d", __LINE__, ri)); 101659743Sgroudier 101759743Sgroudier cc = uncore_pcpu[cpu]; 101859743Sgroudier pm = cc->pc_uncorepmcs[ri].phw_pmc; 101959743Sgroudier 102059743Sgroudier KASSERT(pm, 102159743Sgroudier ("[uncore,%d] starting cpu%d,ri%d with no pmc configured", 102259743Sgroudier __LINE__, cpu, ri)); 102359743Sgroudier 102459743Sgroudier PMCDBG(MDP,STA,1, "ucp-start cpu=%d ri=%d", cpu, ri); 102559743Sgroudier 102659743Sgroudier evsel = pm->pm_md.pm_ucp.pm_ucp_evsel; 102759743Sgroudier 102859743Sgroudier PMCDBG(MDP,STA,2, 102959743Sgroudier "ucp-start/2 cpu=%d ri=%d evselmsr=0x%x evsel=0x%x", 103059743Sgroudier cpu, ri, SELECTSEL(uncore_cputype) + ri, evsel); 103159743Sgroudier 103259743Sgroudier /* Event specific configuration. */ 103359743Sgroudier switch (pm->pm_event) { 103459743Sgroudier case PMC_EV_UCP_EVENT_0CH_04H_E: 103559743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x2); 103659743Sgroudier break; 103759743Sgroudier case PMC_EV_UCP_EVENT_0CH_04H_F: 103859743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x8); 103959743Sgroudier break; 104059743Sgroudier case PMC_EV_UCP_EVENT_0CH_04H_M: 104159743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x1); 104259743Sgroudier break; 104359743Sgroudier case PMC_EV_UCP_EVENT_0CH_04H_S: 104459743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x4); 104559743Sgroudier break; 104659743Sgroudier case PMC_EV_UCP_EVENT_0CH_08H_E: 104759743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x2); 104859743Sgroudier break; 104959743Sgroudier case PMC_EV_UCP_EVENT_0CH_08H_F: 105059743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x8); 105159743Sgroudier break; 105259743Sgroudier case PMC_EV_UCP_EVENT_0CH_08H_M: 105359743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x1); 105459743Sgroudier break; 105559743Sgroudier case PMC_EV_UCP_EVENT_0CH_08H_S: 105659743Sgroudier wrmsr(MSR_GQ_SNOOP_MESF,0x4); 105759743Sgroudier break; 105859743Sgroudier default: 105959743Sgroudier break; 106059743Sgroudier } 106159743Sgroudier 106259743Sgroudier wrmsr(SELECTSEL(uncore_cputype) + ri, evsel); 106359743Sgroudier 106459743Sgroudier do { 106559743Sgroudier cc->pc_resync = 0; 106659743Sgroudier cc->pc_globalctrl |= (1ULL << ri); 106759743Sgroudier wrmsr(UC_GLOBAL_CTRL, cc->pc_globalctrl); 106859743Sgroudier } while (cc->pc_resync != 0); 106959743Sgroudier 107059743Sgroudier return (0); 107159743Sgroudier} 107259743Sgroudier 107359743Sgroudierstatic int 107459743Sgroudierucp_stop_pmc(int cpu, int ri) 107559743Sgroudier{ 107659743Sgroudier struct pmc *pm; 107759743Sgroudier struct uncore_cpu *cc; 107859743Sgroudier 107959743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 108059743Sgroudier ("[uncore,%d] illegal cpu value %d", __LINE__, cpu)); 108159743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucp_npmc, 108259743Sgroudier ("[uncore,%d] illegal row index %d", __LINE__, ri)); 108359743Sgroudier 108459743Sgroudier cc = uncore_pcpu[cpu]; 108559743Sgroudier pm = cc->pc_uncorepmcs[ri].phw_pmc; 108659743Sgroudier 108759743Sgroudier KASSERT(pm, 108859743Sgroudier ("[uncore,%d] cpu%d ri%d no configured PMC to stop", __LINE__, 108959743Sgroudier cpu, ri)); 109059743Sgroudier 109159743Sgroudier PMCDBG(MDP,STO,1, "ucp-stop cpu=%d ri=%d", cpu, ri); 109259743Sgroudier 109359743Sgroudier /* stop hw. */ 109459743Sgroudier wrmsr(SELECTSEL(uncore_cputype) + ri, 0); 109559743Sgroudier 109659743Sgroudier do { 109759743Sgroudier cc->pc_resync = 0; 109859743Sgroudier cc->pc_globalctrl &= ~(1ULL << ri); 109959743Sgroudier wrmsr(UC_GLOBAL_CTRL, cc->pc_globalctrl); 110059743Sgroudier } while (cc->pc_resync != 0); 110159743Sgroudier 110259743Sgroudier return (0); 110359743Sgroudier} 110459743Sgroudier 110559743Sgroudierstatic int 110659743Sgroudierucp_write_pmc(int cpu, int ri, pmc_value_t v) 110759743Sgroudier{ 110859743Sgroudier struct pmc *pm; 110959743Sgroudier struct uncore_cpu *cc; 111059743Sgroudier 111159743Sgroudier KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 111259743Sgroudier ("[uncore,%d] illegal cpu value %d", __LINE__, cpu)); 111359743Sgroudier KASSERT(ri >= 0 && ri < uncore_ucp_npmc, 111459743Sgroudier ("[uncore,%d] illegal row index %d", __LINE__, ri)); 111559743Sgroudier 111659743Sgroudier cc = uncore_pcpu[cpu]; 111759743Sgroudier pm = cc->pc_uncorepmcs[ri].phw_pmc; 111859743Sgroudier 111959743Sgroudier KASSERT(pm, 112059743Sgroudier ("[uncore,%d] cpu%d ri%d no configured PMC to stop", __LINE__, 112159743Sgroudier cpu, ri)); 112259743Sgroudier 112359743Sgroudier PMCDBG(MDP,WRI,1, "ucp-write cpu=%d ri=%d msr=0x%x v=%jx", cpu, ri, 112459743Sgroudier UCP_PMC0 + ri, v); 112559743Sgroudier 112659743Sgroudier if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 112759743Sgroudier v = ucp_reload_count_to_perfctr_value(v); 112859743Sgroudier 112959743Sgroudier /* 113059743Sgroudier * Write the new value to the counter. The counter will be in 113159743Sgroudier * a stopped state when the pcd_write() entry point is called. 113259743Sgroudier */ 113359743Sgroudier 113459743Sgroudier wrmsr(UCP_PMC0 + ri, v); 113559743Sgroudier 113659743Sgroudier return (0); 113759743Sgroudier} 113859743Sgroudier 113959743Sgroudier 114059743Sgroudierstatic void 114159743Sgroudierucp_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth) 114259743Sgroudier{ 114359743Sgroudier struct pmc_classdep *pcd; 114459743Sgroudier 114559743Sgroudier KASSERT(md != NULL, ("[ucp,%d] md is NULL", __LINE__)); 114659743Sgroudier 114759743Sgroudier PMCDBG(MDP,INI,1, "%s", "ucp-initialize"); 114859743Sgroudier 114959743Sgroudier pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP]; 115059743Sgroudier 115159743Sgroudier pcd->pcd_caps = UCP_PMC_CAPS; 115259743Sgroudier pcd->pcd_class = PMC_CLASS_UCP; 115359743Sgroudier pcd->pcd_num = npmc; 115459743Sgroudier pcd->pcd_ri = md->pmd_npmc; 115559743Sgroudier pcd->pcd_width = pmcwidth; 115659743Sgroudier 115759743Sgroudier pcd->pcd_allocate_pmc = ucp_allocate_pmc; 115859743Sgroudier pcd->pcd_config_pmc = ucp_config_pmc; 115959743Sgroudier pcd->pcd_describe = ucp_describe; 116059743Sgroudier pcd->pcd_get_config = ucp_get_config; 116159743Sgroudier pcd->pcd_get_msr = NULL; 116259743Sgroudier pcd->pcd_pcpu_fini = uncore_pcpu_fini; 116359743Sgroudier pcd->pcd_pcpu_init = uncore_pcpu_init; 116459743Sgroudier pcd->pcd_read_pmc = ucp_read_pmc; 116559743Sgroudier pcd->pcd_release_pmc = ucp_release_pmc; 116659743Sgroudier pcd->pcd_start_pmc = ucp_start_pmc; 116759743Sgroudier pcd->pcd_stop_pmc = ucp_stop_pmc; 116859743Sgroudier pcd->pcd_write_pmc = ucp_write_pmc; 116959743Sgroudier 117059743Sgroudier md->pmd_npmc += npmc; 117159743Sgroudier} 117259743Sgroudier 117359743Sgroudierint 117459743Sgroudierpmc_uncore_initialize(struct pmc_mdep *md, int maxcpu) 117559743Sgroudier{ 117659743Sgroudier uncore_cputype = md->pmd_cputype; 117759743Sgroudier uncore_pmcmask = 0; 117859743Sgroudier 117959743Sgroudier /* 118059743Sgroudier * Initialize programmable counters. 118159743Sgroudier */ 118259743Sgroudier 118359743Sgroudier uncore_ucp_npmc = 8; 118459743Sgroudier uncore_ucp_width = 48; 118559743Sgroudier 118659743Sgroudier uncore_pmcmask |= ((1ULL << uncore_ucp_npmc) - 1); 118759743Sgroudier 118859743Sgroudier ucp_initialize(md, maxcpu, uncore_ucp_npmc, uncore_ucp_width); 118959743Sgroudier 119059743Sgroudier /* 119159743Sgroudier * Initialize fixed function counters, if present. 119259743Sgroudier */ 119359743Sgroudier uncore_ucf_ri = uncore_ucp_npmc; 119459743Sgroudier uncore_ucf_npmc = 1; 119559743Sgroudier uncore_ucf_width = 48; 119659743Sgroudier 119759743Sgroudier ucf_initialize(md, maxcpu, uncore_ucf_npmc, uncore_ucf_width); 119859743Sgroudier uncore_pmcmask |= ((1ULL << uncore_ucf_npmc) - 1) << SELECTOFF(uncore_cputype); 119959743Sgroudier 120059743Sgroudier PMCDBG(MDP,INI,1,"uncore-init pmcmask=0x%jx ucfri=%d", uncore_pmcmask, 120159743Sgroudier uncore_ucf_ri); 120259743Sgroudier 120359743Sgroudier uncore_pcpu = malloc(sizeof(struct uncore_cpu **) * maxcpu, M_PMC, 120459743Sgroudier M_ZERO | M_WAITOK); 120559743Sgroudier 120659743Sgroudier return (0); 120759743Sgroudier} 120859743Sgroudier 120959743Sgroudiervoid 121059743Sgroudierpmc_uncore_finalize(struct pmc_mdep *md) 121159743Sgroudier{ 121259743Sgroudier PMCDBG(MDP,INI,1, "%s", "uncore-finalize"); 121359743Sgroudier 121459743Sgroudier free(uncore_pcpu, M_PMC); 121559743Sgroudier uncore_pcpu = NULL; 121659743Sgroudier} 121759743Sgroudier