11fa7f10bSFabien Thomas /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
41fa7f10bSFabien Thomas * Copyright (c) 2010 Fabien Thomas
51fa7f10bSFabien Thomas * All rights reserved.
61fa7f10bSFabien Thomas *
71fa7f10bSFabien Thomas * Redistribution and use in source and binary forms, with or without
81fa7f10bSFabien Thomas * modification, are permitted provided that the following conditions
91fa7f10bSFabien Thomas * are met:
101fa7f10bSFabien Thomas * 1. Redistributions of source code must retain the above copyright
111fa7f10bSFabien Thomas * notice, this list of conditions and the following disclaimer.
121fa7f10bSFabien Thomas * 2. Redistributions in binary form must reproduce the above copyright
131fa7f10bSFabien Thomas * notice, this list of conditions and the following disclaimer in the
141fa7f10bSFabien Thomas * documentation and/or other materials provided with the distribution.
151fa7f10bSFabien Thomas *
161fa7f10bSFabien Thomas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171fa7f10bSFabien Thomas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181fa7f10bSFabien Thomas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191fa7f10bSFabien Thomas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201fa7f10bSFabien Thomas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211fa7f10bSFabien Thomas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221fa7f10bSFabien Thomas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231fa7f10bSFabien Thomas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241fa7f10bSFabien Thomas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251fa7f10bSFabien Thomas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261fa7f10bSFabien Thomas * SUCH DAMAGE.
271fa7f10bSFabien Thomas */
281fa7f10bSFabien Thomas
291fa7f10bSFabien Thomas /*
301fa7f10bSFabien Thomas * Intel Uncore PMCs.
311fa7f10bSFabien Thomas */
321fa7f10bSFabien Thomas
331fa7f10bSFabien Thomas #include <sys/param.h>
341fa7f10bSFabien Thomas #include <sys/bus.h>
351fa7f10bSFabien Thomas #include <sys/pmc.h>
361fa7f10bSFabien Thomas #include <sys/pmckern.h>
371fa7f10bSFabien Thomas #include <sys/systm.h>
381fa7f10bSFabien Thomas
391fa7f10bSFabien Thomas #include <machine/intr_machdep.h>
40e07ef9b0SJohn Baldwin #include <x86/apicvar.h>
411fa7f10bSFabien Thomas #include <machine/cpu.h>
421fa7f10bSFabien Thomas #include <machine/cpufunc.h>
431fa7f10bSFabien Thomas #include <machine/specialreg.h>
441fa7f10bSFabien Thomas
451fa7f10bSFabien Thomas #define UCF_PMC_CAPS \
461fa7f10bSFabien Thomas (PMC_CAP_READ | PMC_CAP_WRITE)
471fa7f10bSFabien Thomas
481fa7f10bSFabien Thomas #define UCP_PMC_CAPS \
491fa7f10bSFabien Thomas (PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \
501fa7f10bSFabien Thomas PMC_CAP_INVERT | PMC_CAP_QUALIFIER | PMC_CAP_PRECISE)
511fa7f10bSFabien Thomas
5278d763a2SDavide Italiano #define SELECTSEL(x) \
53cc0c1555SSean Bruno (((x) == PMC_CPU_INTEL_SANDYBRIDGE || (x) == PMC_CPU_INTEL_HASWELL) ? \
54cc0c1555SSean Bruno UCP_CB0_EVSEL0 : UCP_EVSEL0)
5578d763a2SDavide Italiano
5678d763a2SDavide Italiano #define SELECTOFF(x) \
57cc0c1555SSean Bruno (((x) == PMC_CPU_INTEL_SANDYBRIDGE || (x) == PMC_CPU_INTEL_HASWELL) ? \
58cc0c1555SSean Bruno UCF_OFFSET_SB : UCF_OFFSET)
5978d763a2SDavide Italiano
601fa7f10bSFabien Thomas static enum pmc_cputype uncore_cputype;
611fa7f10bSFabien Thomas
621fa7f10bSFabien Thomas struct uncore_cpu {
631fa7f10bSFabien Thomas volatile uint32_t pc_ucfctrl; /* Fixed function control. */
641fa7f10bSFabien Thomas volatile uint64_t pc_globalctrl; /* Global control register. */
651fa7f10bSFabien Thomas struct pmc_hw pc_uncorepmcs[];
661fa7f10bSFabien Thomas };
671fa7f10bSFabien Thomas
681fa7f10bSFabien Thomas static struct uncore_cpu **uncore_pcpu;
691fa7f10bSFabien Thomas
701fa7f10bSFabien Thomas static uint64_t uncore_pmcmask;
711fa7f10bSFabien Thomas
721fa7f10bSFabien Thomas static int uncore_ucf_ri; /* relative index of fixed counters */
731fa7f10bSFabien Thomas static int uncore_ucf_width;
741fa7f10bSFabien Thomas static int uncore_ucf_npmc;
751fa7f10bSFabien Thomas
761fa7f10bSFabien Thomas static int uncore_ucp_width;
771fa7f10bSFabien Thomas static int uncore_ucp_npmc;
781fa7f10bSFabien Thomas
791fa7f10bSFabien Thomas static int
uncore_pcpu_noop(struct pmc_mdep * md,int cpu)801fa7f10bSFabien Thomas uncore_pcpu_noop(struct pmc_mdep *md, int cpu)
811fa7f10bSFabien Thomas {
821fa7f10bSFabien Thomas (void) md;
831fa7f10bSFabien Thomas (void) cpu;
841fa7f10bSFabien Thomas return (0);
851fa7f10bSFabien Thomas }
861fa7f10bSFabien Thomas
871fa7f10bSFabien Thomas static int
uncore_pcpu_init(struct pmc_mdep * md,int cpu)881fa7f10bSFabien Thomas uncore_pcpu_init(struct pmc_mdep *md, int cpu)
891fa7f10bSFabien Thomas {
901fa7f10bSFabien Thomas struct pmc_cpu *pc;
911fa7f10bSFabien Thomas struct uncore_cpu *cc;
921fa7f10bSFabien Thomas struct pmc_hw *phw;
931fa7f10bSFabien Thomas int uncore_ri, n, npmc;
941fa7f10bSFabien Thomas
951fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
961fa7f10bSFabien Thomas ("[ucf,%d] insane cpu number %d", __LINE__, cpu));
971fa7f10bSFabien Thomas
984a3690dfSJohn Baldwin PMCDBG1(MDP,INI,1,"uncore-init cpu=%d", cpu);
991fa7f10bSFabien Thomas
1001fa7f10bSFabien Thomas uncore_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_ri;
1011fa7f10bSFabien Thomas npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_num;
1021fa7f10bSFabien Thomas npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCF].pcd_num;
1031fa7f10bSFabien Thomas
1041fa7f10bSFabien Thomas cc = malloc(sizeof(struct uncore_cpu) + npmc * sizeof(struct pmc_hw),
1051fa7f10bSFabien Thomas M_PMC, M_WAITOK | M_ZERO);
1061fa7f10bSFabien Thomas
1071fa7f10bSFabien Thomas uncore_pcpu[cpu] = cc;
1081fa7f10bSFabien Thomas pc = pmc_pcpu[cpu];
1091fa7f10bSFabien Thomas
1101fa7f10bSFabien Thomas KASSERT(pc != NULL && cc != NULL,
1111fa7f10bSFabien Thomas ("[uncore,%d] NULL per-cpu structures cpu=%d", __LINE__, cpu));
1121fa7f10bSFabien Thomas
1131fa7f10bSFabien Thomas for (n = 0, phw = cc->pc_uncorepmcs; n < npmc; n++, phw++) {
1141fa7f10bSFabien Thomas phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
1151fa7f10bSFabien Thomas PMC_PHW_CPU_TO_STATE(cpu) |
1161fa7f10bSFabien Thomas PMC_PHW_INDEX_TO_STATE(n + uncore_ri);
1171fa7f10bSFabien Thomas phw->phw_pmc = NULL;
1181fa7f10bSFabien Thomas pc->pc_hwpmcs[n + uncore_ri] = phw;
1191fa7f10bSFabien Thomas }
1201fa7f10bSFabien Thomas
1211fa7f10bSFabien Thomas return (0);
1221fa7f10bSFabien Thomas }
1231fa7f10bSFabien Thomas
1241fa7f10bSFabien Thomas static int
uncore_pcpu_fini(struct pmc_mdep * md,int cpu)1251fa7f10bSFabien Thomas uncore_pcpu_fini(struct pmc_mdep *md, int cpu)
1261fa7f10bSFabien Thomas {
1271fa7f10bSFabien Thomas int uncore_ri, n, npmc;
1281fa7f10bSFabien Thomas struct pmc_cpu *pc;
1291fa7f10bSFabien Thomas struct uncore_cpu *cc;
1301fa7f10bSFabien Thomas
1311fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
1321fa7f10bSFabien Thomas ("[uncore,%d] insane cpu number (%d)", __LINE__, cpu));
1331fa7f10bSFabien Thomas
1344a3690dfSJohn Baldwin PMCDBG1(MDP,INI,1,"uncore-pcpu-fini cpu=%d", cpu);
1351fa7f10bSFabien Thomas
1361fa7f10bSFabien Thomas if ((cc = uncore_pcpu[cpu]) == NULL)
1371fa7f10bSFabien Thomas return (0);
1381fa7f10bSFabien Thomas
1391fa7f10bSFabien Thomas uncore_pcpu[cpu] = NULL;
1401fa7f10bSFabien Thomas
1411fa7f10bSFabien Thomas pc = pmc_pcpu[cpu];
1421fa7f10bSFabien Thomas
1431fa7f10bSFabien Thomas KASSERT(pc != NULL, ("[uncore,%d] NULL per-cpu %d state", __LINE__,
1441fa7f10bSFabien Thomas cpu));
1451fa7f10bSFabien Thomas
1461fa7f10bSFabien Thomas npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_num;
1471fa7f10bSFabien Thomas uncore_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP].pcd_ri;
1481fa7f10bSFabien Thomas
1491fa7f10bSFabien Thomas for (n = 0; n < npmc; n++)
15078d763a2SDavide Italiano wrmsr(SELECTSEL(uncore_cputype) + n, 0);
1511fa7f10bSFabien Thomas
1521fa7f10bSFabien Thomas wrmsr(UCF_CTRL, 0);
1531fa7f10bSFabien Thomas npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCF].pcd_num;
1541fa7f10bSFabien Thomas
1551fa7f10bSFabien Thomas for (n = 0; n < npmc; n++)
1561fa7f10bSFabien Thomas pc->pc_hwpmcs[n + uncore_ri] = NULL;
1571fa7f10bSFabien Thomas
1581fa7f10bSFabien Thomas free(cc, M_PMC);
1591fa7f10bSFabien Thomas
1601fa7f10bSFabien Thomas return (0);
1611fa7f10bSFabien Thomas }
1621fa7f10bSFabien Thomas
1631fa7f10bSFabien Thomas /*
1641fa7f10bSFabien Thomas * Fixed function counters.
1651fa7f10bSFabien Thomas */
1661fa7f10bSFabien Thomas
1671fa7f10bSFabien Thomas static pmc_value_t
ucf_perfctr_value_to_reload_count(pmc_value_t v)1681fa7f10bSFabien Thomas ucf_perfctr_value_to_reload_count(pmc_value_t v)
1691fa7f10bSFabien Thomas {
170e74c7ffcSJessica Clarke
171e74c7ffcSJessica Clarke /* If the PMC has overflowed, return a reload count of zero. */
172e74c7ffcSJessica Clarke if ((v & (1ULL << (uncore_ucf_width - 1))) == 0)
173e74c7ffcSJessica Clarke return (0);
1741fa7f10bSFabien Thomas v &= (1ULL << uncore_ucf_width) - 1;
1751fa7f10bSFabien Thomas return (1ULL << uncore_ucf_width) - v;
1761fa7f10bSFabien Thomas }
1771fa7f10bSFabien Thomas
1781fa7f10bSFabien Thomas static pmc_value_t
ucf_reload_count_to_perfctr_value(pmc_value_t rlc)1791fa7f10bSFabien Thomas ucf_reload_count_to_perfctr_value(pmc_value_t rlc)
1801fa7f10bSFabien Thomas {
1811fa7f10bSFabien Thomas return (1ULL << uncore_ucf_width) - rlc;
1821fa7f10bSFabien Thomas }
1831fa7f10bSFabien Thomas
1841fa7f10bSFabien Thomas static int
ucf_allocate_pmc(int cpu,int ri,struct pmc * pm,const struct pmc_op_pmcallocate * a)1851fa7f10bSFabien Thomas ucf_allocate_pmc(int cpu, int ri, struct pmc *pm,
1861fa7f10bSFabien Thomas const struct pmc_op_pmcallocate *a)
1871fa7f10bSFabien Thomas {
1880e78510bSMitchell Horne uint32_t flags;
1891fa7f10bSFabien Thomas
1901fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
1911fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU %d", __LINE__, cpu));
1921fa7f10bSFabien Thomas
1934a3690dfSJohn Baldwin PMCDBG2(MDP,ALL,1, "ucf-allocate ri=%d reqcaps=0x%x", ri, pm->pm_caps);
1941fa7f10bSFabien Thomas
1951fa7f10bSFabien Thomas if (ri < 0 || ri > uncore_ucf_npmc)
1961fa7f10bSFabien Thomas return (EINVAL);
1971fa7f10bSFabien Thomas
1980e78510bSMitchell Horne if (a->pm_class != PMC_CLASS_UCF)
1991fa7f10bSFabien Thomas return (EINVAL);
2001fa7f10bSFabien Thomas
201c190fb35SMitchell Horne if ((a->pm_flags & PMC_F_EV_PMU) == 0)
202c190fb35SMitchell Horne return (EINVAL);
203c190fb35SMitchell Horne
2041fa7f10bSFabien Thomas flags = UCF_EN;
2051fa7f10bSFabien Thomas
2061fa7f10bSFabien Thomas pm->pm_md.pm_ucf.pm_ucf_ctrl = (flags << (ri * 4));
2071fa7f10bSFabien Thomas
2084a3690dfSJohn Baldwin PMCDBG1(MDP,ALL,2, "ucf-allocate config=0x%jx",
2091fa7f10bSFabien Thomas (uintmax_t) pm->pm_md.pm_ucf.pm_ucf_ctrl);
2101fa7f10bSFabien Thomas
2111fa7f10bSFabien Thomas return (0);
2121fa7f10bSFabien Thomas }
2131fa7f10bSFabien Thomas
2141fa7f10bSFabien Thomas static int
ucf_config_pmc(int cpu,int ri,struct pmc * pm)2151fa7f10bSFabien Thomas ucf_config_pmc(int cpu, int ri, struct pmc *pm)
2161fa7f10bSFabien Thomas {
2171fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
2181fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU %d", __LINE__, cpu));
2191fa7f10bSFabien Thomas
2201fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucf_npmc,
2211fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
2221fa7f10bSFabien Thomas
2234a3690dfSJohn Baldwin PMCDBG3(MDP,CFG,1, "ucf-config cpu=%d ri=%d pm=%p", cpu, ri, pm);
2241fa7f10bSFabien Thomas
2251fa7f10bSFabien Thomas KASSERT(uncore_pcpu[cpu] != NULL, ("[uncore,%d] null per-cpu %d", __LINE__,
2261fa7f10bSFabien Thomas cpu));
2271fa7f10bSFabien Thomas
2281fa7f10bSFabien Thomas uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc = pm;
2291fa7f10bSFabien Thomas
2301fa7f10bSFabien Thomas return (0);
2311fa7f10bSFabien Thomas }
2321fa7f10bSFabien Thomas
2331fa7f10bSFabien Thomas static int
ucf_describe(int cpu,int ri,struct pmc_info * pi,struct pmc ** ppmc)2341fa7f10bSFabien Thomas ucf_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
2351fa7f10bSFabien Thomas {
2361fa7f10bSFabien Thomas struct pmc_hw *phw;
2371fa7f10bSFabien Thomas
2381fa7f10bSFabien Thomas phw = &uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri];
2391fa7f10bSFabien Thomas
24031610e34SMitchell Horne snprintf(pi->pm_name, sizeof(pi->pm_name), "UCF-%d", ri);
2411fa7f10bSFabien Thomas pi->pm_class = PMC_CLASS_UCF;
2421fa7f10bSFabien Thomas
2431fa7f10bSFabien Thomas if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
2441fa7f10bSFabien Thomas pi->pm_enabled = TRUE;
2451fa7f10bSFabien Thomas *ppmc = phw->phw_pmc;
2461fa7f10bSFabien Thomas } else {
2471fa7f10bSFabien Thomas pi->pm_enabled = FALSE;
2481fa7f10bSFabien Thomas *ppmc = NULL;
2491fa7f10bSFabien Thomas }
2501fa7f10bSFabien Thomas
2511fa7f10bSFabien Thomas return (0);
2521fa7f10bSFabien Thomas }
2531fa7f10bSFabien Thomas
2541fa7f10bSFabien Thomas static int
ucf_get_config(int cpu,int ri,struct pmc ** ppm)2551fa7f10bSFabien Thomas ucf_get_config(int cpu, int ri, struct pmc **ppm)
2561fa7f10bSFabien Thomas {
2571fa7f10bSFabien Thomas *ppm = uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc;
2581fa7f10bSFabien Thomas
2591fa7f10bSFabien Thomas return (0);
2601fa7f10bSFabien Thomas }
2611fa7f10bSFabien Thomas
2621fa7f10bSFabien Thomas static int
ucf_read_pmc(int cpu,int ri,struct pmc * pm,pmc_value_t * v)26339f92a76SMitchell Horne ucf_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v)
2641fa7f10bSFabien Thomas {
2651fa7f10bSFabien Thomas pmc_value_t tmp;
2661fa7f10bSFabien Thomas
2671fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
2681fa7f10bSFabien Thomas ("[uncore,%d] illegal cpu value %d", __LINE__, cpu));
2691fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucf_npmc,
2701fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
2711fa7f10bSFabien Thomas
2721fa7f10bSFabien Thomas tmp = rdmsr(UCF_CTR0 + ri);
2731fa7f10bSFabien Thomas
2741fa7f10bSFabien Thomas if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
2751fa7f10bSFabien Thomas *v = ucf_perfctr_value_to_reload_count(tmp);
2761fa7f10bSFabien Thomas else
2771fa7f10bSFabien Thomas *v = tmp;
2781fa7f10bSFabien Thomas
2794a3690dfSJohn Baldwin PMCDBG3(MDP,REA,1, "ucf-read cpu=%d ri=%d -> v=%jx", cpu, ri, *v);
2801fa7f10bSFabien Thomas
2811fa7f10bSFabien Thomas return (0);
2821fa7f10bSFabien Thomas }
2831fa7f10bSFabien Thomas
2841fa7f10bSFabien Thomas static int
ucf_release_pmc(int cpu,int ri,struct pmc * pmc)2851fa7f10bSFabien Thomas ucf_release_pmc(int cpu, int ri, struct pmc *pmc)
2861fa7f10bSFabien Thomas {
2874a3690dfSJohn Baldwin PMCDBG3(MDP,REL,1, "ucf-release cpu=%d ri=%d pm=%p", cpu, ri, pmc);
2881fa7f10bSFabien Thomas
2891fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
2901fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU value %d", __LINE__, cpu));
2911fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucf_npmc,
2921fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
2931fa7f10bSFabien Thomas
2941fa7f10bSFabien Thomas KASSERT(uncore_pcpu[cpu]->pc_uncorepmcs[ri + uncore_ucf_ri].phw_pmc == NULL,
2951fa7f10bSFabien Thomas ("[uncore,%d] PHW pmc non-NULL", __LINE__));
2961fa7f10bSFabien Thomas
2971fa7f10bSFabien Thomas return (0);
2981fa7f10bSFabien Thomas }
2991fa7f10bSFabien Thomas
3001fa7f10bSFabien Thomas static int
ucf_start_pmc(int cpu,int ri,struct pmc * pm)30139f92a76SMitchell Horne ucf_start_pmc(int cpu, int ri, struct pmc *pm)
3021fa7f10bSFabien Thomas {
3031fa7f10bSFabien Thomas struct uncore_cpu *ucfc;
3041fa7f10bSFabien Thomas
3051fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
3061fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU value %d", __LINE__, cpu));
3071fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucf_npmc,
3081fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
3091fa7f10bSFabien Thomas
3104a3690dfSJohn Baldwin PMCDBG2(MDP,STA,1,"ucf-start cpu=%d ri=%d", cpu, ri);
3111fa7f10bSFabien Thomas
3121fa7f10bSFabien Thomas ucfc = uncore_pcpu[cpu];
3131fa7f10bSFabien Thomas ucfc->pc_ucfctrl |= pm->pm_md.pm_ucf.pm_ucf_ctrl;
3141fa7f10bSFabien Thomas
3151fa7f10bSFabien Thomas wrmsr(UCF_CTRL, ucfc->pc_ucfctrl);
3161fa7f10bSFabien Thomas
31778d763a2SDavide Italiano ucfc->pc_globalctrl |= (1ULL << (ri + SELECTOFF(uncore_cputype)));
3181fa7f10bSFabien Thomas wrmsr(UC_GLOBAL_CTRL, ucfc->pc_globalctrl);
3191fa7f10bSFabien Thomas
3204a3690dfSJohn Baldwin PMCDBG4(MDP,STA,1,"ucfctrl=%x(%x) globalctrl=%jx(%jx)",
3211fa7f10bSFabien Thomas ucfc->pc_ucfctrl, (uint32_t) rdmsr(UCF_CTRL),
3221fa7f10bSFabien Thomas ucfc->pc_globalctrl, rdmsr(UC_GLOBAL_CTRL));
3231fa7f10bSFabien Thomas
3241fa7f10bSFabien Thomas return (0);
3251fa7f10bSFabien Thomas }
3261fa7f10bSFabien Thomas
3271fa7f10bSFabien Thomas static int
ucf_stop_pmc(int cpu,int ri,struct pmc * pm __unused)32839f92a76SMitchell Horne ucf_stop_pmc(int cpu, int ri, struct pmc *pm __unused)
3291fa7f10bSFabien Thomas {
3301fa7f10bSFabien Thomas uint32_t fc;
3311fa7f10bSFabien Thomas struct uncore_cpu *ucfc;
3321fa7f10bSFabien Thomas
3334a3690dfSJohn Baldwin PMCDBG2(MDP,STO,1,"ucf-stop cpu=%d ri=%d", cpu, ri);
3341fa7f10bSFabien Thomas
3351fa7f10bSFabien Thomas ucfc = uncore_pcpu[cpu];
3361fa7f10bSFabien Thomas
3371fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
3381fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU value %d", __LINE__, cpu));
3391fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucf_npmc,
3401fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
3411fa7f10bSFabien Thomas
3421fa7f10bSFabien Thomas fc = (UCF_MASK << (ri * 4));
3431fa7f10bSFabien Thomas
3441fa7f10bSFabien Thomas ucfc->pc_ucfctrl &= ~fc;
3451fa7f10bSFabien Thomas
3464a3690dfSJohn Baldwin PMCDBG1(MDP,STO,1,"ucf-stop ucfctrl=%x", ucfc->pc_ucfctrl);
3471fa7f10bSFabien Thomas wrmsr(UCF_CTRL, ucfc->pc_ucfctrl);
3481fa7f10bSFabien Thomas
349326a8d3eSAlexander Motin /* Don't need to write UC_GLOBAL_CTRL, one disable is enough. */
3501fa7f10bSFabien Thomas
3514a3690dfSJohn Baldwin PMCDBG4(MDP,STO,1,"ucfctrl=%x(%x) globalctrl=%jx(%jx)",
3521fa7f10bSFabien Thomas ucfc->pc_ucfctrl, (uint32_t) rdmsr(UCF_CTRL),
3531fa7f10bSFabien Thomas ucfc->pc_globalctrl, rdmsr(UC_GLOBAL_CTRL));
3541fa7f10bSFabien Thomas
3551fa7f10bSFabien Thomas return (0);
3561fa7f10bSFabien Thomas }
3571fa7f10bSFabien Thomas
3581fa7f10bSFabien Thomas static int
ucf_write_pmc(int cpu,int ri,struct pmc * pm,pmc_value_t v)35939f92a76SMitchell Horne ucf_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v)
3601fa7f10bSFabien Thomas {
3611fa7f10bSFabien Thomas struct uncore_cpu *cc;
3621fa7f10bSFabien Thomas
3631fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
3641fa7f10bSFabien Thomas ("[uncore,%d] illegal cpu value %d", __LINE__, cpu));
3651fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucf_npmc,
3661fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
3671fa7f10bSFabien Thomas
3681fa7f10bSFabien Thomas cc = uncore_pcpu[cpu];
3691fa7f10bSFabien Thomas
3701fa7f10bSFabien Thomas if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
3711fa7f10bSFabien Thomas v = ucf_reload_count_to_perfctr_value(v);
3721fa7f10bSFabien Thomas
3731fa7f10bSFabien Thomas wrmsr(UCF_CTRL, 0); /* Turn off fixed counters */
3741fa7f10bSFabien Thomas wrmsr(UCF_CTR0 + ri, v);
3751fa7f10bSFabien Thomas wrmsr(UCF_CTRL, cc->pc_ucfctrl);
3761fa7f10bSFabien Thomas
3774a3690dfSJohn Baldwin PMCDBG4(MDP,WRI,1, "ucf-write cpu=%d ri=%d v=%jx ucfctrl=%jx ",
3781fa7f10bSFabien Thomas cpu, ri, v, (uintmax_t) rdmsr(UCF_CTRL));
3791fa7f10bSFabien Thomas
3801fa7f10bSFabien Thomas return (0);
3811fa7f10bSFabien Thomas }
3821fa7f10bSFabien Thomas
3831fa7f10bSFabien Thomas
3841fa7f10bSFabien Thomas static void
ucf_initialize(struct pmc_mdep * md,int maxcpu,int npmc,int pmcwidth)3851fa7f10bSFabien Thomas ucf_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth)
3861fa7f10bSFabien Thomas {
3871fa7f10bSFabien Thomas struct pmc_classdep *pcd;
3881fa7f10bSFabien Thomas
3891fa7f10bSFabien Thomas KASSERT(md != NULL, ("[ucf,%d] md is NULL", __LINE__));
3901fa7f10bSFabien Thomas
3914a3690dfSJohn Baldwin PMCDBG0(MDP,INI,1, "ucf-initialize");
3921fa7f10bSFabien Thomas
3931fa7f10bSFabien Thomas pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCF];
3941fa7f10bSFabien Thomas
3951fa7f10bSFabien Thomas pcd->pcd_caps = UCF_PMC_CAPS;
3961fa7f10bSFabien Thomas pcd->pcd_class = PMC_CLASS_UCF;
3971fa7f10bSFabien Thomas pcd->pcd_num = npmc;
3981fa7f10bSFabien Thomas pcd->pcd_ri = md->pmd_npmc;
3991fa7f10bSFabien Thomas pcd->pcd_width = pmcwidth;
4001fa7f10bSFabien Thomas
4011fa7f10bSFabien Thomas pcd->pcd_allocate_pmc = ucf_allocate_pmc;
4021fa7f10bSFabien Thomas pcd->pcd_config_pmc = ucf_config_pmc;
4031fa7f10bSFabien Thomas pcd->pcd_describe = ucf_describe;
4041fa7f10bSFabien Thomas pcd->pcd_get_config = ucf_get_config;
4051fa7f10bSFabien Thomas pcd->pcd_get_msr = NULL;
4061fa7f10bSFabien Thomas pcd->pcd_pcpu_fini = uncore_pcpu_noop;
4071fa7f10bSFabien Thomas pcd->pcd_pcpu_init = uncore_pcpu_noop;
4081fa7f10bSFabien Thomas pcd->pcd_read_pmc = ucf_read_pmc;
4091fa7f10bSFabien Thomas pcd->pcd_release_pmc = ucf_release_pmc;
4101fa7f10bSFabien Thomas pcd->pcd_start_pmc = ucf_start_pmc;
4111fa7f10bSFabien Thomas pcd->pcd_stop_pmc = ucf_stop_pmc;
4121fa7f10bSFabien Thomas pcd->pcd_write_pmc = ucf_write_pmc;
4131fa7f10bSFabien Thomas
4141fa7f10bSFabien Thomas md->pmd_npmc += npmc;
4151fa7f10bSFabien Thomas }
4161fa7f10bSFabien Thomas
4171fa7f10bSFabien Thomas /*
4181fa7f10bSFabien Thomas * Intel programmable PMCs.
4191fa7f10bSFabien Thomas */
4201fa7f10bSFabien Thomas
4211fa7f10bSFabien Thomas /*
4221fa7f10bSFabien Thomas * Event descriptor tables.
4231fa7f10bSFabien Thomas *
4241fa7f10bSFabien Thomas * For each event id, we track:
4251fa7f10bSFabien Thomas *
4261fa7f10bSFabien Thomas * 1. The CPUs that the event is valid for.
4271fa7f10bSFabien Thomas *
4281fa7f10bSFabien Thomas * 2. If the event uses a fixed UMASK, the value of the umask field.
4291fa7f10bSFabien Thomas * If the event doesn't use a fixed UMASK, a mask of legal bits
4301fa7f10bSFabien Thomas * to check against.
4311fa7f10bSFabien Thomas */
4321fa7f10bSFabien Thomas
4331fa7f10bSFabien Thomas struct ucp_event_descr {
4341fa7f10bSFabien Thomas enum pmc_event ucp_ev;
4351fa7f10bSFabien Thomas unsigned char ucp_evcode;
4361fa7f10bSFabien Thomas unsigned char ucp_umask;
4371fa7f10bSFabien Thomas unsigned char ucp_flags;
4381fa7f10bSFabien Thomas };
4391fa7f10bSFabien Thomas
4401fa7f10bSFabien Thomas #define UCP_F_I7 (1 << 0) /* CPU: Core i7 */
4411fa7f10bSFabien Thomas #define UCP_F_WM (1 << 1) /* CPU: Westmere */
44278d763a2SDavide Italiano #define UCP_F_SB (1 << 2) /* CPU: Sandy Bridge */
443cc0c1555SSean Bruno #define UCP_F_HW (1 << 3) /* CPU: Haswell */
444cc0c1555SSean Bruno #define UCP_F_FM (1 << 4) /* Fixed mask */
4451fa7f10bSFabien Thomas
4461fa7f10bSFabien Thomas #define UCP_F_ALLCPUS \
4471fa7f10bSFabien Thomas (UCP_F_I7 | UCP_F_WM)
4481fa7f10bSFabien Thomas
4491fa7f10bSFabien Thomas #define UCP_F_CMASK 0xFF000000
4501fa7f10bSFabien Thomas
4511fa7f10bSFabien Thomas static pmc_value_t
ucp_perfctr_value_to_reload_count(pmc_value_t v)4521fa7f10bSFabien Thomas ucp_perfctr_value_to_reload_count(pmc_value_t v)
4531fa7f10bSFabien Thomas {
4541fa7f10bSFabien Thomas v &= (1ULL << uncore_ucp_width) - 1;
4551fa7f10bSFabien Thomas return (1ULL << uncore_ucp_width) - v;
4561fa7f10bSFabien Thomas }
4571fa7f10bSFabien Thomas
4581fa7f10bSFabien Thomas static pmc_value_t
ucp_reload_count_to_perfctr_value(pmc_value_t rlc)4591fa7f10bSFabien Thomas ucp_reload_count_to_perfctr_value(pmc_value_t rlc)
4601fa7f10bSFabien Thomas {
4611fa7f10bSFabien Thomas return (1ULL << uncore_ucp_width) - rlc;
4621fa7f10bSFabien Thomas }
4631fa7f10bSFabien Thomas
464cc0c1555SSean Bruno /*
465cc0c1555SSean Bruno * Counter specific event information for Sandybridge and Haswell
466cc0c1555SSean Bruno */
4671fa7f10bSFabien Thomas static int
ucp_event_sb_hw_ok_on_counter(uint8_t ev,int ri)468e92a1350SMatt Macy ucp_event_sb_hw_ok_on_counter(uint8_t ev, int ri)
46978d763a2SDavide Italiano {
47078d763a2SDavide Italiano uint32_t mask;
47178d763a2SDavide Italiano
472e92a1350SMatt Macy switch (ev) {
47378d763a2SDavide Italiano /*
47478d763a2SDavide Italiano * Events valid only on counter 0.
47578d763a2SDavide Italiano */
476e92a1350SMatt Macy case 0x80:
477e92a1350SMatt Macy case 0x83:
47878d763a2SDavide Italiano mask = (1 << 0);
47978d763a2SDavide Italiano break;
48078d763a2SDavide Italiano
48178d763a2SDavide Italiano default:
48278d763a2SDavide Italiano mask = ~0; /* Any row index is ok. */
48378d763a2SDavide Italiano }
48478d763a2SDavide Italiano
48578d763a2SDavide Italiano return (mask & (1 << ri));
48678d763a2SDavide Italiano }
48778d763a2SDavide Italiano
48878d763a2SDavide Italiano static int
ucp_allocate_pmc(int cpu,int ri,struct pmc * pm,const struct pmc_op_pmcallocate * a)4891fa7f10bSFabien Thomas ucp_allocate_pmc(int cpu, int ri, struct pmc *pm,
4901fa7f10bSFabien Thomas const struct pmc_op_pmcallocate *a)
4911fa7f10bSFabien Thomas {
492e92a1350SMatt Macy uint8_t ev;
493e92a1350SMatt Macy const struct pmc_md_ucp_op_pmcallocate *ucp;
4941fa7f10bSFabien Thomas
4951fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
4961fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU %d", __LINE__, cpu));
4971fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucp_npmc,
4981fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index value %d", __LINE__, ri));
4991fa7f10bSFabien Thomas
500315cd55dSMitchell Horne if (a->pm_class != PMC_CLASS_UCP)
501315cd55dSMitchell Horne return (EINVAL);
502315cd55dSMitchell Horne
503c190fb35SMitchell Horne if ((a->pm_flags & PMC_F_EV_PMU) == 0)
504c190fb35SMitchell Horne return (EINVAL);
505c190fb35SMitchell Horne
506e92a1350SMatt Macy ucp = &a->pm_md.pm_ucp;
507e92a1350SMatt Macy ev = UCP_EVSEL(ucp->pm_ucp_config);
50878d763a2SDavide Italiano switch (uncore_cputype) {
509cc0c1555SSean Bruno case PMC_CPU_INTEL_HASWELL:
51078d763a2SDavide Italiano case PMC_CPU_INTEL_SANDYBRIDGE:
511cc0c1555SSean Bruno if (ucp_event_sb_hw_ok_on_counter(ev, ri) == 0)
51278d763a2SDavide Italiano return (EINVAL);
51378d763a2SDavide Italiano break;
51478d763a2SDavide Italiano default:
51578d763a2SDavide Italiano break;
51678d763a2SDavide Italiano }
51778d763a2SDavide Italiano
518e92a1350SMatt Macy pm->pm_md.pm_ucp.pm_ucp_evsel = ucp->pm_ucp_config | UCP_EN;
5191fa7f10bSFabien Thomas
5201fa7f10bSFabien Thomas return (0);
5211fa7f10bSFabien Thomas }
5221fa7f10bSFabien Thomas
5231fa7f10bSFabien Thomas static int
ucp_config_pmc(int cpu,int ri,struct pmc * pm)5241fa7f10bSFabien Thomas ucp_config_pmc(int cpu, int ri, struct pmc *pm)
5251fa7f10bSFabien Thomas {
5261fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
5271fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU %d", __LINE__, cpu));
5281fa7f10bSFabien Thomas
5291fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucp_npmc,
5301fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
5311fa7f10bSFabien Thomas
5324a3690dfSJohn Baldwin PMCDBG3(MDP,CFG,1, "ucp-config cpu=%d ri=%d pm=%p", cpu, ri, pm);
5331fa7f10bSFabien Thomas
5341fa7f10bSFabien Thomas KASSERT(uncore_pcpu[cpu] != NULL, ("[uncore,%d] null per-cpu %d", __LINE__,
5351fa7f10bSFabien Thomas cpu));
5361fa7f10bSFabien Thomas
5371fa7f10bSFabien Thomas uncore_pcpu[cpu]->pc_uncorepmcs[ri].phw_pmc = pm;
5381fa7f10bSFabien Thomas
5391fa7f10bSFabien Thomas return (0);
5401fa7f10bSFabien Thomas }
5411fa7f10bSFabien Thomas
5421fa7f10bSFabien Thomas static int
ucp_describe(int cpu,int ri,struct pmc_info * pi,struct pmc ** ppmc)5431fa7f10bSFabien Thomas ucp_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
5441fa7f10bSFabien Thomas {
5451fa7f10bSFabien Thomas struct pmc_hw *phw;
5461fa7f10bSFabien Thomas
5471fa7f10bSFabien Thomas phw = &uncore_pcpu[cpu]->pc_uncorepmcs[ri];
5481fa7f10bSFabien Thomas
54931610e34SMitchell Horne snprintf(pi->pm_name, sizeof(pi->pm_name), "UCP-%d", ri);
5501fa7f10bSFabien Thomas pi->pm_class = PMC_CLASS_UCP;
5511fa7f10bSFabien Thomas
5521fa7f10bSFabien Thomas if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
5531fa7f10bSFabien Thomas pi->pm_enabled = TRUE;
5541fa7f10bSFabien Thomas *ppmc = phw->phw_pmc;
5551fa7f10bSFabien Thomas } else {
5561fa7f10bSFabien Thomas pi->pm_enabled = FALSE;
5571fa7f10bSFabien Thomas *ppmc = NULL;
5581fa7f10bSFabien Thomas }
5591fa7f10bSFabien Thomas
5601fa7f10bSFabien Thomas return (0);
5611fa7f10bSFabien Thomas }
5621fa7f10bSFabien Thomas
5631fa7f10bSFabien Thomas static int
ucp_get_config(int cpu,int ri,struct pmc ** ppm)5641fa7f10bSFabien Thomas ucp_get_config(int cpu, int ri, struct pmc **ppm)
5651fa7f10bSFabien Thomas {
5661fa7f10bSFabien Thomas *ppm = uncore_pcpu[cpu]->pc_uncorepmcs[ri].phw_pmc;
5671fa7f10bSFabien Thomas
5681fa7f10bSFabien Thomas return (0);
5691fa7f10bSFabien Thomas }
5701fa7f10bSFabien Thomas
5711fa7f10bSFabien Thomas static int
ucp_read_pmc(int cpu,int ri,struct pmc * pm,pmc_value_t * v)57239f92a76SMitchell Horne ucp_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v)
5731fa7f10bSFabien Thomas {
5741fa7f10bSFabien Thomas pmc_value_t tmp;
5751fa7f10bSFabien Thomas
5761fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
5771fa7f10bSFabien Thomas ("[uncore,%d] illegal cpu value %d", __LINE__, cpu));
5781fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucp_npmc,
5791fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
5801fa7f10bSFabien Thomas
5811fa7f10bSFabien Thomas tmp = rdmsr(UCP_PMC0 + ri);
5821fa7f10bSFabien Thomas if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
5831fa7f10bSFabien Thomas *v = ucp_perfctr_value_to_reload_count(tmp);
5841fa7f10bSFabien Thomas else
5851fa7f10bSFabien Thomas *v = tmp;
5861fa7f10bSFabien Thomas
5874a3690dfSJohn Baldwin PMCDBG4(MDP,REA,1, "ucp-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri,
5881fa7f10bSFabien Thomas ri, *v);
5891fa7f10bSFabien Thomas
5901fa7f10bSFabien Thomas return (0);
5911fa7f10bSFabien Thomas }
5921fa7f10bSFabien Thomas
5931fa7f10bSFabien Thomas static int
ucp_release_pmc(int cpu,int ri,struct pmc * pm)5941fa7f10bSFabien Thomas ucp_release_pmc(int cpu, int ri, struct pmc *pm)
5951fa7f10bSFabien Thomas {
5961fa7f10bSFabien Thomas (void) pm;
5971fa7f10bSFabien Thomas
5984a3690dfSJohn Baldwin PMCDBG3(MDP,REL,1, "ucp-release cpu=%d ri=%d pm=%p", cpu, ri,
5991fa7f10bSFabien Thomas pm);
6001fa7f10bSFabien Thomas
6011fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
6021fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU value %d", __LINE__, cpu));
6031fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucp_npmc,
6041fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
6051fa7f10bSFabien Thomas
6061fa7f10bSFabien Thomas KASSERT(uncore_pcpu[cpu]->pc_uncorepmcs[ri].phw_pmc
6071fa7f10bSFabien Thomas == NULL, ("[uncore,%d] PHW pmc non-NULL", __LINE__));
6081fa7f10bSFabien Thomas
6091fa7f10bSFabien Thomas return (0);
6101fa7f10bSFabien Thomas }
6111fa7f10bSFabien Thomas
6121fa7f10bSFabien Thomas static int
ucp_start_pmc(int cpu,int ri,struct pmc * pm)61339f92a76SMitchell Horne ucp_start_pmc(int cpu, int ri, struct pmc *pm)
6141fa7f10bSFabien Thomas {
6151a4614a5SAlexander Motin uint64_t evsel;
6161fa7f10bSFabien Thomas struct uncore_cpu *cc;
6171fa7f10bSFabien Thomas
6181fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
6191fa7f10bSFabien Thomas ("[uncore,%d] illegal CPU value %d", __LINE__, cpu));
6201fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucp_npmc,
6211fa7f10bSFabien Thomas ("[uncore,%d] illegal row-index %d", __LINE__, ri));
6221fa7f10bSFabien Thomas
6231fa7f10bSFabien Thomas cc = uncore_pcpu[cpu];
6241fa7f10bSFabien Thomas
6254a3690dfSJohn Baldwin PMCDBG2(MDP,STA,1, "ucp-start cpu=%d ri=%d", cpu, ri);
6261fa7f10bSFabien Thomas
6271fa7f10bSFabien Thomas evsel = pm->pm_md.pm_ucp.pm_ucp_evsel;
6281fa7f10bSFabien Thomas
6294a3690dfSJohn Baldwin PMCDBG4(MDP,STA,2,
63078d763a2SDavide Italiano "ucp-start/2 cpu=%d ri=%d evselmsr=0x%x evsel=0x%x",
63178d763a2SDavide Italiano cpu, ri, SELECTSEL(uncore_cputype) + ri, evsel);
6321fa7f10bSFabien Thomas
63378d763a2SDavide Italiano wrmsr(SELECTSEL(uncore_cputype) + ri, evsel);
6341fa7f10bSFabien Thomas
6351fa7f10bSFabien Thomas cc->pc_globalctrl |= (1ULL << ri);
6361fa7f10bSFabien Thomas wrmsr(UC_GLOBAL_CTRL, cc->pc_globalctrl);
6371fa7f10bSFabien Thomas
6381fa7f10bSFabien Thomas return (0);
6391fa7f10bSFabien Thomas }
6401fa7f10bSFabien Thomas
6411fa7f10bSFabien Thomas static int
ucp_stop_pmc(int cpu,int ri,struct pmc * pm __unused)64239f92a76SMitchell Horne ucp_stop_pmc(int cpu, int ri, struct pmc *pm __unused)
6431fa7f10bSFabien Thomas {
6441fa7f10bSFabien Thomas
6451fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
6461fa7f10bSFabien Thomas ("[uncore,%d] illegal cpu value %d", __LINE__, cpu));
6471fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucp_npmc,
6481fa7f10bSFabien Thomas ("[uncore,%d] illegal row index %d", __LINE__, ri));
6491fa7f10bSFabien Thomas
6504a3690dfSJohn Baldwin PMCDBG2(MDP,STO,1, "ucp-stop cpu=%d ri=%d", cpu, ri);
6511fa7f10bSFabien Thomas
65278d763a2SDavide Italiano /* stop hw. */
65378d763a2SDavide Italiano wrmsr(SELECTSEL(uncore_cputype) + ri, 0);
6541fa7f10bSFabien Thomas
655326a8d3eSAlexander Motin /* Don't need to write UC_GLOBAL_CTRL, one disable is enough. */
6561fa7f10bSFabien Thomas
6571fa7f10bSFabien Thomas return (0);
6581fa7f10bSFabien Thomas }
6591fa7f10bSFabien Thomas
6601fa7f10bSFabien Thomas static int
ucp_write_pmc(int cpu,int ri,struct pmc * pm,pmc_value_t v)66139f92a76SMitchell Horne ucp_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v)
6621fa7f10bSFabien Thomas {
6631fa7f10bSFabien Thomas
6641fa7f10bSFabien Thomas KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
6651fa7f10bSFabien Thomas ("[uncore,%d] illegal cpu value %d", __LINE__, cpu));
6661fa7f10bSFabien Thomas KASSERT(ri >= 0 && ri < uncore_ucp_npmc,
6671fa7f10bSFabien Thomas ("[uncore,%d] illegal row index %d", __LINE__, ri));
6681fa7f10bSFabien Thomas
6694a3690dfSJohn Baldwin PMCDBG4(MDP,WRI,1, "ucp-write cpu=%d ri=%d msr=0x%x v=%jx", cpu, ri,
6701fa7f10bSFabien Thomas UCP_PMC0 + ri, v);
6711fa7f10bSFabien Thomas
6721fa7f10bSFabien Thomas if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
6731fa7f10bSFabien Thomas v = ucp_reload_count_to_perfctr_value(v);
6741fa7f10bSFabien Thomas
6751fa7f10bSFabien Thomas /*
6761fa7f10bSFabien Thomas * Write the new value to the counter. The counter will be in
6771fa7f10bSFabien Thomas * a stopped state when the pcd_write() entry point is called.
6781fa7f10bSFabien Thomas */
6791fa7f10bSFabien Thomas
6801fa7f10bSFabien Thomas wrmsr(UCP_PMC0 + ri, v);
6811fa7f10bSFabien Thomas
6821fa7f10bSFabien Thomas return (0);
6831fa7f10bSFabien Thomas }
6841fa7f10bSFabien Thomas
6851fa7f10bSFabien Thomas
6861fa7f10bSFabien Thomas static void
ucp_initialize(struct pmc_mdep * md,int maxcpu,int npmc,int pmcwidth)6871fa7f10bSFabien Thomas ucp_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth)
6881fa7f10bSFabien Thomas {
6891fa7f10bSFabien Thomas struct pmc_classdep *pcd;
6901fa7f10bSFabien Thomas
6911fa7f10bSFabien Thomas KASSERT(md != NULL, ("[ucp,%d] md is NULL", __LINE__));
6921fa7f10bSFabien Thomas
6934a3690dfSJohn Baldwin PMCDBG0(MDP,INI,1, "ucp-initialize");
6941fa7f10bSFabien Thomas
6951fa7f10bSFabien Thomas pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_UCP];
6961fa7f10bSFabien Thomas
6971fa7f10bSFabien Thomas pcd->pcd_caps = UCP_PMC_CAPS;
6981fa7f10bSFabien Thomas pcd->pcd_class = PMC_CLASS_UCP;
6991fa7f10bSFabien Thomas pcd->pcd_num = npmc;
7001fa7f10bSFabien Thomas pcd->pcd_ri = md->pmd_npmc;
7011fa7f10bSFabien Thomas pcd->pcd_width = pmcwidth;
7021fa7f10bSFabien Thomas
7031fa7f10bSFabien Thomas pcd->pcd_allocate_pmc = ucp_allocate_pmc;
7041fa7f10bSFabien Thomas pcd->pcd_config_pmc = ucp_config_pmc;
7051fa7f10bSFabien Thomas pcd->pcd_describe = ucp_describe;
7061fa7f10bSFabien Thomas pcd->pcd_get_config = ucp_get_config;
7071fa7f10bSFabien Thomas pcd->pcd_get_msr = NULL;
7081fa7f10bSFabien Thomas pcd->pcd_pcpu_fini = uncore_pcpu_fini;
7091fa7f10bSFabien Thomas pcd->pcd_pcpu_init = uncore_pcpu_init;
7101fa7f10bSFabien Thomas pcd->pcd_read_pmc = ucp_read_pmc;
7111fa7f10bSFabien Thomas pcd->pcd_release_pmc = ucp_release_pmc;
7121fa7f10bSFabien Thomas pcd->pcd_start_pmc = ucp_start_pmc;
7131fa7f10bSFabien Thomas pcd->pcd_stop_pmc = ucp_stop_pmc;
7141fa7f10bSFabien Thomas pcd->pcd_write_pmc = ucp_write_pmc;
7151fa7f10bSFabien Thomas
7161fa7f10bSFabien Thomas md->pmd_npmc += npmc;
7171fa7f10bSFabien Thomas }
7181fa7f10bSFabien Thomas
7191fa7f10bSFabien Thomas int
pmc_uncore_initialize(struct pmc_mdep * md,int maxcpu)7201fa7f10bSFabien Thomas pmc_uncore_initialize(struct pmc_mdep *md, int maxcpu)
7211fa7f10bSFabien Thomas {
7221fa7f10bSFabien Thomas uncore_cputype = md->pmd_cputype;
7231fa7f10bSFabien Thomas uncore_pmcmask = 0;
7241fa7f10bSFabien Thomas
7251fa7f10bSFabien Thomas /*
7261fa7f10bSFabien Thomas * Initialize programmable counters.
7271fa7f10bSFabien Thomas */
7281fa7f10bSFabien Thomas
7291fa7f10bSFabien Thomas uncore_ucp_npmc = 8;
7301fa7f10bSFabien Thomas uncore_ucp_width = 48;
7311fa7f10bSFabien Thomas
7321fa7f10bSFabien Thomas uncore_pmcmask |= ((1ULL << uncore_ucp_npmc) - 1);
7331fa7f10bSFabien Thomas
7341fa7f10bSFabien Thomas ucp_initialize(md, maxcpu, uncore_ucp_npmc, uncore_ucp_width);
7351fa7f10bSFabien Thomas
7361fa7f10bSFabien Thomas /*
7371fa7f10bSFabien Thomas * Initialize fixed function counters, if present.
7381fa7f10bSFabien Thomas */
7391fa7f10bSFabien Thomas uncore_ucf_ri = uncore_ucp_npmc;
7401fa7f10bSFabien Thomas uncore_ucf_npmc = 1;
7411fa7f10bSFabien Thomas uncore_ucf_width = 48;
7421fa7f10bSFabien Thomas
7431fa7f10bSFabien Thomas ucf_initialize(md, maxcpu, uncore_ucf_npmc, uncore_ucf_width);
74478d763a2SDavide Italiano uncore_pmcmask |= ((1ULL << uncore_ucf_npmc) - 1) << SELECTOFF(uncore_cputype);
7451fa7f10bSFabien Thomas
7464a3690dfSJohn Baldwin PMCDBG2(MDP,INI,1,"uncore-init pmcmask=0x%jx ucfri=%d", uncore_pmcmask,
7471fa7f10bSFabien Thomas uncore_ucf_ri);
7481fa7f10bSFabien Thomas
749c08da142SEitan Adler uncore_pcpu = malloc(sizeof(*uncore_pcpu) * maxcpu, M_PMC,
7501fa7f10bSFabien Thomas M_ZERO | M_WAITOK);
7511fa7f10bSFabien Thomas
7521fa7f10bSFabien Thomas return (0);
7531fa7f10bSFabien Thomas }
7541fa7f10bSFabien Thomas
7551fa7f10bSFabien Thomas void
pmc_uncore_finalize(struct pmc_mdep * md)7561fa7f10bSFabien Thomas pmc_uncore_finalize(struct pmc_mdep *md)
7571fa7f10bSFabien Thomas {
7584a3690dfSJohn Baldwin PMCDBG0(MDP,INI,1, "uncore-finalize");
7591fa7f10bSFabien Thomas
760*90a6ea5cSMitchell Horne for (int i = 0; i < pmc_cpu_max(); i++)
761*90a6ea5cSMitchell Horne KASSERT(uncore_pcpu[i] == NULL,
762*90a6ea5cSMitchell Horne ("[uncore,%d] non-null pcpu cpu %d", __LINE__, i));
763*90a6ea5cSMitchell Horne
7641fa7f10bSFabien Thomas free(uncore_pcpu, M_PMC);
7651fa7f10bSFabien Thomas uncore_pcpu = NULL;
7661fa7f10bSFabien Thomas }
767