hwpmc_soft.c revision 247836
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: head/sys/dev/hwpmc/hwpmc_soft.c 247836 2013-03-05 10:18:48Z fabient $"); 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 139233628Sfabient PMCDBG(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 if (soft_pc == NULL) 245233628Sfabient return (ENOMEM); 246233628Sfabient 247233628Sfabient pc = pmc_pcpu[cpu]; 248233628Sfabient 249233628Sfabient KASSERT(pc != NULL, ("[soft,%d] cpu %d null per-cpu", __LINE__, cpu)); 250233628Sfabient 251233628Sfabient soft_pcpu[cpu] = soft_pc; 252233628Sfabient phw = soft_pc->soft_hw; 253233628Sfabient first_ri = md->pmd_classdep[PMC_CLASS_INDEX_SOFT].pcd_ri; 254233628Sfabient 255233628Sfabient for (n = 0; n < SOFT_NPMCS; n++, phw++) { 256233628Sfabient phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | 257233628Sfabient PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n); 258233628Sfabient phw->phw_pmc = NULL; 259233628Sfabient pc->pc_hwpmcs[n + first_ri] = phw; 260233628Sfabient } 261233628Sfabient 262233628Sfabient return (0); 263233628Sfabient} 264233628Sfabient 265233628Sfabientstatic int 266233628Sfabientsoft_read_pmc(int cpu, int ri, pmc_value_t *v) 267233628Sfabient{ 268233628Sfabient struct pmc *pm; 269233628Sfabient const struct pmc_hw *phw; 270233628Sfabient 271233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 272233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 273233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 274233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 275233628Sfabient 276233628Sfabient phw = &soft_pcpu[cpu]->soft_hw[ri]; 277233628Sfabient pm = phw->phw_pmc; 278233628Sfabient 279233628Sfabient KASSERT(pm != NULL, 280233628Sfabient ("[soft,%d] no owner for PHW [cpu%d,pmc%d]", __LINE__, cpu, ri)); 281233628Sfabient 282233628Sfabient PMCDBG(MDP,REA,1,"soft-read id=%d", ri); 283233628Sfabient 284233628Sfabient *v = soft_pcpu[cpu]->soft_values[ri]; 285233628Sfabient 286233628Sfabient return (0); 287233628Sfabient} 288233628Sfabient 289233628Sfabientstatic int 290233628Sfabientsoft_write_pmc(int cpu, int ri, pmc_value_t v) 291233628Sfabient{ 292233628Sfabient struct pmc *pm; 293233628Sfabient const struct soft_descr *pd; 294233628Sfabient 295233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 296233628Sfabient ("[soft,%d] illegal cpu value %d", __LINE__, cpu)); 297233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 298233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 299233628Sfabient 300233628Sfabient pm = soft_pcpu[cpu]->soft_hw[ri].phw_pmc; 301233628Sfabient pd = &soft_pmcdesc[ri]; 302233628Sfabient 303233628Sfabient KASSERT(pm, 304233628Sfabient ("[soft,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); 305233628Sfabient 306233628Sfabient PMCDBG(MDP,WRI,1, "soft-write cpu=%d ri=%d v=%jx", cpu, ri, v); 307233628Sfabient 308233628Sfabient soft_pcpu[cpu]->soft_values[ri] = v; 309233628Sfabient 310233628Sfabient return (0); 311233628Sfabient} 312233628Sfabient 313233628Sfabientstatic int 314233628Sfabientsoft_release_pmc(int cpu, int ri, struct pmc *pmc) 315233628Sfabient{ 316233628Sfabient struct pmc_hw *phw; 317247836Sfabient enum pmc_event ev; 318247836Sfabient struct pmc_soft *ps; 319233628Sfabient 320233628Sfabient (void) pmc; 321233628Sfabient 322233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 323233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 324233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 325233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 326233628Sfabient 327233628Sfabient phw = &soft_pcpu[cpu]->soft_hw[ri]; 328233628Sfabient 329233628Sfabient KASSERT(phw->phw_pmc == NULL, 330233628Sfabient ("[soft,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 331233628Sfabient 332247836Sfabient ev = pmc->pm_event; 333247836Sfabient 334247836Sfabient /* Check if event is registered. */ 335247836Sfabient ps = pmc_soft_ev_acquire(ev); 336247836Sfabient KASSERT(ps != NULL, 337247836Sfabient ("[soft,%d] unregistered event %d", __LINE__, ev)); 338247836Sfabient pmc_soft_ev_release(ps); 339247836Sfabient /* Module unload is protected by pmc SX lock. */ 340247836Sfabient if (ps->ps_release != NULL) 341247836Sfabient ps->ps_release(); 342233628Sfabient return (0); 343233628Sfabient} 344233628Sfabient 345233628Sfabientstatic int 346233628Sfabientsoft_start_pmc(int cpu, int ri) 347233628Sfabient{ 348233628Sfabient struct pmc *pm; 349233628Sfabient struct soft_cpu *pc; 350233628Sfabient struct pmc_soft *ps; 351233628Sfabient 352233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 353233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 354233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 355233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 356233628Sfabient 357233628Sfabient pc = soft_pcpu[cpu]; 358233628Sfabient pm = pc->soft_hw[ri].phw_pmc; 359233628Sfabient 360233628Sfabient KASSERT(pm, 361233628Sfabient ("[soft,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); 362233628Sfabient 363233628Sfabient ps = pmc_soft_ev_acquire(pm->pm_event); 364233628Sfabient if (ps == NULL) 365233628Sfabient return (EINVAL); 366233628Sfabient atomic_add_int(&ps->ps_running, 1); 367233628Sfabient pmc_soft_ev_release(ps); 368233628Sfabient 369233628Sfabient return (0); 370233628Sfabient} 371233628Sfabient 372233628Sfabientstatic int 373233628Sfabientsoft_stop_pmc(int cpu, int ri) 374233628Sfabient{ 375233628Sfabient struct pmc *pm; 376233628Sfabient struct soft_cpu *pc; 377233628Sfabient struct pmc_soft *ps; 378233628Sfabient 379233628Sfabient KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 380233628Sfabient ("[soft,%d] illegal CPU value %d", __LINE__, cpu)); 381233628Sfabient KASSERT(ri >= 0 && ri < SOFT_NPMCS, 382233628Sfabient ("[soft,%d] illegal row-index %d", __LINE__, ri)); 383233628Sfabient 384233628Sfabient pc = soft_pcpu[cpu]; 385233628Sfabient pm = pc->soft_hw[ri].phw_pmc; 386233628Sfabient 387233628Sfabient KASSERT(pm, 388233628Sfabient ("[soft,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); 389233628Sfabient 390233628Sfabient ps = pmc_soft_ev_acquire(pm->pm_event); 391233628Sfabient /* event unregistered ? */ 392233628Sfabient if (ps != NULL) { 393233628Sfabient atomic_subtract_int(&ps->ps_running, 1); 394233628Sfabient pmc_soft_ev_release(ps); 395233628Sfabient } 396233628Sfabient 397233628Sfabient return (0); 398233628Sfabient} 399233628Sfabient 400233628Sfabientint 401233628Sfabientpmc_soft_intr(struct pmckern_soft *ks) 402233628Sfabient{ 403233628Sfabient struct pmc *pm; 404233628Sfabient struct soft_cpu *pc; 405233628Sfabient int ri, processed, error, user_mode; 406233628Sfabient 407233628Sfabient KASSERT(ks->pm_cpu >= 0 && ks->pm_cpu < pmc_cpu_max(), 408233628Sfabient ("[soft,%d] CPU %d out of range", __LINE__, ks->pm_cpu)); 409233628Sfabient 410233628Sfabient processed = 0; 411233628Sfabient pc = soft_pcpu[ks->pm_cpu]; 412233628Sfabient 413233628Sfabient for (ri = 0; ri < SOFT_NPMCS; ri++) { 414233628Sfabient 415233628Sfabient pm = pc->soft_hw[ri].phw_pmc; 416233628Sfabient if (pm == NULL || 417233628Sfabient pm->pm_state != PMC_STATE_RUNNING || 418233628Sfabient pm->pm_event != ks->pm_ev) { 419233628Sfabient continue; 420233628Sfabient } 421233628Sfabient 422233628Sfabient processed = 1; 423233628Sfabient if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) { 424247318Smav if ((pc->soft_values[ri]--) <= 0) 425247318Smav pc->soft_values[ri] += pm->pm_sc.pm_reloadcount; 426247318Smav else 427247318Smav continue; 428233628Sfabient user_mode = TRAPF_USERMODE(ks->pm_tf); 429233628Sfabient error = pmc_process_interrupt(ks->pm_cpu, PMC_SR, pm, 430233628Sfabient ks->pm_tf, user_mode); 431233628Sfabient if (error) { 432233628Sfabient soft_stop_pmc(ks->pm_cpu, ri); 433233628Sfabient continue; 434233628Sfabient } 435233628Sfabient 436233628Sfabient if (user_mode) { 437233628Sfabient /* If in user mode setup AST to process 438233628Sfabient * callchain out of interrupt context. 439233628Sfabient */ 440233628Sfabient curthread->td_flags |= TDF_ASTPENDING; 441233628Sfabient } 442247318Smav } else 443247318Smav pc->soft_values[ri]++; 444233628Sfabient } 445233628Sfabient 446233628Sfabient atomic_add_int(processed ? &pmc_stats.pm_intr_processed : 447233628Sfabient &pmc_stats.pm_intr_ignored, 1); 448233628Sfabient 449233628Sfabient return (processed); 450233628Sfabient} 451233628Sfabient 452233628Sfabientvoid 453233628Sfabientpmc_soft_initialize(struct pmc_mdep *md) 454233628Sfabient{ 455233628Sfabient struct pmc_classdep *pcd; 456233628Sfabient 457233628Sfabient /* Add SOFT PMCs. */ 458233628Sfabient soft_pcpu = malloc(sizeof(struct soft_cpu *) * pmc_cpu_max(), M_PMC, 459233628Sfabient M_ZERO|M_WAITOK); 460233628Sfabient 461233628Sfabient pcd = &md->pmd_classdep[PMC_CLASS_INDEX_SOFT]; 462233628Sfabient 463233628Sfabient pcd->pcd_caps = SOFT_CAPS; 464233628Sfabient pcd->pcd_class = PMC_CLASS_SOFT; 465233628Sfabient pcd->pcd_num = SOFT_NPMCS; 466233628Sfabient pcd->pcd_ri = md->pmd_npmc; 467233628Sfabient pcd->pcd_width = 64; 468233628Sfabient 469233628Sfabient pcd->pcd_allocate_pmc = soft_allocate_pmc; 470233628Sfabient pcd->pcd_config_pmc = soft_config_pmc; 471233628Sfabient pcd->pcd_describe = soft_describe; 472233628Sfabient pcd->pcd_get_config = soft_get_config; 473233628Sfabient pcd->pcd_get_msr = NULL; 474233628Sfabient pcd->pcd_pcpu_init = soft_pcpu_init; 475233628Sfabient pcd->pcd_pcpu_fini = soft_pcpu_fini; 476233628Sfabient pcd->pcd_read_pmc = soft_read_pmc; 477233628Sfabient pcd->pcd_write_pmc = soft_write_pmc; 478233628Sfabient pcd->pcd_release_pmc = soft_release_pmc; 479233628Sfabient pcd->pcd_start_pmc = soft_start_pmc; 480233628Sfabient pcd->pcd_stop_pmc = soft_stop_pmc; 481233628Sfabient 482233628Sfabient md->pmd_npmc += SOFT_NPMCS; 483233628Sfabient} 484233628Sfabient 485233628Sfabientvoid 486233628Sfabientpmc_soft_finalize(struct pmc_mdep *md) 487233628Sfabient{ 488233628Sfabient#ifdef INVARIANTS 489233628Sfabient int i, ncpus; 490233628Sfabient 491233628Sfabient ncpus = pmc_cpu_max(); 492233628Sfabient for (i = 0; i < ncpus; i++) 493233628Sfabient KASSERT(soft_pcpu[i] == NULL, ("[soft,%d] non-null pcpu cpu %d", 494233628Sfabient __LINE__, i)); 495233628Sfabient 496233628Sfabient KASSERT(md->pmd_classdep[PMC_CLASS_INDEX_SOFT].pcd_class == 497233628Sfabient PMC_CLASS_SOFT, ("[soft,%d] class mismatch", __LINE__)); 498233628Sfabient#endif 499233628Sfabient free(soft_pcpu, M_PMC); 500233628Sfabient soft_pcpu = NULL; 501233628Sfabient} 502