1e829eb6dSJoseph Koshy /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 4e829eb6dSJoseph Koshy * Copyright (c) 2008 Joseph Koshy 5e829eb6dSJoseph Koshy * All rights reserved. 6e829eb6dSJoseph Koshy * 7e829eb6dSJoseph Koshy * Redistribution and use in source and binary forms, with or without 8e829eb6dSJoseph Koshy * modification, are permitted provided that the following conditions 9e829eb6dSJoseph Koshy * are met: 10e829eb6dSJoseph Koshy * 1. Redistributions of source code must retain the above copyright 11e829eb6dSJoseph Koshy * notice, this list of conditions and the following disclaimer. 12e829eb6dSJoseph Koshy * 2. Redistributions in binary form must reproduce the above copyright 13e829eb6dSJoseph Koshy * notice, this list of conditions and the following disclaimer in the 14e829eb6dSJoseph Koshy * documentation and/or other materials provided with the distribution. 15e829eb6dSJoseph Koshy * 16e829eb6dSJoseph Koshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17e829eb6dSJoseph Koshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18e829eb6dSJoseph Koshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19e829eb6dSJoseph Koshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20e829eb6dSJoseph Koshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21e829eb6dSJoseph Koshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22e829eb6dSJoseph Koshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23e829eb6dSJoseph Koshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24e829eb6dSJoseph Koshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25e829eb6dSJoseph Koshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26e829eb6dSJoseph Koshy * SUCH DAMAGE. 27e829eb6dSJoseph Koshy */ 28e829eb6dSJoseph Koshy 29e829eb6dSJoseph Koshy #include <sys/cdefs.h> 30e829eb6dSJoseph Koshy __FBSDID("$FreeBSD$"); 31e829eb6dSJoseph Koshy 32e829eb6dSJoseph Koshy #include <sys/param.h> 33e829eb6dSJoseph Koshy #include <sys/pmc.h> 34e829eb6dSJoseph Koshy #include <sys/pmckern.h> 35e829eb6dSJoseph Koshy #include <sys/systm.h> 36e829eb6dSJoseph Koshy 37e829eb6dSJoseph Koshy #include <machine/specialreg.h> 38e829eb6dSJoseph Koshy 39e829eb6dSJoseph Koshy /* 40e829eb6dSJoseph Koshy * TSC support. 41e829eb6dSJoseph Koshy */ 42e829eb6dSJoseph Koshy 43e829eb6dSJoseph Koshy #define TSC_CAPS PMC_CAP_READ 44e829eb6dSJoseph Koshy 45e829eb6dSJoseph Koshy struct tsc_descr { 46e829eb6dSJoseph Koshy struct pmc_descr pm_descr; /* "base class" */ 47e829eb6dSJoseph Koshy }; 48e829eb6dSJoseph Koshy 49e829eb6dSJoseph Koshy static struct tsc_descr tsc_pmcdesc[TSC_NPMCS] = 50e829eb6dSJoseph Koshy { 51e829eb6dSJoseph Koshy { 52e829eb6dSJoseph Koshy .pm_descr = 53e829eb6dSJoseph Koshy { 54e829eb6dSJoseph Koshy .pd_name = "TSC", 55e829eb6dSJoseph Koshy .pd_class = PMC_CLASS_TSC, 56e829eb6dSJoseph Koshy .pd_caps = TSC_CAPS, 57e829eb6dSJoseph Koshy .pd_width = 64 58e829eb6dSJoseph Koshy } 59e829eb6dSJoseph Koshy } 60e829eb6dSJoseph Koshy }; 61e829eb6dSJoseph Koshy 62e829eb6dSJoseph Koshy /* 63e829eb6dSJoseph Koshy * Per-CPU data structure for TSCs. 64e829eb6dSJoseph Koshy */ 65e829eb6dSJoseph Koshy 66e829eb6dSJoseph Koshy struct tsc_cpu { 67e829eb6dSJoseph Koshy struct pmc_hw tc_hw; 68e829eb6dSJoseph Koshy }; 69e829eb6dSJoseph Koshy 70e829eb6dSJoseph Koshy static struct tsc_cpu **tsc_pcpu; 71e829eb6dSJoseph Koshy 72e829eb6dSJoseph Koshy static int 73*a35453b9SMitchell Horne tsc_allocate_pmc(int cpu __diagused, int ri __diagused, struct pmc *pm __unused, 74e829eb6dSJoseph Koshy const struct pmc_op_pmcallocate *a) 75e829eb6dSJoseph Koshy { 76e829eb6dSJoseph Koshy 77e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 78e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 79e829eb6dSJoseph Koshy KASSERT(ri >= 0 && ri < TSC_NPMCS, 80e829eb6dSJoseph Koshy ("[tsc,%d] illegal row index %d", __LINE__, ri)); 81e829eb6dSJoseph Koshy 82e829eb6dSJoseph Koshy if (a->pm_class != PMC_CLASS_TSC) 83e829eb6dSJoseph Koshy return (EINVAL); 84e829eb6dSJoseph Koshy 85e829eb6dSJoseph Koshy if (a->pm_ev != PMC_EV_TSC_TSC || 86e829eb6dSJoseph Koshy a->pm_mode != PMC_MODE_SC) 87e829eb6dSJoseph Koshy return (EINVAL); 88e829eb6dSJoseph Koshy 89e829eb6dSJoseph Koshy return (0); 90e829eb6dSJoseph Koshy } 91e829eb6dSJoseph Koshy 92e829eb6dSJoseph Koshy static int 93e829eb6dSJoseph Koshy tsc_config_pmc(int cpu, int ri, struct pmc *pm) 94e829eb6dSJoseph Koshy { 95e829eb6dSJoseph Koshy struct pmc_hw *phw; 96e829eb6dSJoseph Koshy 974a3690dfSJohn Baldwin PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); 98e829eb6dSJoseph Koshy 99e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 100e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 101e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 102e829eb6dSJoseph Koshy 103e829eb6dSJoseph Koshy phw = &tsc_pcpu[cpu]->tc_hw; 104e829eb6dSJoseph Koshy 105e829eb6dSJoseph Koshy KASSERT(pm == NULL || phw->phw_pmc == NULL, 106e829eb6dSJoseph Koshy ("[tsc,%d] pm=%p phw->pm=%p hwpmc not unconfigured", __LINE__, 107e829eb6dSJoseph Koshy pm, phw->phw_pmc)); 108e829eb6dSJoseph Koshy 109e829eb6dSJoseph Koshy phw->phw_pmc = pm; 110e829eb6dSJoseph Koshy 111e829eb6dSJoseph Koshy return (0); 112e829eb6dSJoseph Koshy } 113e829eb6dSJoseph Koshy 114e829eb6dSJoseph Koshy static int 115e829eb6dSJoseph Koshy tsc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 116e829eb6dSJoseph Koshy { 117e829eb6dSJoseph Koshy const struct tsc_descr *pd; 118e829eb6dSJoseph Koshy struct pmc_hw *phw; 119e829eb6dSJoseph Koshy 120e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 121e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU %d", __LINE__, cpu)); 122e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 123e829eb6dSJoseph Koshy 124e829eb6dSJoseph Koshy phw = &tsc_pcpu[cpu]->tc_hw; 125e829eb6dSJoseph Koshy pd = &tsc_pmcdesc[ri]; 126e829eb6dSJoseph Koshy 12731610e34SMitchell Horne strlcpy(pi->pm_name, pd->pm_descr.pd_name, sizeof(pi->pm_name)); 128e829eb6dSJoseph Koshy pi->pm_class = pd->pm_descr.pd_class; 129e829eb6dSJoseph Koshy 130e829eb6dSJoseph Koshy if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 131e829eb6dSJoseph Koshy pi->pm_enabled = TRUE; 132e829eb6dSJoseph Koshy *ppmc = phw->phw_pmc; 133e829eb6dSJoseph Koshy } else { 134e829eb6dSJoseph Koshy pi->pm_enabled = FALSE; 135e829eb6dSJoseph Koshy *ppmc = NULL; 136e829eb6dSJoseph Koshy } 137e829eb6dSJoseph Koshy 138e829eb6dSJoseph Koshy return (0); 139e829eb6dSJoseph Koshy } 140e829eb6dSJoseph Koshy 141e829eb6dSJoseph Koshy static int 142*a35453b9SMitchell Horne tsc_get_config(int cpu, int ri __diagused, struct pmc **ppm) 143e829eb6dSJoseph Koshy { 144e829eb6dSJoseph Koshy 145e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 146e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU %d", __LINE__, cpu)); 147e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 148e829eb6dSJoseph Koshy 149e829eb6dSJoseph Koshy *ppm = tsc_pcpu[cpu]->tc_hw.phw_pmc; 150e829eb6dSJoseph Koshy 151e829eb6dSJoseph Koshy return (0); 152e829eb6dSJoseph Koshy } 153e829eb6dSJoseph Koshy 154e829eb6dSJoseph Koshy static int 155*a35453b9SMitchell Horne tsc_get_msr(int ri __diagused, uint32_t *msr) 156e829eb6dSJoseph Koshy { 157e829eb6dSJoseph Koshy 158e829eb6dSJoseph Koshy KASSERT(ri >= 0 && ri < TSC_NPMCS, 159e829eb6dSJoseph Koshy ("[tsc,%d] ri %d out of range", __LINE__, ri)); 160e829eb6dSJoseph Koshy 161e829eb6dSJoseph Koshy *msr = MSR_TSC; 162e829eb6dSJoseph Koshy 163e829eb6dSJoseph Koshy return (0); 164e829eb6dSJoseph Koshy } 165e829eb6dSJoseph Koshy 166e829eb6dSJoseph Koshy static int 167e829eb6dSJoseph Koshy tsc_pcpu_fini(struct pmc_mdep *md, int cpu) 168e829eb6dSJoseph Koshy { 169e829eb6dSJoseph Koshy int ri; 170e829eb6dSJoseph Koshy struct pmc_cpu *pc; 171e829eb6dSJoseph Koshy 172e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 173e829eb6dSJoseph Koshy ("[tsc,%d] illegal cpu %d", __LINE__, cpu)); 174e829eb6dSJoseph Koshy KASSERT(tsc_pcpu[cpu] != NULL, ("[tsc,%d] null pcpu", __LINE__)); 175e829eb6dSJoseph Koshy 176e829eb6dSJoseph Koshy free(tsc_pcpu[cpu], M_PMC); 177e829eb6dSJoseph Koshy tsc_pcpu[cpu] = NULL; 178e829eb6dSJoseph Koshy 179e829eb6dSJoseph Koshy ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_TSC].pcd_ri; 180e829eb6dSJoseph Koshy 181e829eb6dSJoseph Koshy pc = pmc_pcpu[cpu]; 182e829eb6dSJoseph Koshy pc->pc_hwpmcs[ri] = NULL; 183e829eb6dSJoseph Koshy 184e829eb6dSJoseph Koshy return (0); 185e829eb6dSJoseph Koshy } 186e829eb6dSJoseph Koshy 187e829eb6dSJoseph Koshy static int 188e829eb6dSJoseph Koshy tsc_pcpu_init(struct pmc_mdep *md, int cpu) 189e829eb6dSJoseph Koshy { 190e829eb6dSJoseph Koshy int ri; 191e829eb6dSJoseph Koshy struct pmc_cpu *pc; 192e829eb6dSJoseph Koshy struct tsc_cpu *tsc_pc; 193e829eb6dSJoseph Koshy 194e829eb6dSJoseph Koshy 195e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 196e829eb6dSJoseph Koshy ("[tsc,%d] illegal cpu %d", __LINE__, cpu)); 197e829eb6dSJoseph Koshy KASSERT(tsc_pcpu, ("[tsc,%d] null pcpu", __LINE__)); 198e829eb6dSJoseph Koshy KASSERT(tsc_pcpu[cpu] == NULL, ("[tsc,%d] non-null per-cpu", 199e829eb6dSJoseph Koshy __LINE__)); 200e829eb6dSJoseph Koshy 201e829eb6dSJoseph Koshy tsc_pc = malloc(sizeof(struct tsc_cpu), M_PMC, M_WAITOK|M_ZERO); 202e829eb6dSJoseph Koshy 203e829eb6dSJoseph Koshy tsc_pc->tc_hw.phw_state = PMC_PHW_FLAG_IS_ENABLED | 204e829eb6dSJoseph Koshy PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(0) | 205e829eb6dSJoseph Koshy PMC_PHW_FLAG_IS_SHAREABLE; 206e829eb6dSJoseph Koshy 207e829eb6dSJoseph Koshy tsc_pcpu[cpu] = tsc_pc; 208e829eb6dSJoseph Koshy 209e829eb6dSJoseph Koshy ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_TSC].pcd_ri; 210e829eb6dSJoseph Koshy 211e829eb6dSJoseph Koshy KASSERT(pmc_pcpu, ("[tsc,%d] null generic pcpu", __LINE__)); 212e829eb6dSJoseph Koshy 213e829eb6dSJoseph Koshy pc = pmc_pcpu[cpu]; 214e829eb6dSJoseph Koshy 215e829eb6dSJoseph Koshy KASSERT(pc, ("[tsc,%d] null generic per-cpu", __LINE__)); 216e829eb6dSJoseph Koshy 217e829eb6dSJoseph Koshy pc->pc_hwpmcs[ri] = &tsc_pc->tc_hw; 218e829eb6dSJoseph Koshy 219e829eb6dSJoseph Koshy return (0); 220e829eb6dSJoseph Koshy } 221e829eb6dSJoseph Koshy 222e829eb6dSJoseph Koshy static int 223e829eb6dSJoseph Koshy tsc_read_pmc(int cpu, int ri, pmc_value_t *v) 224e829eb6dSJoseph Koshy { 225e829eb6dSJoseph Koshy struct pmc *pm; 226aee6e7dcSMateusz Guzik enum pmc_mode mode __diagused; 227e829eb6dSJoseph Koshy const struct pmc_hw *phw; 228e829eb6dSJoseph Koshy 229e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 230e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 231e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal ri %d", __LINE__, ri)); 232e829eb6dSJoseph Koshy 233e829eb6dSJoseph Koshy phw = &tsc_pcpu[cpu]->tc_hw; 234e829eb6dSJoseph Koshy pm = phw->phw_pmc; 235e829eb6dSJoseph Koshy 236e829eb6dSJoseph Koshy KASSERT(pm != NULL, 237e829eb6dSJoseph Koshy ("[tsc,%d] no owner for PHW [cpu%d,pmc%d]", __LINE__, cpu, ri)); 238e829eb6dSJoseph Koshy 239e829eb6dSJoseph Koshy mode = PMC_TO_MODE(pm); 240e829eb6dSJoseph Koshy 241e829eb6dSJoseph Koshy KASSERT(mode == PMC_MODE_SC, 242e829eb6dSJoseph Koshy ("[tsc,%d] illegal pmc mode %d", __LINE__, mode)); 243e829eb6dSJoseph Koshy 2444a3690dfSJohn Baldwin PMCDBG1(MDP,REA,1,"tsc-read id=%d", ri); 245e829eb6dSJoseph Koshy 246e829eb6dSJoseph Koshy *v = rdtsc(); 247e829eb6dSJoseph Koshy 248e829eb6dSJoseph Koshy return (0); 249e829eb6dSJoseph Koshy } 250e829eb6dSJoseph Koshy 251e829eb6dSJoseph Koshy static int 252*a35453b9SMitchell Horne tsc_release_pmc(int cpu, int ri __diagused, struct pmc *pmc __unused) 253e829eb6dSJoseph Koshy { 254aee6e7dcSMateusz Guzik struct pmc_hw *phw __diagused; 255e829eb6dSJoseph Koshy 256e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 257e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 258e829eb6dSJoseph Koshy KASSERT(ri == 0, 259e829eb6dSJoseph Koshy ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 260e829eb6dSJoseph Koshy 261e829eb6dSJoseph Koshy phw = &tsc_pcpu[cpu]->tc_hw; 262e829eb6dSJoseph Koshy 263e829eb6dSJoseph Koshy KASSERT(phw->phw_pmc == NULL, 264e829eb6dSJoseph Koshy ("[tsc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 265e829eb6dSJoseph Koshy 266e829eb6dSJoseph Koshy /* 267e829eb6dSJoseph Koshy * Nothing to do. 268e829eb6dSJoseph Koshy */ 269e829eb6dSJoseph Koshy return (0); 270e829eb6dSJoseph Koshy } 271e829eb6dSJoseph Koshy 272e829eb6dSJoseph Koshy static int 273*a35453b9SMitchell Horne tsc_start_pmc(int cpu __diagused, int ri __diagused) 274e829eb6dSJoseph Koshy { 275e829eb6dSJoseph Koshy 276e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 277e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 278e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 279e829eb6dSJoseph Koshy 280e829eb6dSJoseph Koshy return (0); /* TSCs are always running. */ 281e829eb6dSJoseph Koshy } 282e829eb6dSJoseph Koshy 283e829eb6dSJoseph Koshy static int 284*a35453b9SMitchell Horne tsc_stop_pmc(int cpu __diagused, int ri __diagused) 285e829eb6dSJoseph Koshy { 286e829eb6dSJoseph Koshy 287e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 288e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 289e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 290e829eb6dSJoseph Koshy 291e829eb6dSJoseph Koshy return (0); /* Cannot actually stop a TSC. */ 292e829eb6dSJoseph Koshy } 293e829eb6dSJoseph Koshy 294e829eb6dSJoseph Koshy static int 295*a35453b9SMitchell Horne tsc_write_pmc(int cpu __diagused, int ri __diagused, pmc_value_t v __unused) 296e829eb6dSJoseph Koshy { 297e829eb6dSJoseph Koshy 298e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 299e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 300e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 301e829eb6dSJoseph Koshy 302e829eb6dSJoseph Koshy /* 303e829eb6dSJoseph Koshy * The TSCs are used as timecounters by the kernel, so even 304e829eb6dSJoseph Koshy * though some i386 CPUs support writeable TSCs, we don't 305e829eb6dSJoseph Koshy * support writing changing TSC values through the HWPMC API. 306e829eb6dSJoseph Koshy */ 307e829eb6dSJoseph Koshy return (0); 308e829eb6dSJoseph Koshy } 309e829eb6dSJoseph Koshy 310e829eb6dSJoseph Koshy int 311e829eb6dSJoseph Koshy pmc_tsc_initialize(struct pmc_mdep *md, int maxcpu) 312e829eb6dSJoseph Koshy { 313e829eb6dSJoseph Koshy struct pmc_classdep *pcd; 314e829eb6dSJoseph Koshy 315e829eb6dSJoseph Koshy KASSERT(md != NULL, ("[tsc,%d] md is NULL", __LINE__)); 316e829eb6dSJoseph Koshy KASSERT(md->pmd_nclass >= 1, ("[tsc,%d] dubious md->nclass %d", 317e829eb6dSJoseph Koshy __LINE__, md->pmd_nclass)); 318e829eb6dSJoseph Koshy 319e829eb6dSJoseph Koshy tsc_pcpu = malloc(sizeof(struct tsc_cpu *) * maxcpu, M_PMC, 320e829eb6dSJoseph Koshy M_ZERO|M_WAITOK); 321e829eb6dSJoseph Koshy 322e829eb6dSJoseph Koshy pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_TSC]; 323e829eb6dSJoseph Koshy 324e829eb6dSJoseph Koshy pcd->pcd_caps = PMC_CAP_READ; 325e829eb6dSJoseph Koshy pcd->pcd_class = PMC_CLASS_TSC; 326e829eb6dSJoseph Koshy pcd->pcd_num = TSC_NPMCS; 327e829eb6dSJoseph Koshy pcd->pcd_ri = md->pmd_npmc; 328e829eb6dSJoseph Koshy pcd->pcd_width = 64; 329e829eb6dSJoseph Koshy 330e829eb6dSJoseph Koshy pcd->pcd_allocate_pmc = tsc_allocate_pmc; 331e829eb6dSJoseph Koshy pcd->pcd_config_pmc = tsc_config_pmc; 332e829eb6dSJoseph Koshy pcd->pcd_describe = tsc_describe; 333e829eb6dSJoseph Koshy pcd->pcd_get_config = tsc_get_config; 334e829eb6dSJoseph Koshy pcd->pcd_get_msr = tsc_get_msr; 335e829eb6dSJoseph Koshy pcd->pcd_pcpu_init = tsc_pcpu_init; 336e829eb6dSJoseph Koshy pcd->pcd_pcpu_fini = tsc_pcpu_fini; 337e829eb6dSJoseph Koshy pcd->pcd_read_pmc = tsc_read_pmc; 338e829eb6dSJoseph Koshy pcd->pcd_release_pmc = tsc_release_pmc; 339e829eb6dSJoseph Koshy pcd->pcd_start_pmc = tsc_start_pmc; 340e829eb6dSJoseph Koshy pcd->pcd_stop_pmc = tsc_stop_pmc; 341e829eb6dSJoseph Koshy pcd->pcd_write_pmc = tsc_write_pmc; 342e829eb6dSJoseph Koshy 343e829eb6dSJoseph Koshy md->pmd_npmc += TSC_NPMCS; 344e829eb6dSJoseph Koshy 345e829eb6dSJoseph Koshy return (0); 346e829eb6dSJoseph Koshy } 347e829eb6dSJoseph Koshy 348e829eb6dSJoseph Koshy void 349*a35453b9SMitchell Horne pmc_tsc_finalize(struct pmc_mdep *md __diagused) 350e829eb6dSJoseph Koshy { 351e829eb6dSJoseph Koshy #ifdef INVARIANTS 352e829eb6dSJoseph Koshy int i, ncpus; 353e829eb6dSJoseph Koshy 354e829eb6dSJoseph Koshy ncpus = pmc_cpu_max(); 355e829eb6dSJoseph Koshy for (i = 0; i < ncpus; i++) 356e829eb6dSJoseph Koshy KASSERT(tsc_pcpu[i] == NULL, ("[tsc,%d] non-null pcpu cpu %d", 357e829eb6dSJoseph Koshy __LINE__, i)); 358e829eb6dSJoseph Koshy 359e829eb6dSJoseph Koshy KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_TSC].pcd_class == 360e829eb6dSJoseph Koshy PMC_CLASS_TSC, ("[tsc,%d] class mismatch", __LINE__)); 361e829eb6dSJoseph Koshy #endif 362e829eb6dSJoseph Koshy 363e829eb6dSJoseph Koshy free(tsc_pcpu, M_PMC); 364e829eb6dSJoseph Koshy tsc_pcpu = NULL; 365e829eb6dSJoseph Koshy } 366