2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2008 Joseph Koshy
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/param.h>
36 #include <sys/pmckern.h>
38 #include <sys/systm.h>
40 #include <machine/intr_machdep.h>
41 #include <x86/apicvar.h>
42 #include <machine/cpu.h>
43 #include <machine/cpufunc.h>
44 #include <machine/md_var.h>
45 #include <machine/specialreg.h>
47 #define CORE_CPUID_REQUEST 0xA
48 #define CORE_CPUID_REQUEST_SIZE 0x4
49 #define CORE_CPUID_EAX 0x0
50 #define CORE_CPUID_EBX 0x1
51 #define CORE_CPUID_ECX 0x2
52 #define CORE_CPUID_EDX 0x3
54 #define IAF_PMC_CAPS \
55 (PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_INTERRUPT | \
56 PMC_CAP_USER | PMC_CAP_SYSTEM)
57 #define IAF_RI_TO_MSR(RI) ((RI) + (1 << 30))
59 #define IAP_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | PMC_CAP_SYSTEM | \
60 PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \
61 PMC_CAP_INVERT | PMC_CAP_QUALIFIER | PMC_CAP_PRECISE)
63 #define EV_IS_NOTARCH 0
64 #define EV_IS_ARCH_SUPP 1
65 #define EV_IS_ARCH_NOTSUPP -1
68 * "Architectural" events defined by Intel. The values of these
69 * symbols correspond to positions in the bitmask returned by
70 * the CPUID.0AH instruction.
72 enum core_arch_events {
73 CORE_AE_BRANCH_INSTRUCTION_RETIRED = 5,
74 CORE_AE_BRANCH_MISSES_RETIRED = 6,
75 CORE_AE_INSTRUCTION_RETIRED = 1,
76 CORE_AE_LLC_MISSES = 4,
77 CORE_AE_LLC_REFERENCE = 3,
78 CORE_AE_UNHALTED_REFERENCE_CYCLES = 2,
79 CORE_AE_UNHALTED_CORE_CYCLES = 0
82 static enum pmc_cputype core_cputype;
83 static int core_version;
86 volatile uint32_t pc_iafctrl; /* Fixed function control. */
87 volatile uint64_t pc_globalctrl; /* Global control register. */
88 struct pmc_hw pc_corepmcs[];
91 static struct core_cpu **core_pcpu;
93 static uint32_t core_architectural_events;
94 static uint64_t core_pmcmask;
96 static int core_iaf_ri; /* relative index of fixed counters */
97 static int core_iaf_width;
98 static int core_iaf_npmc;
100 static int core_iap_width;
101 static int core_iap_npmc;
102 static int core_iap_wroffset;
104 static u_int pmc_alloc_refs;
105 static bool pmc_tsx_force_abort_set;
108 core_pcpu_noop(struct pmc_mdep *md, int cpu)
116 core_pcpu_init(struct pmc_mdep *md, int cpu)
121 int core_ri, n, npmc;
123 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
124 ("[iaf,%d] insane cpu number %d", __LINE__, cpu));
126 PMCDBG1(MDP,INI,1,"core-init cpu=%d", cpu);
128 core_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_ri;
129 npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_num;
131 if (core_version >= 2)
132 npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF].pcd_num;
134 cc = malloc(sizeof(struct core_cpu) + npmc * sizeof(struct pmc_hw),
135 M_PMC, M_WAITOK | M_ZERO);
140 KASSERT(pc != NULL && cc != NULL,
141 ("[core,%d] NULL per-cpu structures cpu=%d", __LINE__, cpu));
143 for (n = 0, phw = cc->pc_corepmcs; n < npmc; n++, phw++) {
144 phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
145 PMC_PHW_CPU_TO_STATE(cpu) |
146 PMC_PHW_INDEX_TO_STATE(n + core_ri);
148 pc->pc_hwpmcs[n + core_ri] = phw;
151 if (core_version >= 2 && vm_guest == VM_GUEST_NO) {
152 /* Enable Freezing PMCs on PMI. */
153 wrmsr(MSR_DEBUGCTLMSR, rdmsr(MSR_DEBUGCTLMSR) | 0x1000);
160 core_pcpu_fini(struct pmc_mdep *md, int cpu)
162 int core_ri, n, npmc;
166 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
167 ("[core,%d] insane cpu number (%d)", __LINE__, cpu));
169 PMCDBG1(MDP,INI,1,"core-pcpu-fini cpu=%d", cpu);
171 if ((cc = core_pcpu[cpu]) == NULL)
174 core_pcpu[cpu] = NULL;
178 KASSERT(pc != NULL, ("[core,%d] NULL per-cpu %d state", __LINE__,
181 npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_num;
182 core_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_ri;
184 for (n = 0; n < npmc; n++)
185 wrmsr(IAP_EVSEL0 + n, 0);
187 if (core_version >= 2) {
189 npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF].pcd_num;
192 for (n = 0; n < npmc; n++)
193 pc->pc_hwpmcs[n + core_ri] = NULL;
201 * Fixed function counters.
205 iaf_perfctr_value_to_reload_count(pmc_value_t v)
208 /* If the PMC has overflowed, return a reload count of zero. */
209 if ((v & (1ULL << (core_iaf_width - 1))) == 0)
211 v &= (1ULL << core_iaf_width) - 1;
212 return (1ULL << core_iaf_width) - v;
216 iaf_reload_count_to_perfctr_value(pmc_value_t rlc)
218 return (1ULL << core_iaf_width) - rlc;
222 iaf_allocate_pmc(int cpu, int ri, struct pmc *pm,
223 const struct pmc_op_pmcallocate *a)
227 uint64_t config, flags;
228 const struct pmc_md_iap_op_pmcallocate *iap;
230 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
231 ("[core,%d] illegal CPU %d", __LINE__, cpu));
233 PMCDBG2(MDP,ALL,1, "iaf-allocate ri=%d reqcaps=0x%x", ri, pm->pm_caps);
235 if (ri < 0 || ri > core_iaf_npmc)
238 if (a->pm_class != PMC_CLASS_IAF)
241 if ((a->pm_flags & PMC_F_EV_PMU) == 0)
244 iap = &a->pm_md.pm_iap;
245 config = iap->pm_iap_config;
246 ev = IAP_EVSEL_GET(config);
247 umask = IAP_UMASK_GET(config);
254 case 0: /* INST_RETIRED.ANY */
255 if (ev != 0xC0 || umask != 0x00)
258 case 1: /* CPU_CLK_UNHALTED.THREAD */
259 if (ev != 0x3C || umask != 0x00)
262 case 2: /* CPU_CLK_UNHALTED.REF */
263 if (ev != 0x3C || umask != 0x01)
266 case 3: /* TOPDOWN.SLOTS */
267 if (ev != 0xA4 || umask != 0x01)
276 if ((cpu_stdext_feature3 & CPUID_STDEXT3_TSXFA) != 0 &&
277 !pmc_tsx_force_abort_set) {
278 pmc_tsx_force_abort_set = true;
279 x86_msr_op(MSR_TSX_FORCE_ABORT, MSR_OP_RENDEZVOUS_ALL |
280 MSR_OP_WRITE, 1, NULL);
286 if (config & IAP_USR)
288 if (config & IAP_ANY)
290 if (config & IAP_INT)
294 if (caps & PMC_CAP_INTERRUPT)
296 if (caps & PMC_CAP_SYSTEM)
298 if (caps & PMC_CAP_USER)
300 if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
301 flags |= (IAF_OS | IAF_USR);
303 pm->pm_md.pm_iaf.pm_iaf_ctrl = (flags << (ri * 4));
305 PMCDBG1(MDP,ALL,2, "iaf-allocate config=0x%jx",
306 (uintmax_t) pm->pm_md.pm_iaf.pm_iaf_ctrl);
312 iaf_config_pmc(int cpu, int ri, struct pmc *pm)
314 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
315 ("[core,%d] illegal CPU %d", __LINE__, cpu));
317 KASSERT(ri >= 0 && ri < core_iaf_npmc,
318 ("[core,%d] illegal row-index %d", __LINE__, ri));
320 PMCDBG3(MDP,CFG,1, "iaf-config cpu=%d ri=%d pm=%p", cpu, ri, pm);
322 KASSERT(core_pcpu[cpu] != NULL, ("[core,%d] null per-cpu %d", __LINE__,
325 core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc = pm;
331 iaf_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
335 phw = &core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri];
337 snprintf(pi->pm_name, sizeof(pi->pm_name), "IAF-%d", ri);
338 pi->pm_class = PMC_CLASS_IAF;
340 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
341 pi->pm_enabled = TRUE;
342 *ppmc = phw->phw_pmc;
344 pi->pm_enabled = FALSE;
352 iaf_get_config(int cpu, int ri, struct pmc **ppm)
354 *ppm = core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc;
360 iaf_get_msr(int ri, uint32_t *msr)
362 KASSERT(ri >= 0 && ri < core_iaf_npmc,
363 ("[iaf,%d] ri %d out of range", __LINE__, ri));
365 *msr = IAF_RI_TO_MSR(ri);
371 iaf_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v)
375 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
376 ("[core,%d] illegal cpu value %d", __LINE__, cpu));
377 KASSERT(ri >= 0 && ri < core_iaf_npmc,
378 ("[core,%d] illegal row-index %d", __LINE__, ri));
380 tmp = rdpmc(IAF_RI_TO_MSR(ri));
382 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
383 *v = iaf_perfctr_value_to_reload_count(tmp);
385 *v = tmp & ((1ULL << core_iaf_width) - 1);
387 PMCDBG4(MDP,REA,1, "iaf-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri,
388 IAF_RI_TO_MSR(ri), *v);
394 iaf_release_pmc(int cpu, int ri, struct pmc *pmc)
396 PMCDBG3(MDP,REL,1, "iaf-release cpu=%d ri=%d pm=%p", cpu, ri, pmc);
398 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
399 ("[core,%d] illegal CPU value %d", __LINE__, cpu));
400 KASSERT(ri >= 0 && ri < core_iaf_npmc,
401 ("[core,%d] illegal row-index %d", __LINE__, ri));
403 KASSERT(core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc == NULL,
404 ("[core,%d] PHW pmc non-NULL", __LINE__));
406 MPASS(pmc_alloc_refs > 0);
407 if (pmc_alloc_refs-- == 1 && pmc_tsx_force_abort_set) {
408 pmc_tsx_force_abort_set = false;
409 x86_msr_op(MSR_TSX_FORCE_ABORT, MSR_OP_RENDEZVOUS_ALL |
410 MSR_OP_WRITE, 0, NULL);
417 iaf_start_pmc(int cpu, int ri, struct pmc *pm)
421 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
422 ("[core,%d] illegal CPU value %d", __LINE__, cpu));
423 KASSERT(ri >= 0 && ri < core_iaf_npmc,
424 ("[core,%d] illegal row-index %d", __LINE__, ri));
426 PMCDBG2(MDP,STA,1,"iaf-start cpu=%d ri=%d", cpu, ri);
429 cc->pc_iafctrl |= pm->pm_md.pm_iaf.pm_iaf_ctrl;
430 wrmsr(IAF_CTRL, cc->pc_iafctrl);
432 cc->pc_globalctrl |= (1ULL << (ri + IAF_OFFSET));
433 wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl);
435 PMCDBG4(MDP,STA,1,"iafctrl=%x(%x) globalctrl=%jx(%jx)",
436 cc->pc_iafctrl, (uint32_t) rdmsr(IAF_CTRL),
437 cc->pc_globalctrl, rdmsr(IA_GLOBAL_CTRL));
443 iaf_stop_pmc(int cpu, int ri, struct pmc *pm)
447 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
448 ("[core,%d] illegal CPU value %d", __LINE__, cpu));
449 KASSERT(ri >= 0 && ri < core_iaf_npmc,
450 ("[core,%d] illegal row-index %d", __LINE__, ri));
452 PMCDBG2(MDP,STA,1,"iaf-stop cpu=%d ri=%d", cpu, ri);
456 cc->pc_iafctrl &= ~(IAF_MASK << (ri * 4));
457 wrmsr(IAF_CTRL, cc->pc_iafctrl);
459 /* Don't need to write IA_GLOBAL_CTRL, one disable is enough. */
461 PMCDBG4(MDP,STO,1,"iafctrl=%x(%x) globalctrl=%jx(%jx)",
462 cc->pc_iafctrl, (uint32_t) rdmsr(IAF_CTRL),
463 cc->pc_globalctrl, rdmsr(IA_GLOBAL_CTRL));
469 iaf_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v)
473 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
474 ("[core,%d] illegal cpu value %d", __LINE__, cpu));
475 KASSERT(ri >= 0 && ri < core_iaf_npmc,
476 ("[core,%d] illegal row-index %d", __LINE__, ri));
480 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
481 v = iaf_reload_count_to_perfctr_value(v);
483 /* Turn off the fixed counter */
484 wrmsr(IAF_CTRL, cc->pc_iafctrl & ~(IAF_MASK << (ri * 4)));
486 wrmsr(IAF_CTR0 + ri, v & ((1ULL << core_iaf_width) - 1));
488 /* Turn on fixed counters */
489 wrmsr(IAF_CTRL, cc->pc_iafctrl);
491 PMCDBG6(MDP,WRI,1, "iaf-write cpu=%d ri=%d msr=0x%x v=%jx iafctrl=%jx "
492 "pmc=%jx", cpu, ri, IAF_RI_TO_MSR(ri), v,
493 (uintmax_t) rdmsr(IAF_CTRL),
494 (uintmax_t) rdpmc(IAF_RI_TO_MSR(ri)));
501 iaf_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth)
503 struct pmc_classdep *pcd;
505 KASSERT(md != NULL, ("[iaf,%d] md is NULL", __LINE__));
507 PMCDBG0(MDP,INI,1, "iaf-initialize");
509 pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF];
511 pcd->pcd_caps = IAF_PMC_CAPS;
512 pcd->pcd_class = PMC_CLASS_IAF;
514 pcd->pcd_ri = md->pmd_npmc;
515 pcd->pcd_width = pmcwidth;
517 pcd->pcd_allocate_pmc = iaf_allocate_pmc;
518 pcd->pcd_config_pmc = iaf_config_pmc;
519 pcd->pcd_describe = iaf_describe;
520 pcd->pcd_get_config = iaf_get_config;
521 pcd->pcd_get_msr = iaf_get_msr;
522 pcd->pcd_pcpu_fini = core_pcpu_noop;
523 pcd->pcd_pcpu_init = core_pcpu_noop;
524 pcd->pcd_read_pmc = iaf_read_pmc;
525 pcd->pcd_release_pmc = iaf_release_pmc;
526 pcd->pcd_start_pmc = iaf_start_pmc;
527 pcd->pcd_stop_pmc = iaf_stop_pmc;
528 pcd->pcd_write_pmc = iaf_write_pmc;
530 md->pmd_npmc += npmc;
534 * Intel programmable PMCs.
537 /* Sub fields of UMASK that this event supports. */
538 #define IAP_M_CORE (1 << 0) /* Core specificity */
539 #define IAP_M_AGENT (1 << 1) /* Agent specificity */
540 #define IAP_M_PREFETCH (1 << 2) /* Prefetch */
541 #define IAP_M_MESI (1 << 3) /* MESI */
542 #define IAP_M_SNOOPRESPONSE (1 << 4) /* Snoop response */
543 #define IAP_M_SNOOPTYPE (1 << 5) /* Snoop type */
544 #define IAP_M_TRANSITION (1 << 6) /* Transition */
546 #define IAP_F_CORE (0x3 << 14) /* Core specificity */
547 #define IAP_F_AGENT (0x1 << 13) /* Agent specificity */
548 #define IAP_F_PREFETCH (0x3 << 12) /* Prefetch */
549 #define IAP_F_MESI (0xF << 8) /* MESI */
550 #define IAP_F_SNOOPRESPONSE (0xB << 8) /* Snoop response */
551 #define IAP_F_SNOOPTYPE (0x3 << 8) /* Snoop type */
552 #define IAP_F_TRANSITION (0x1 << 12) /* Transition */
554 #define IAP_PREFETCH_RESERVED (0x2 << 12)
555 #define IAP_CORE_THIS (0x1 << 14)
556 #define IAP_CORE_ALL (0x3 << 14)
557 #define IAP_F_CMASK 0xFF000000
560 iap_perfctr_value_to_reload_count(pmc_value_t v)
563 /* If the PMC has overflowed, return a reload count of zero. */
564 if ((v & (1ULL << (core_iap_width - 1))) == 0)
566 v &= (1ULL << core_iap_width) - 1;
567 return (1ULL << core_iap_width) - v;
571 iap_reload_count_to_perfctr_value(pmc_value_t rlc)
573 return (1ULL << core_iap_width) - rlc;
577 iap_pmc_has_overflowed(int ri)
582 * We treat a Core (i.e., Intel architecture v1) PMC as has
583 * having overflowed if its MSB is zero.
586 return ((v & (1ULL << (core_iap_width - 1))) == 0);
590 iap_event_corei7_ok_on_counter(uint8_t evsel, int ri)
595 /* Events valid only on counter 0, 1. */
608 /* Any row index is ok. */
613 return (mask & (1 << ri));
617 iap_event_westmere_ok_on_counter(uint8_t evsel, int ri)
622 /* Events valid only on counter 0. */
628 /* Events valid only on counter 0, 1. */
636 /* Any row index is ok. */
641 return (mask & (1 << ri));
645 iap_event_sb_sbx_ib_ibx_ok_on_counter(uint8_t evsel, int ri)
650 /* Events valid only on counter 0. */
654 /* Events valid only on counter 1. */
658 /* Events valid only on counter 2. */
664 /* Events valid only on counter 3. */
669 /* Any row index is ok. */
674 return (mask & (1 << ri));
678 iap_event_core_ok_on_counter(uint8_t evsel, int ri)
684 * Events valid only on counter 0.
696 * Events valid only on counter 1.
705 mask = ~0; /* Any row index is ok. */
708 return (mask & (1 << ri));
712 iap_allocate_pmc(int cpu, int ri, struct pmc *pm,
713 const struct pmc_op_pmcallocate *a)
716 const struct pmc_md_iap_op_pmcallocate *iap;
718 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
719 ("[core,%d] illegal CPU %d", __LINE__, cpu));
720 KASSERT(ri >= 0 && ri < core_iap_npmc,
721 ("[core,%d] illegal row-index value %d", __LINE__, ri));
723 if (a->pm_class != PMC_CLASS_IAP)
726 if ((a->pm_flags & PMC_F_EV_PMU) == 0)
729 iap = &a->pm_md.pm_iap;
730 ev = IAP_EVSEL_GET(iap->pm_iap_config);
732 switch (core_cputype) {
733 case PMC_CPU_INTEL_CORE:
734 case PMC_CPU_INTEL_CORE2:
735 case PMC_CPU_INTEL_CORE2EXTREME:
736 if (iap_event_core_ok_on_counter(ev, ri) == 0)
738 case PMC_CPU_INTEL_COREI7:
739 case PMC_CPU_INTEL_NEHALEM_EX:
740 if (iap_event_corei7_ok_on_counter(ev, ri) == 0)
743 case PMC_CPU_INTEL_WESTMERE:
744 case PMC_CPU_INTEL_WESTMERE_EX:
745 if (iap_event_westmere_ok_on_counter(ev, ri) == 0)
748 case PMC_CPU_INTEL_SANDYBRIDGE:
749 case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
750 case PMC_CPU_INTEL_IVYBRIDGE:
751 case PMC_CPU_INTEL_IVYBRIDGE_XEON:
752 case PMC_CPU_INTEL_HASWELL:
753 case PMC_CPU_INTEL_HASWELL_XEON:
754 case PMC_CPU_INTEL_BROADWELL:
755 case PMC_CPU_INTEL_BROADWELL_XEON:
756 if (iap_event_sb_sbx_ib_ibx_ok_on_counter(ev, ri) == 0)
759 case PMC_CPU_INTEL_ATOM:
760 case PMC_CPU_INTEL_ATOM_SILVERMONT:
761 case PMC_CPU_INTEL_ATOM_GOLDMONT:
762 case PMC_CPU_INTEL_ATOM_GOLDMONT_P:
763 case PMC_CPU_INTEL_ATOM_TREMONT:
764 case PMC_CPU_INTEL_SKYLAKE:
765 case PMC_CPU_INTEL_SKYLAKE_XEON:
766 case PMC_CPU_INTEL_ICELAKE:
767 case PMC_CPU_INTEL_ICELAKE_XEON:
768 case PMC_CPU_INTEL_ALDERLAKE:
773 pm->pm_md.pm_iap.pm_iap_evsel = iap->pm_iap_config;
778 iap_config_pmc(int cpu, int ri, struct pmc *pm)
780 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
781 ("[core,%d] illegal CPU %d", __LINE__, cpu));
783 KASSERT(ri >= 0 && ri < core_iap_npmc,
784 ("[core,%d] illegal row-index %d", __LINE__, ri));
786 PMCDBG3(MDP,CFG,1, "iap-config cpu=%d ri=%d pm=%p", cpu, ri, pm);
788 KASSERT(core_pcpu[cpu] != NULL, ("[core,%d] null per-cpu %d", __LINE__,
791 core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc = pm;
797 iap_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
801 phw = &core_pcpu[cpu]->pc_corepmcs[ri];
803 snprintf(pi->pm_name, sizeof(pi->pm_name), "IAP-%d", ri);
804 pi->pm_class = PMC_CLASS_IAP;
806 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
807 pi->pm_enabled = TRUE;
808 *ppmc = phw->phw_pmc;
810 pi->pm_enabled = FALSE;
818 iap_get_config(int cpu, int ri, struct pmc **ppm)
820 *ppm = core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc;
826 iap_get_msr(int ri, uint32_t *msr)
828 KASSERT(ri >= 0 && ri < core_iap_npmc,
829 ("[iap,%d] ri %d out of range", __LINE__, ri));
837 iap_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v)
841 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
842 ("[core,%d] illegal cpu value %d", __LINE__, cpu));
843 KASSERT(ri >= 0 && ri < core_iap_npmc,
844 ("[core,%d] illegal row-index %d", __LINE__, ri));
847 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
848 *v = iap_perfctr_value_to_reload_count(tmp);
850 *v = tmp & ((1ULL << core_iap_width) - 1);
852 PMCDBG4(MDP,REA,1, "iap-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri,
859 iap_release_pmc(int cpu, int ri, struct pmc *pm)
863 PMCDBG3(MDP,REL,1, "iap-release cpu=%d ri=%d pm=%p", cpu, ri,
866 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
867 ("[core,%d] illegal CPU value %d", __LINE__, cpu));
868 KASSERT(ri >= 0 && ri < core_iap_npmc,
869 ("[core,%d] illegal row-index %d", __LINE__, ri));
871 KASSERT(core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc
872 == NULL, ("[core,%d] PHW pmc non-NULL", __LINE__));
878 iap_start_pmc(int cpu, int ri, struct pmc *pm)
883 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
884 ("[core,%d] illegal CPU value %d", __LINE__, cpu));
885 KASSERT(ri >= 0 && ri < core_iap_npmc,
886 ("[core,%d] illegal row-index %d", __LINE__, ri));
890 PMCDBG2(MDP,STA,1, "iap-start cpu=%d ri=%d", cpu, ri);
892 evsel = pm->pm_md.pm_iap.pm_iap_evsel;
894 PMCDBG4(MDP,STA,2, "iap-start/2 cpu=%d ri=%d evselmsr=0x%x evsel=0x%x",
895 cpu, ri, IAP_EVSEL0 + ri, evsel);
897 /* Event specific configuration. */
899 switch (IAP_EVSEL_GET(evsel)) {
901 wrmsr(IA_OFFCORE_RSP0, pm->pm_md.pm_iap.pm_iap_rsp);
904 wrmsr(IA_OFFCORE_RSP1, pm->pm_md.pm_iap.pm_iap_rsp);
910 wrmsr(IAP_EVSEL0 + ri, evsel | IAP_EN);
912 if (core_version >= 2) {
913 cc->pc_globalctrl |= (1ULL << ri);
914 wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl);
921 iap_stop_pmc(int cpu, int ri, struct pmc *pm __unused)
924 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
925 ("[core,%d] illegal cpu value %d", __LINE__, cpu));
926 KASSERT(ri >= 0 && ri < core_iap_npmc,
927 ("[core,%d] illegal row index %d", __LINE__, ri));
929 PMCDBG2(MDP,STO,1, "iap-stop cpu=%d ri=%d", cpu, ri);
931 wrmsr(IAP_EVSEL0 + ri, 0);
933 /* Don't need to write IA_GLOBAL_CTRL, one disable is enough. */
939 iap_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v)
942 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
943 ("[core,%d] illegal cpu value %d", __LINE__, cpu));
944 KASSERT(ri >= 0 && ri < core_iap_npmc,
945 ("[core,%d] illegal row index %d", __LINE__, ri));
947 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
948 v = iap_reload_count_to_perfctr_value(v);
950 v &= (1ULL << core_iap_width) - 1;
952 PMCDBG4(MDP,WRI,1, "iap-write cpu=%d ri=%d msr=0x%x v=%jx", cpu, ri,
956 * Write the new value to the counter (or it's alias). The
957 * counter will be in a stopped state when the pcd_write()
958 * entry point is called.
960 wrmsr(core_iap_wroffset + IAP_PMC0 + ri, v);
966 iap_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth,
969 struct pmc_classdep *pcd;
971 KASSERT(md != NULL, ("[iap,%d] md is NULL", __LINE__));
973 PMCDBG0(MDP,INI,1, "iap-initialize");
975 /* Remember the set of architectural events supported. */
976 core_architectural_events = ~flags;
978 pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP];
980 pcd->pcd_caps = IAP_PMC_CAPS;
981 pcd->pcd_class = PMC_CLASS_IAP;
983 pcd->pcd_ri = md->pmd_npmc;
984 pcd->pcd_width = pmcwidth;
986 pcd->pcd_allocate_pmc = iap_allocate_pmc;
987 pcd->pcd_config_pmc = iap_config_pmc;
988 pcd->pcd_describe = iap_describe;
989 pcd->pcd_get_config = iap_get_config;
990 pcd->pcd_get_msr = iap_get_msr;
991 pcd->pcd_pcpu_fini = core_pcpu_fini;
992 pcd->pcd_pcpu_init = core_pcpu_init;
993 pcd->pcd_read_pmc = iap_read_pmc;
994 pcd->pcd_release_pmc = iap_release_pmc;
995 pcd->pcd_start_pmc = iap_start_pmc;
996 pcd->pcd_stop_pmc = iap_stop_pmc;
997 pcd->pcd_write_pmc = iap_write_pmc;
999 md->pmd_npmc += npmc;
1003 core_intr(struct trapframe *tf)
1007 struct core_cpu *cc;
1008 int error, found_interrupt, ri;
1010 PMCDBG3(MDP,INT, 1, "cpu=%d tf=%p um=%d", curcpu, (void *) tf,
1011 TRAPF_USERMODE(tf));
1013 found_interrupt = 0;
1014 cc = core_pcpu[curcpu];
1016 for (ri = 0; ri < core_iap_npmc; ri++) {
1018 if ((pm = cc->pc_corepmcs[ri].phw_pmc) == NULL ||
1019 !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
1022 if (!iap_pmc_has_overflowed(ri))
1025 found_interrupt = 1;
1027 if (pm->pm_state != PMC_STATE_RUNNING)
1030 error = pmc_process_interrupt(PMC_HR, pm, tf);
1032 v = pm->pm_sc.pm_reloadcount;
1033 v = iap_reload_count_to_perfctr_value(v);
1036 * Stop the counter, reload it but only restart it if
1037 * the PMC is not stalled.
1039 wrmsr(IAP_EVSEL0 + ri, pm->pm_md.pm_iap.pm_iap_evsel);
1040 wrmsr(core_iap_wroffset + IAP_PMC0 + ri, v);
1042 if (__predict_false(error))
1045 wrmsr(IAP_EVSEL0 + ri, pm->pm_md.pm_iap.pm_iap_evsel | IAP_EN);
1048 if (found_interrupt)
1049 counter_u64_add(pmc_stats.pm_intr_processed, 1);
1051 counter_u64_add(pmc_stats.pm_intr_ignored, 1);
1053 if (found_interrupt)
1054 lapic_reenable_pmc();
1056 return (found_interrupt);
1060 core2_intr(struct trapframe *tf)
1062 int error, found_interrupt = 0, n, cpu;
1063 uint64_t flag, intrstatus, intrdisable = 0;
1065 struct core_cpu *cc;
1069 PMCDBG3(MDP,INT, 1, "cpu=%d tf=0x%p um=%d", cpu, (void *) tf,
1070 TRAPF_USERMODE(tf));
1073 * The IA_GLOBAL_STATUS (MSR 0x38E) register indicates which
1074 * PMCs have a pending PMI interrupt. We take a 'snapshot' of
1075 * the current set of interrupting PMCs and process these
1076 * after stopping them.
1078 intrstatus = rdmsr(IA_GLOBAL_STATUS);
1079 PMCDBG2(MDP,INT, 1, "cpu=%d intrstatus=%jx", cpu,
1080 (uintmax_t) intrstatus);
1083 * Stop PMCs unless hardware already done it.
1085 if ((intrstatus & IA_GLOBAL_STATUS_FLAG_CTR_FRZ) == 0)
1086 wrmsr(IA_GLOBAL_CTRL, 0);
1088 cc = core_pcpu[cpu];
1089 KASSERT(cc != NULL, ("[core,%d] null pcpu", __LINE__));
1092 * Look for interrupts from fixed function PMCs.
1094 for (n = 0, flag = (1ULL << IAF_OFFSET); n < core_iaf_npmc;
1097 if ((intrstatus & flag) == 0)
1100 found_interrupt = 1;
1102 pm = cc->pc_corepmcs[n + core_iaf_ri].phw_pmc;
1103 if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING ||
1104 !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
1107 error = pmc_process_interrupt(PMC_HR, pm, tf);
1108 if (__predict_false(error))
1109 intrdisable |= flag;
1111 v = iaf_reload_count_to_perfctr_value(pm->pm_sc.pm_reloadcount);
1113 /* Reload sampling count. */
1114 wrmsr(IAF_CTR0 + n, v);
1116 PMCDBG4(MDP,INT, 1, "iaf-intr cpu=%d error=%d v=%jx(%jx)", curcpu,
1117 error, (uintmax_t) v, (uintmax_t) rdpmc(IAF_RI_TO_MSR(n)));
1121 * Process interrupts from the programmable counters.
1123 for (n = 0, flag = 1; n < core_iap_npmc; n++, flag <<= 1) {
1124 if ((intrstatus & flag) == 0)
1127 found_interrupt = 1;
1129 pm = cc->pc_corepmcs[n].phw_pmc;
1130 if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING ||
1131 !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
1134 error = pmc_process_interrupt(PMC_HR, pm, tf);
1135 if (__predict_false(error))
1136 intrdisable |= flag;
1138 v = iap_reload_count_to_perfctr_value(pm->pm_sc.pm_reloadcount);
1140 PMCDBG3(MDP,INT, 1, "iap-intr cpu=%d error=%d v=%jx", cpu, error,
1143 /* Reload sampling count. */
1144 wrmsr(core_iap_wroffset + IAP_PMC0 + n, v);
1147 if (found_interrupt)
1148 counter_u64_add(pmc_stats.pm_intr_processed, 1);
1150 counter_u64_add(pmc_stats.pm_intr_ignored, 1);
1152 if (found_interrupt)
1153 lapic_reenable_pmc();
1156 * Reenable all non-stalled PMCs.
1158 if ((intrstatus & IA_GLOBAL_STATUS_FLAG_CTR_FRZ) == 0) {
1159 wrmsr(IA_GLOBAL_OVF_CTRL, intrstatus);
1160 cc->pc_globalctrl &= ~intrdisable;
1161 wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl);
1163 if (__predict_false(intrdisable)) {
1164 cc->pc_globalctrl &= ~intrdisable;
1165 wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl);
1167 wrmsr(IA_GLOBAL_OVF_CTRL, intrstatus);
1170 PMCDBG4(MDP, INT, 1, "cpu=%d fixedctrl=%jx globalctrl=%jx status=%jx",
1171 cpu, (uintmax_t) rdmsr(IAF_CTRL),
1172 (uintmax_t) rdmsr(IA_GLOBAL_CTRL),
1173 (uintmax_t) rdmsr(IA_GLOBAL_STATUS));
1175 return (found_interrupt);
1179 pmc_core_initialize(struct pmc_mdep *md, int maxcpu, int version_override)
1181 int cpuid[CORE_CPUID_REQUEST_SIZE];
1184 do_cpuid(CORE_CPUID_REQUEST, cpuid);
1186 core_cputype = md->pmd_cputype;
1187 core_version = (version_override > 0) ? version_override :
1188 cpuid[CORE_CPUID_EAX] & 0xFF;
1190 PMCDBG3(MDP,INI,1,"core-init cputype=%d ncpu=%d version=%d",
1191 core_cputype, maxcpu, core_version);
1193 if (core_version < 1 || core_version > 5 ||
1194 (core_cputype != PMC_CPU_INTEL_CORE && core_version == 1)) {
1195 /* Unknown PMC architecture. */
1196 printf("hwpmc_core: unknown PMC architecture: %d\n",
1198 return (EPROGMISMATCH);
1201 core_iap_wroffset = 0;
1202 if (cpu_feature2 & CPUID2_PDCM) {
1203 if (rdmsr(IA32_PERF_CAPABILITIES) & PERFCAP_FW_WRITE) {
1204 PMCDBG0(MDP, INI, 1,
1205 "core-init full-width write supported");
1206 core_iap_wroffset = IAP_A_PMC0 - IAP_PMC0;
1208 PMCDBG0(MDP, INI, 1,
1209 "core-init full-width write NOT supported");
1211 PMCDBG0(MDP, INI, 1, "core-init pdcm not supported");
1216 * Initialize programmable counters.
1218 core_iap_npmc = (cpuid[CORE_CPUID_EAX] >> 8) & 0xFF;
1219 core_iap_width = (cpuid[CORE_CPUID_EAX] >> 16) & 0xFF;
1221 core_pmcmask |= ((1ULL << core_iap_npmc) - 1);
1223 nflags = (cpuid[CORE_CPUID_EAX] >> 24) & 0xFF;
1224 flags = cpuid[CORE_CPUID_EBX] & ((1 << nflags) - 1);
1226 iap_initialize(md, maxcpu, core_iap_npmc, core_iap_width, flags);
1229 * Initialize fixed function counters, if present.
1231 if (core_version >= 2) {
1232 core_iaf_ri = core_iap_npmc;
1233 core_iaf_npmc = cpuid[CORE_CPUID_EDX] & 0x1F;
1234 core_iaf_width = (cpuid[CORE_CPUID_EDX] >> 5) & 0xFF;
1236 iaf_initialize(md, maxcpu, core_iaf_npmc, core_iaf_width);
1237 core_pmcmask |= ((1ULL << core_iaf_npmc) - 1) << IAF_OFFSET;
1240 PMCDBG2(MDP,INI,1,"core-init pmcmask=0x%jx iafri=%d", core_pmcmask,
1243 core_pcpu = malloc(sizeof(*core_pcpu) * maxcpu, M_PMC,
1247 * Choose the appropriate interrupt handler.
1249 if (core_version >= 2)
1250 md->pmd_intr = core2_intr;
1252 md->pmd_intr = core_intr;
1258 pmc_core_finalize(struct pmc_mdep *md)
1260 PMCDBG0(MDP,INI,1, "core-finalize");
1262 for (int i = 0; i < pmc_cpu_max(); i++)
1263 KASSERT(core_pcpu[i] == NULL,
1264 ("[core,%d] non-null pcpu cpu %d", __LINE__, i));
1266 free(core_pcpu, M_PMC);