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