1233628Sfabient/*- 2233628Sfabient * Copyright (c) 2012 Fabien Thomas 3233628Sfabient * All rights reserved. 4233628Sfabient * 5233628Sfabient * Redistribution and use in source and binary forms, with or without 6233628Sfabient * modification, are permitted provided that the following conditions 7233628Sfabient * are met: 8233628Sfabient * 1. Redistributions of source code must retain the above copyright 9233628Sfabient * notice, this list of conditions and the following disclaimer. 10233628Sfabient * 2. Redistributions in binary form must reproduce the above copyright 11233628Sfabient * notice, this list of conditions and the following disclaimer in the 12233628Sfabient * documentation and/or other materials provided with the distribution. 13233628Sfabient * 14233628Sfabient * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15233628Sfabient * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16233628Sfabient * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17233628Sfabient * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18233628Sfabient * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19233628Sfabient * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20233628Sfabient * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21233628Sfabient * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22233628Sfabient * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23233628Sfabient * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24233628Sfabient * SUCH DAMAGE. 25233628Sfabient */ 26233628Sfabient 27233628Sfabient#include <sys/cdefs.h> 28233628Sfabient__FBSDID("$FreeBSD$"); 29233628Sfabient 30233628Sfabient#include <sys/param.h> 31233628Sfabient#include <sys/pmc.h> 32233628Sfabient#include <sys/pmckern.h> 33233628Sfabient#include <sys/systm.h> 34233628Sfabient#include <sys/mutex.h> 35233628Sfabient 36233628Sfabient#include <machine/cpu.h> 37233628Sfabient#include <machine/cpufunc.h> 38233628Sfabient 39233628Sfabient#include "hwpmc_soft.h" 40233628Sfabient 41233628Sfabient/* 42233628Sfabient * Software PMC support. 43233628Sfabient */ 44233628Sfabient 45233628Sfabient#define SOFT_CAPS (PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_INTERRUPT | \ 46233628Sfabient PMC_CAP_USER | PMC_CAP_SYSTEM) 47233628Sfabient 48233628Sfabientstruct soft_descr { 49233628Sfabient struct pmc_descr pm_descr; /* "base class" */ 50233628Sfabient}; 51233628Sfabient 52233628Sfabientstatic struct soft_descr soft_pmcdesc[SOFT_NPMCS] = 53233628Sfabient{ 54233628Sfabient#define SOFT_PMCDESCR(N) \ 55233628Sfabient { \ 56233628Sfabient .pm_descr = \ 57233628Sfabient { \ 58233628Sfabient .pd_name = #N, \ 59233628Sfabient .pd_class = PMC_CLASS_SOFT, \ 60233628Sfabient .pd_caps = SOFT_CAPS, \ 61233628Sfabient .pd_width = 64 \ 62233628Sfabient }, \ 63233628Sfabient } 64233628Sfabient 65233628Sfabient SOFT_PMCDESCR(SOFT0), 66233628Sfabient SOFT_PMCDESCR(SOFT1), 67233628Sfabient SOFT_PMCDESCR(SOFT2), 68233628Sfabient SOFT_PMCDESCR(SOFT3), 69233628Sfabient SOFT_PMCDESCR(SOFT4), 70233628Sfabient SOFT_PMCDESCR(SOFT5), 71233628Sfabient SOFT_PMCDESCR(SOFT6), 72233628Sfabient SOFT_PMCDESCR(SOFT7), 73233628Sfabient SOFT_PMCDESCR(SOFT8), 74233628Sfabient SOFT_PMCDESCR(SOFT9), 75233628Sfabient SOFT_PMCDESCR(SOFT10), 76233628Sfabient SOFT_PMCDESCR(SOFT11), 77233628Sfabient SOFT_PMCDESCR(SOFT12), 78233628Sfabient SOFT_PMCDESCR(SOFT13), 79233628Sfabient SOFT_PMCDESCR(SOFT14), 80233628Sfabient SOFT_PMCDESCR(SOFT15) 81233628Sfabient}; 82233628Sfabient 83233628Sfabient/* 84233628Sfabient * Per-CPU data structure. 85233628Sfabient */ 86233628Sfabient 87233628Sfabientstruct soft_cpu { 88233628Sfabient struct pmc_hw soft_hw[SOFT_NPMCS]; 89233628Sfabient pmc_value_t soft_values[SOFT_NPMCS]; 90233628Sfabient}; 91233628Sfabient 92233628Sfabient 93233628Sfabientstatic struct soft_cpu **soft_pcpu; 94233628Sfabient 95233628Sfabientstatic int 96233628Sfabientsoft_allocate_pmc(int cpu, int ri, struct pmc *pm, 97233628Sfabient const struct pmc_op_pmcallocate *a) 98233628Sfabient{ 99233628Sfabient enum pmc_event ev; 100233628Sfabient struct pmc_soft *ps; 101233628Sfabient 102233628Sfabient (void) cpu; 103233628Sfabient 104233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 105233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 106233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 107233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 108233628Sfabient 109233628Sfabient if (a->pm_class != PMC_CLASS_SOFT) 110233628Sfabient return (EINVAL); 111233628Sfabient 112233628Sfabient if ((pm->pm_caps & SOFT_CAPS) == 0) 113233628Sfabient return (EINVAL); 114233628Sfabient 115233628Sfabient if ((pm->pm_caps & ~SOFT_CAPS) != 0) 116233628Sfabient return (EPERM); 117233628Sfabient 118233628Sfabient ev = pm->pm_event; 119245339Ssbruno if ((int)ev < PMC_EV_SOFT_FIRST || (int)ev > PMC_EV_SOFT_LAST) 120233628Sfabient return (EINVAL); 121233628Sfabient 122233628Sfabient /* Check if event is registered. */ 123233628Sfabient ps = pmc_soft_ev_acquire(ev); 124233628Sfabient if (ps == NULL) 125233628Sfabient return (EINVAL); 126233628Sfabient pmc_soft_ev_release(ps); 127247836Sfabient /* Module unload is protected by pmc SX lock. */ 128247836Sfabient if (ps->ps_alloc != NULL) 129247836Sfabient ps->ps_alloc(); 130233628Sfabient 131233628Sfabient return (0); 132233628Sfabient} 133233628Sfabient 134233628Sfabientstatic int 135233628Sfabientsoft_config_pmc(int cpu, int ri, struct pmc *pm) 136233628Sfabient{ 137233628Sfabient struct pmc_hw *phw; 138233628Sfabient 139282658Sjhb PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); 140233628Sfabient 141233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 142233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 143233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 144233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 145233628Sfabient 146233628Sfabient phw = &soft_pcpu[cpu]->soft_hw[ri]; 147233628Sfabient 148233628Sfabient KASSERT(pm == NULL || phw->phw_pmc == NULL, 149233628Sfabient ("[soft,%d] pm=%p phw->pm=%p hwpmc not unconfigured", __LINE__, 150233628Sfabient pm, phw->phw_pmc)); 151233628Sfabient 152233628Sfabient phw->phw_pmc = pm; 153233628Sfabient 154233628Sfabient return (0); 155233628Sfabient} 156233628Sfabient 157233628Sfabientstatic int 158233628Sfabientsoft_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 159233628Sfabient{ 160233628Sfabient int error; 161233628Sfabient size_t copied; 162233628Sfabient const struct soft_descr *pd; 163233628Sfabient struct pmc_hw *phw; 164233628Sfabient 165233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 166233628Sfabient ("[soft,%d] illegal CPU %d", __LINE__, cpu)); 167233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 168233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 169233628Sfabient 170233628Sfabient phw = &soft_pcpu[cpu]->soft_hw[ri]; 171233628Sfabient pd = &soft_pmcdesc[ri]; 172233628Sfabient 173233628Sfabient if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name, 174233628Sfabient PMC_NAME_MAX, &copied)) != 0) 175233628Sfabient return (error); 176233628Sfabient 177233628Sfabient pi->pm_class = pd->pm_descr.pd_class; 178233628Sfabient 179233628Sfabient if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 180233628Sfabient pi->pm_enabled = TRUE; 181233628Sfabient *ppmc = phw->phw_pmc; 182233628Sfabient } else { 183233628Sfabient pi->pm_enabled = FALSE; 184233628Sfabient *ppmc = NULL; 185233628Sfabient } 186233628Sfabient 187233628Sfabient return (0); 188233628Sfabient} 189233628Sfabient 190233628Sfabientstatic int 191233628Sfabientsoft_get_config(int cpu, int ri, struct pmc **ppm) 192233628Sfabient{ 193233628Sfabient (void) ri; 194233628Sfabient 195233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 196233628Sfabient ("[soft,%d] illegal CPU %d", __LINE__, cpu)); 197233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 198233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 199233628Sfabient 200233628Sfabient *ppm = soft_pcpu[cpu]->soft_hw[ri].phw_pmc; 201233628Sfabient return (0); 202233628Sfabient} 203233628Sfabient 204233628Sfabientstatic int 205233628Sfabientsoft_pcpu_fini(struct pmc_mdep *md, int cpu) 206233628Sfabient{ 207233628Sfabient int ri; 208233628Sfabient struct pmc_cpu *pc; 209233628Sfabient 210233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 211233628Sfabient ("[soft,%d] illegal cpu %d", __LINE__, cpu)); 212233628Sfabient KASSERT(soft_pcpu[cpu] != NULL, ("[soft,%d] null pcpu", __LINE__)); 213233628Sfabient 214233628Sfabient free(soft_pcpu[cpu], M_PMC); 215233628Sfabient soft_pcpu[cpu] = NULL; 216233628Sfabient 217233628Sfabient ri = md->pmd_classdep[PMC_CLASS_INDEX_SOFT].pcd_ri; 218233628Sfabient 219233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 220233628Sfabient ("[soft,%d] ri=%d", __LINE__, ri)); 221233628Sfabient 222233628Sfabient pc = pmc_pcpu[cpu]; 223233628Sfabient pc->pc_hwpmcs[ri] = NULL; 224233628Sfabient 225233628Sfabient return (0); 226233628Sfabient} 227233628Sfabient 228233628Sfabientstatic int 229233628Sfabientsoft_pcpu_init(struct pmc_mdep *md, int cpu) 230233628Sfabient{ 231233628Sfabient int first_ri, n; 232233628Sfabient struct pmc_cpu *pc; 233233628Sfabient struct soft_cpu *soft_pc; 234233628Sfabient struct pmc_hw *phw; 235233628Sfabient 236233628Sfabient 237233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 238233628Sfabient ("[soft,%d] illegal cpu %d", __LINE__, cpu)); 239233628Sfabient KASSERT(soft_pcpu, ("[soft,%d] null pcpu", __LINE__)); 240233628Sfabient KASSERT(soft_pcpu[cpu] == NULL, ("[soft,%d] non-null per-cpu", 241233628Sfabient __LINE__)); 242233628Sfabient 243233628Sfabient soft_pc = malloc(sizeof(struct soft_cpu), M_PMC, M_WAITOK|M_ZERO); 244233628Sfabient pc = pmc_pcpu[cpu]; 245233628Sfabient 246233628Sfabient KASSERT(pc != NULL, ("[soft,%d] cpu %d null per-cpu", __LINE__, cpu)); 247233628Sfabient 248233628Sfabient soft_pcpu[cpu] = soft_pc; 249233628Sfabient phw = soft_pc->soft_hw; 250233628Sfabient first_ri = md->pmd_classdep[PMC_CLASS_INDEX_SOFT].pcd_ri; 251233628Sfabient 252233628Sfabient for (n = 0; n < SOFT_NPMCS; n++, phw++) { 253233628Sfabient phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | 254233628Sfabient PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n); 255233628Sfabient phw->phw_pmc = NULL; 256233628Sfabient pc->pc_hwpmcs[n + first_ri] = phw; 257233628Sfabient } 258233628Sfabient 259233628Sfabient return (0); 260233628Sfabient} 261233628Sfabient 262233628Sfabientstatic int 263233628Sfabientsoft_read_pmc(int cpu, int ri, pmc_value_t *v) 264233628Sfabient{ 265233628Sfabient struct pmc *pm; 266233628Sfabient const struct pmc_hw *phw; 267233628Sfabient 268233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 269233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 270233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 271233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 272233628Sfabient 273233628Sfabient phw = &soft_pcpu[cpu]->soft_hw[ri]; 274233628Sfabient pm = phw->phw_pmc; 275233628Sfabient 276233628Sfabient KASSERT(pm != NULL, 277233628Sfabient ("[soft,%d] no owner for PHW [cpu%d,pmc%d]", __LINE__, cpu, ri)); 278233628Sfabient 279282658Sjhb PMCDBG1(MDP,REA,1,"soft-read id=%d", ri); 280233628Sfabient 281233628Sfabient *v = soft_pcpu[cpu]->soft_values[ri]; 282233628Sfabient 283233628Sfabient return (0); 284233628Sfabient} 285233628Sfabient 286233628Sfabientstatic int 287233628Sfabientsoft_write_pmc(int cpu, int ri, pmc_value_t v) 288233628Sfabient{ 289233628Sfabient struct pmc *pm; 290233628Sfabient const struct soft_descr *pd; 291233628Sfabient 292233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 293233628Sfabient ("[soft,%d] illegal cpu value %d", __LINE__, cpu)); 294233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 295233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 296233628Sfabient 297233628Sfabient pm = soft_pcpu[cpu]->soft_hw[ri].phw_pmc; 298233628Sfabient pd = &soft_pmcdesc[ri]; 299233628Sfabient 300233628Sfabient KASSERT(pm, 301233628Sfabient ("[soft,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); 302233628Sfabient 303282658Sjhb PMCDBG3(MDP,WRI,1, "soft-write cpu=%d ri=%d v=%jx", cpu, ri, v); 304233628Sfabient 305233628Sfabient soft_pcpu[cpu]->soft_values[ri] = v; 306233628Sfabient 307233628Sfabient return (0); 308233628Sfabient} 309233628Sfabient 310233628Sfabientstatic int 311233628Sfabientsoft_release_pmc(int cpu, int ri, struct pmc *pmc) 312233628Sfabient{ 313233628Sfabient struct pmc_hw *phw; 314247836Sfabient enum pmc_event ev; 315247836Sfabient struct pmc_soft *ps; 316233628Sfabient 317233628Sfabient (void) pmc; 318233628Sfabient 319233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 320233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 321233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 322233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 323233628Sfabient 324233628Sfabient phw = &soft_pcpu[cpu]->soft_hw[ri]; 325233628Sfabient 326233628Sfabient KASSERT(phw->phw_pmc == NULL, 327233628Sfabient ("[soft,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 328233628Sfabient 329247836Sfabient ev = pmc->pm_event; 330247836Sfabient 331247836Sfabient /* Check if event is registered. */ 332247836Sfabient ps = pmc_soft_ev_acquire(ev); 333247836Sfabient KASSERT(ps != NULL, 334247836Sfabient ("[soft,%d] unregistered event %d", __LINE__, ev)); 335247836Sfabient pmc_soft_ev_release(ps); 336247836Sfabient /* Module unload is protected by pmc SX lock. */ 337247836Sfabient if (ps->ps_release != NULL) 338247836Sfabient ps->ps_release(); 339233628Sfabient return (0); 340233628Sfabient} 341233628Sfabient 342233628Sfabientstatic int 343233628Sfabientsoft_start_pmc(int cpu, int ri) 344233628Sfabient{ 345233628Sfabient struct pmc *pm; 346233628Sfabient struct soft_cpu *pc; 347233628Sfabient struct pmc_soft *ps; 348233628Sfabient 349233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 350233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 351233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 352233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 353233628Sfabient 354233628Sfabient pc = soft_pcpu[cpu]; 355233628Sfabient pm = pc->soft_hw[ri].phw_pmc; 356233628Sfabient 357233628Sfabient KASSERT(pm, 358233628Sfabient ("[soft,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); 359233628Sfabient 360233628Sfabient ps = pmc_soft_ev_acquire(pm->pm_event); 361233628Sfabient if (ps == NULL) 362233628Sfabient return (EINVAL); 363233628Sfabient atomic_add_int(&ps->ps_running, 1); 364233628Sfabient pmc_soft_ev_release(ps); 365233628Sfabient 366233628Sfabient return (0); 367233628Sfabient} 368233628Sfabient 369233628Sfabientstatic int 370233628Sfabientsoft_stop_pmc(int cpu, int ri) 371233628Sfabient{ 372233628Sfabient struct pmc *pm; 373233628Sfabient struct soft_cpu *pc; 374233628Sfabient struct pmc_soft *ps; 375233628Sfabient 376233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 377233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 378233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 379233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 380233628Sfabient 381233628Sfabient pc = soft_pcpu[cpu]; 382233628Sfabient pm = pc->soft_hw[ri].phw_pmc; 383233628Sfabient 384233628Sfabient KASSERT(pm, 385233628Sfabient ("[soft,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); 386233628Sfabient 387233628Sfabient ps = pmc_soft_ev_acquire(pm->pm_event); 388233628Sfabient /* event unregistered ? */ 389233628Sfabient if (ps != NULL) { 390233628Sfabient atomic_subtract_int(&ps->ps_running, 1); 391233628Sfabient pmc_soft_ev_release(ps); 392233628Sfabient } 393233628Sfabient 394233628Sfabient return (0); 395233628Sfabient} 396233628Sfabient 397233628Sfabientint 398233628Sfabientpmc_soft_intr(struct pmckern_soft *ks) 399233628Sfabient{ 400233628Sfabient struct pmc *pm; 401233628Sfabient struct soft_cpu *pc; 402233628Sfabient int ri, processed, error, user_mode; 403233628Sfabient 404233628Sfabient KASSERT(ks->pm_cpu >= 0 && ks->pm_cpu < pmc_cpu_max(), 405233628Sfabient ("[soft,%d] CPU %d out of range", __LINE__, ks->pm_cpu)); 406233628Sfabient 407233628Sfabient processed = 0; 408233628Sfabient pc = soft_pcpu[ks->pm_cpu]; 409233628Sfabient 410233628Sfabient for (ri = 0; ri < SOFT_NPMCS; ri++) { 411233628Sfabient 412233628Sfabient pm = pc->soft_hw[ri].phw_pmc; 413233628Sfabient if (pm == NULL || 414233628Sfabient pm->pm_state != PMC_STATE_RUNNING || 415233628Sfabient pm->pm_event != ks->pm_ev) { 416233628Sfabient continue; 417233628Sfabient } 418233628Sfabient 419233628Sfabient processed = 1; 420233628Sfabient if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) { 421247318Smav if ((pc->soft_values[ri]--) <= 0) 422247318Smav pc->soft_values[ri] += pm->pm_sc.pm_reloadcount; 423247318Smav else 424247318Smav continue; 425233628Sfabient user_mode = TRAPF_USERMODE(ks->pm_tf); 426233628Sfabient error = pmc_process_interrupt(ks->pm_cpu, PMC_SR, pm, 427233628Sfabient ks->pm_tf, user_mode); 428233628Sfabient if (error) { 429233628Sfabient soft_stop_pmc(ks->pm_cpu, ri); 430233628Sfabient continue; 431233628Sfabient } 432233628Sfabient 433233628Sfabient if (user_mode) { 434233628Sfabient /* If in user mode setup AST to process 435233628Sfabient * callchain out of interrupt context. 436233628Sfabient */ 437233628Sfabient curthread->td_flags |= TDF_ASTPENDING; 438233628Sfabient } 439247318Smav } else 440247318Smav pc->soft_values[ri]++; 441233628Sfabient } 442233628Sfabient 443233628Sfabient atomic_add_int(processed ? &pmc_stats.pm_intr_processed : 444233628Sfabient &pmc_stats.pm_intr_ignored, 1); 445233628Sfabient 446233628Sfabient return (processed); 447233628Sfabient} 448233628Sfabient 449233628Sfabientvoid 450233628Sfabientpmc_soft_initialize(struct pmc_mdep *md) 451233628Sfabient{ 452233628Sfabient struct pmc_classdep *pcd; 453233628Sfabient 454233628Sfabient /* Add SOFT PMCs. */ 455233628Sfabient soft_pcpu = malloc(sizeof(struct soft_cpu *) * pmc_cpu_max(), M_PMC, 456233628Sfabient M_ZERO|M_WAITOK); 457233628Sfabient 458233628Sfabient pcd = &md->pmd_classdep[PMC_CLASS_INDEX_SOFT]; 459233628Sfabient 460233628Sfabient pcd->pcd_caps = SOFT_CAPS; 461233628Sfabient pcd->pcd_class = PMC_CLASS_SOFT; 462233628Sfabient pcd->pcd_num = SOFT_NPMCS; 463233628Sfabient pcd->pcd_ri = md->pmd_npmc; 464233628Sfabient pcd->pcd_width = 64; 465233628Sfabient 466233628Sfabient pcd->pcd_allocate_pmc = soft_allocate_pmc; 467233628Sfabient pcd->pcd_config_pmc = soft_config_pmc; 468233628Sfabient pcd->pcd_describe = soft_describe; 469233628Sfabient pcd->pcd_get_config = soft_get_config; 470233628Sfabient pcd->pcd_get_msr = NULL; 471233628Sfabient pcd->pcd_pcpu_init = soft_pcpu_init; 472233628Sfabient pcd->pcd_pcpu_fini = soft_pcpu_fini; 473233628Sfabient pcd->pcd_read_pmc = soft_read_pmc; 474233628Sfabient pcd->pcd_write_pmc = soft_write_pmc; 475233628Sfabient pcd->pcd_release_pmc = soft_release_pmc; 476233628Sfabient pcd->pcd_start_pmc = soft_start_pmc; 477233628Sfabient pcd->pcd_stop_pmc = soft_stop_pmc; 478233628Sfabient 479233628Sfabient md->pmd_npmc += SOFT_NPMCS; 480233628Sfabient} 481233628Sfabient 482233628Sfabientvoid 483233628Sfabientpmc_soft_finalize(struct pmc_mdep *md) 484233628Sfabient{ 485233628Sfabient#ifdef INVARIANTS 486233628Sfabient int i, ncpus; 487233628Sfabient 488233628Sfabient ncpus = pmc_cpu_max(); 489233628Sfabient for (i = 0; i < ncpus; i++) 490233628Sfabient KASSERT(soft_pcpu[i] == NULL, ("[soft,%d] non-null pcpu cpu %d", 491233628Sfabient __LINE__, i)); 492233628Sfabient 493233628Sfabient KASSERT(md->pmd_classdep[PMC_CLASS_INDEX_SOFT].pcd_class == 494233628Sfabient PMC_CLASS_SOFT, ("[soft,%d] class mismatch", __LINE__)); 495233628Sfabient#endif 496233628Sfabient free(soft_pcpu, M_PMC); 497233628Sfabient soft_pcpu = NULL; 498233628Sfabient} 499