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 73a35453b9SMitchell 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 142a35453b9SMitchell 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 155a35453b9SMitchell 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 223*39f92a76SMitchell Horne tsc_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v) 224e829eb6dSJoseph Koshy { 225aee6e7dcSMateusz Guzik enum pmc_mode mode __diagused; 226e829eb6dSJoseph Koshy 227e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 228e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 229e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal ri %d", __LINE__, ri)); 230e829eb6dSJoseph Koshy 231e829eb6dSJoseph Koshy mode = PMC_TO_MODE(pm); 232e829eb6dSJoseph Koshy 233e829eb6dSJoseph Koshy KASSERT(mode == PMC_MODE_SC, 234e829eb6dSJoseph Koshy ("[tsc,%d] illegal pmc mode %d", __LINE__, mode)); 235e829eb6dSJoseph Koshy 2364a3690dfSJohn Baldwin PMCDBG1(MDP,REA,1,"tsc-read id=%d", ri); 237e829eb6dSJoseph Koshy 238e829eb6dSJoseph Koshy *v = rdtsc(); 239e829eb6dSJoseph Koshy 240e829eb6dSJoseph Koshy return (0); 241e829eb6dSJoseph Koshy } 242e829eb6dSJoseph Koshy 243e829eb6dSJoseph Koshy static int 244a35453b9SMitchell Horne tsc_release_pmc(int cpu, int ri __diagused, struct pmc *pmc __unused) 245e829eb6dSJoseph Koshy { 246aee6e7dcSMateusz Guzik struct pmc_hw *phw __diagused; 247e829eb6dSJoseph Koshy 248e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 249e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 250e829eb6dSJoseph Koshy KASSERT(ri == 0, 251e829eb6dSJoseph Koshy ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 252e829eb6dSJoseph Koshy 253e829eb6dSJoseph Koshy phw = &tsc_pcpu[cpu]->tc_hw; 254e829eb6dSJoseph Koshy 255e829eb6dSJoseph Koshy KASSERT(phw->phw_pmc == NULL, 256e829eb6dSJoseph Koshy ("[tsc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 257e829eb6dSJoseph Koshy 258e829eb6dSJoseph Koshy /* 259e829eb6dSJoseph Koshy * Nothing to do. 260e829eb6dSJoseph Koshy */ 261e829eb6dSJoseph Koshy return (0); 262e829eb6dSJoseph Koshy } 263e829eb6dSJoseph Koshy 264e829eb6dSJoseph Koshy static int 265*39f92a76SMitchell Horne tsc_start_pmc(int cpu __diagused, int ri __diagused, struct pmc *pm __unused) 266e829eb6dSJoseph Koshy { 267e829eb6dSJoseph Koshy 268e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 269e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 270e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 271e829eb6dSJoseph Koshy 272e829eb6dSJoseph Koshy return (0); /* TSCs are always running. */ 273e829eb6dSJoseph Koshy } 274e829eb6dSJoseph Koshy 275e829eb6dSJoseph Koshy static int 276*39f92a76SMitchell Horne tsc_stop_pmc(int cpu __diagused, int ri __diagused, struct pmc *pm __unused) 277e829eb6dSJoseph Koshy { 278e829eb6dSJoseph Koshy 279e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 280e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 281e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 282e829eb6dSJoseph Koshy 283e829eb6dSJoseph Koshy return (0); /* Cannot actually stop a TSC. */ 284e829eb6dSJoseph Koshy } 285e829eb6dSJoseph Koshy 286e829eb6dSJoseph Koshy static int 287*39f92a76SMitchell Horne tsc_write_pmc(int cpu __diagused, int ri __diagused, struct pmc *pm __unused, 288*39f92a76SMitchell Horne pmc_value_t v __unused) 289e829eb6dSJoseph Koshy { 290e829eb6dSJoseph Koshy 291e829eb6dSJoseph Koshy KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 292e829eb6dSJoseph Koshy ("[tsc,%d] illegal CPU value %d", __LINE__, cpu)); 293e829eb6dSJoseph Koshy KASSERT(ri == 0, ("[tsc,%d] illegal row-index %d", __LINE__, ri)); 294e829eb6dSJoseph Koshy 295e829eb6dSJoseph Koshy /* 296e829eb6dSJoseph Koshy * The TSCs are used as timecounters by the kernel, so even 297e829eb6dSJoseph Koshy * though some i386 CPUs support writeable TSCs, we don't 298e829eb6dSJoseph Koshy * support writing changing TSC values through the HWPMC API. 299e829eb6dSJoseph Koshy */ 300e829eb6dSJoseph Koshy return (0); 301e829eb6dSJoseph Koshy } 302e829eb6dSJoseph Koshy 303e829eb6dSJoseph Koshy int 304e829eb6dSJoseph Koshy pmc_tsc_initialize(struct pmc_mdep *md, int maxcpu) 305e829eb6dSJoseph Koshy { 306e829eb6dSJoseph Koshy struct pmc_classdep *pcd; 307e829eb6dSJoseph Koshy 308e829eb6dSJoseph Koshy KASSERT(md != NULL, ("[tsc,%d] md is NULL", __LINE__)); 309e829eb6dSJoseph Koshy KASSERT(md->pmd_nclass >= 1, ("[tsc,%d] dubious md->nclass %d", 310e829eb6dSJoseph Koshy __LINE__, md->pmd_nclass)); 311e829eb6dSJoseph Koshy 312e829eb6dSJoseph Koshy tsc_pcpu = malloc(sizeof(struct tsc_cpu *) * maxcpu, M_PMC, 313e829eb6dSJoseph Koshy M_ZERO|M_WAITOK); 314e829eb6dSJoseph Koshy 315e829eb6dSJoseph Koshy pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_TSC]; 316e829eb6dSJoseph Koshy 317e829eb6dSJoseph Koshy pcd->pcd_caps = PMC_CAP_READ; 318e829eb6dSJoseph Koshy pcd->pcd_class = PMC_CLASS_TSC; 319e829eb6dSJoseph Koshy pcd->pcd_num = TSC_NPMCS; 320e829eb6dSJoseph Koshy pcd->pcd_ri = md->pmd_npmc; 321e829eb6dSJoseph Koshy pcd->pcd_width = 64; 322e829eb6dSJoseph Koshy 323e829eb6dSJoseph Koshy pcd->pcd_allocate_pmc = tsc_allocate_pmc; 324e829eb6dSJoseph Koshy pcd->pcd_config_pmc = tsc_config_pmc; 325e829eb6dSJoseph Koshy pcd->pcd_describe = tsc_describe; 326e829eb6dSJoseph Koshy pcd->pcd_get_config = tsc_get_config; 327e829eb6dSJoseph Koshy pcd->pcd_get_msr = tsc_get_msr; 328e829eb6dSJoseph Koshy pcd->pcd_pcpu_init = tsc_pcpu_init; 329e829eb6dSJoseph Koshy pcd->pcd_pcpu_fini = tsc_pcpu_fini; 330e829eb6dSJoseph Koshy pcd->pcd_read_pmc = tsc_read_pmc; 331e829eb6dSJoseph Koshy pcd->pcd_release_pmc = tsc_release_pmc; 332e829eb6dSJoseph Koshy pcd->pcd_start_pmc = tsc_start_pmc; 333e829eb6dSJoseph Koshy pcd->pcd_stop_pmc = tsc_stop_pmc; 334e829eb6dSJoseph Koshy pcd->pcd_write_pmc = tsc_write_pmc; 335e829eb6dSJoseph Koshy 336e829eb6dSJoseph Koshy md->pmd_npmc += TSC_NPMCS; 337e829eb6dSJoseph Koshy 338e829eb6dSJoseph Koshy return (0); 339e829eb6dSJoseph Koshy } 340e829eb6dSJoseph Koshy 341e829eb6dSJoseph Koshy void 342a35453b9SMitchell Horne pmc_tsc_finalize(struct pmc_mdep *md __diagused) 343e829eb6dSJoseph Koshy { 344e829eb6dSJoseph Koshy #ifdef INVARIANTS 345e829eb6dSJoseph Koshy int i, ncpus; 346e829eb6dSJoseph Koshy 347e829eb6dSJoseph Koshy ncpus = pmc_cpu_max(); 348e829eb6dSJoseph Koshy for (i = 0; i < ncpus; i++) 349e829eb6dSJoseph Koshy KASSERT(tsc_pcpu[i] == NULL, ("[tsc,%d] non-null pcpu cpu %d", 350e829eb6dSJoseph Koshy __LINE__, i)); 351e829eb6dSJoseph Koshy 352e829eb6dSJoseph Koshy KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_TSC].pcd_class == 353e829eb6dSJoseph Koshy PMC_CLASS_TSC, ("[tsc,%d] class mismatch", __LINE__)); 354e829eb6dSJoseph Koshy #endif 355e829eb6dSJoseph Koshy 356e829eb6dSJoseph Koshy free(tsc_pcpu, M_PMC); 357e829eb6dSJoseph Koshy tsc_pcpu = NULL; 358e829eb6dSJoseph Koshy } 359