libpmc.c revision 200928
1145256Sjkoshy/*- 2177107Sjkoshy * Copyright (c) 2003-2008 Joseph Koshy 3145256Sjkoshy * All rights reserved. 4145256Sjkoshy * 5145256Sjkoshy * Redistribution and use in source and binary forms, with or without 6145256Sjkoshy * modification, are permitted provided that the following conditions 7145256Sjkoshy * are met: 8145256Sjkoshy * 1. Redistributions of source code must retain the above copyright 9145256Sjkoshy * notice, this list of conditions and the following disclaimer. 10145256Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11145256Sjkoshy * notice, this list of conditions and the following disclaimer in the 12145256Sjkoshy * documentation and/or other materials provided with the distribution. 13145256Sjkoshy * 14145256Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15145256Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16145256Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17145256Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18145256Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19145256Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20145256Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21145256Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22145256Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23145256Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24145256Sjkoshy * SUCH DAMAGE. 25145256Sjkoshy */ 26145256Sjkoshy 27145256Sjkoshy#include <sys/cdefs.h> 28145256Sjkoshy__FBSDID("$FreeBSD: head/lib/libpmc/libpmc.c 200928 2009-12-23 23:16:54Z rpaulo $"); 29145256Sjkoshy 30145256Sjkoshy#include <sys/types.h> 31145256Sjkoshy#include <sys/module.h> 32145256Sjkoshy#include <sys/pmc.h> 33145256Sjkoshy#include <sys/syscall.h> 34145256Sjkoshy 35145256Sjkoshy#include <ctype.h> 36145256Sjkoshy#include <errno.h> 37145256Sjkoshy#include <fcntl.h> 38145256Sjkoshy#include <pmc.h> 39145256Sjkoshy#include <stdio.h> 40145256Sjkoshy#include <stdlib.h> 41145256Sjkoshy#include <string.h> 42145256Sjkoshy#include <strings.h> 43145256Sjkoshy#include <unistd.h> 44145256Sjkoshy 45185363Sjkoshy#include "libpmcinternal.h" 46185363Sjkoshy 47145256Sjkoshy/* Function prototypes */ 48145340Smarcel#if defined(__i386__) 49145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 50145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 51147191Sjkoshy#endif 52147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 53185363Sjkoshystatic int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 54185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 55185363Sjkoshystatic int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 56185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 57147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 58145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 59147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 60147759Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 61147191Sjkoshy#endif 62147191Sjkoshy#if defined(__i386__) 63145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 64145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 65147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 66145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 67145256Sjkoshy#endif 68183725Sjkoshy#if defined(__amd64__) || defined(__i386__) 69183725Sjkoshystatic int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 70183725Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 71183725Sjkoshy#endif 72200928Srpaulo#if defined(__XSCALE__) 73200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 74200928Srpaulo struct pmc_op_pmcallocate *_pmc_config); 75200928Srpaulo#endif 76145256Sjkoshy 77145256Sjkoshy#define PMC_CALL(cmd, params) \ 78145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 79145256Sjkoshy 80145256Sjkoshy/* 81145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 82145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 83145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 84145256Sjkoshy * lookup table. 85145256Sjkoshy */ 86145256Sjkoshystruct pmc_event_alias { 87145256Sjkoshy const char *pm_alias; 88145256Sjkoshy const char *pm_spec; 89145256Sjkoshy}; 90145256Sjkoshy 91145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 92145256Sjkoshy 93145256Sjkoshy/* 94183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 95145256Sjkoshy * to integer codes used by the PMC KLD. 96145256Sjkoshy */ 97145256Sjkoshystruct pmc_event_descr { 98145256Sjkoshy const char *pm_ev_name; 99145256Sjkoshy enum pmc_event pm_ev_code; 100145256Sjkoshy}; 101145256Sjkoshy 102183725Sjkoshy/* 103183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 104183725Sjkoshy * event names to event tables and other PMC class data. 105183725Sjkoshy */ 106183725Sjkoshystruct pmc_class_descr { 107183725Sjkoshy const char *pm_evc_name; 108183725Sjkoshy size_t pm_evc_name_size; 109183725Sjkoshy enum pmc_class pm_evc_class; 110183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 111183725Sjkoshy size_t pm_evc_event_table_size; 112183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 113183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 114183725Sjkoshy}; 115183725Sjkoshy 116183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 117183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 118183725Sjkoshy 119183725Sjkoshy#undef __PMC_EV 120183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 121183725Sjkoshy 122183725Sjkoshy/* 123185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 124183725Sjkoshy * 125185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 126183725Sjkoshy */ 127185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 128183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 129183725Sjkoshy { \ 130183725Sjkoshy __PMC_EV_##C() \ 131185363Sjkoshy } 132185363Sjkoshy 133185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 134185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 135185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 136185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 137185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 138185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 139200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 140185363Sjkoshy 141185363Sjkoshy#undef __PMC_EV_ALIAS 142185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 143185363Sjkoshy 144185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 145185363Sjkoshy{ 146185363Sjkoshy __PMC_EV_ALIAS_ATOM() 147185363Sjkoshy}; 148185363Sjkoshy 149185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 150185363Sjkoshy{ 151185363Sjkoshy __PMC_EV_ALIAS_CORE() 152185363Sjkoshy}; 153185363Sjkoshy 154185363Sjkoshy 155185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 156185363Sjkoshy{ 157185363Sjkoshy __PMC_EV_ALIAS_CORE2() 158185363Sjkoshy}; 159185363Sjkoshy 160187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 161187761Sjeff{ 162187761Sjeff __PMC_EV_ALIAS_COREI7() 163187761Sjeff}; 164187761Sjeff 165185363Sjkoshy/* 166185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 167185363Sjkoshy * 168185363Sjkoshy * Map a CPU to the PMC classes it supports. 169185363Sjkoshy */ 170185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 171183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 172183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 173183725Sjkoshy } 174183725Sjkoshy 175185363SjkoshyPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); 176185363SjkoshyPMC_MDEP_TABLE(core, IAP, PMC_CLASS_TSC); 177185363SjkoshyPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); 178187761SjeffPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); 179183725SjkoshyPMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC); 180183725SjkoshyPMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC); 181183725SjkoshyPMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC); 182183725SjkoshyPMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC); 183183725SjkoshyPMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC); 184200928SrpauloPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_XSCALE); 185183725Sjkoshy 186183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 187145256Sjkoshy{ 188183725Sjkoshy __PMC_EV_TSC() 189145256Sjkoshy}; 190145256Sjkoshy 191183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 192185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 193185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 194185363Sjkoshy { \ 195185363Sjkoshy .pm_evc_name = #CLASS "-", \ 196185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 197185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 198185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 199183725Sjkoshy .pm_evc_event_table_size = \ 200185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 201185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 202183725Sjkoshy } 203183725Sjkoshy 204185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 205185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 206185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 207185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 208185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 209187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 210185363Sjkoshy#endif 211183725Sjkoshy#if defined(__i386__) 212185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 213183725Sjkoshy#endif 214183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 215185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 216185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 217183725Sjkoshy#endif 218183725Sjkoshy#if defined(__i386__) 219185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 220185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 221183725Sjkoshy#endif 222183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 223185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 224183725Sjkoshy#endif 225200928Srpaulo#if defined(__XSCALE__) 226200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 227200928Srpaulo#endif 228183725Sjkoshy 229183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 230183725Sjkoshy 231185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 232185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 233185363Sjkoshy 234183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 235183725Sjkoshystatic size_t pmc_mdep_class_list_size; 236183725Sjkoshy 237145256Sjkoshy/* 238145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 239145256Sjkoshy * strings. 240145256Sjkoshy */ 241145256Sjkoshy 242145256Sjkoshystatic const char * pmc_capability_names[] = { 243145256Sjkoshy#undef __PMC_CAP 244145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 245145256Sjkoshy __PMC_CAPS() 246145256Sjkoshy}; 247145256Sjkoshy 248145256Sjkoshystatic const char * pmc_class_names[] = { 249145256Sjkoshy#undef __PMC_CLASS 250145256Sjkoshy#define __PMC_CLASS(C) #C , 251145256Sjkoshy __PMC_CLASSES() 252145256Sjkoshy}; 253145256Sjkoshy 254183725Sjkoshystruct pmc_cputype_map { 255183725Sjkoshy enum pmc_class pm_cputype; 256183725Sjkoshy const char *pm_name; 257183725Sjkoshy}; 258183725Sjkoshy 259183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 260145256Sjkoshy#undef __PMC_CPU 261183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 262145256Sjkoshy __PMC_CPUS() 263145256Sjkoshy}; 264145256Sjkoshy 265145256Sjkoshystatic const char * pmc_disposition_names[] = { 266145256Sjkoshy#undef __PMC_DISP 267145256Sjkoshy#define __PMC_DISP(D) #D , 268145256Sjkoshy __PMC_DISPOSITIONS() 269145256Sjkoshy}; 270145256Sjkoshy 271145256Sjkoshystatic const char * pmc_mode_names[] = { 272145256Sjkoshy#undef __PMC_MODE 273145256Sjkoshy#define __PMC_MODE(M,N) #M , 274145256Sjkoshy __PMC_MODES() 275145256Sjkoshy}; 276145256Sjkoshy 277145256Sjkoshystatic const char * pmc_state_names[] = { 278145256Sjkoshy#undef __PMC_STATE 279145256Sjkoshy#define __PMC_STATE(S) #S , 280145256Sjkoshy __PMC_STATES() 281145256Sjkoshy}; 282145256Sjkoshy 283145256Sjkoshystatic int pmc_syscall = -1; /* filled in by pmc_init() */ 284145256Sjkoshy 285147219Sjkoshystatic struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */ 286145256Sjkoshy 287145256Sjkoshy/* Event masks for events */ 288145256Sjkoshystruct pmc_masks { 289145256Sjkoshy const char *pm_name; 290145256Sjkoshy const uint32_t pm_value; 291145256Sjkoshy}; 292145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 293145256Sjkoshy#define NULLMASK PMCMASK(NULL,0) 294145256Sjkoshy 295147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 296145256Sjkoshystatic int 297145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 298145256Sjkoshy{ 299145256Sjkoshy const struct pmc_masks *pm; 300145256Sjkoshy char *q, *r; 301145256Sjkoshy int c; 302145256Sjkoshy 303145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 304174406Sjkoshy return (-1); 305183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 306145256Sjkoshy if (*++q == '\0') /* no more data */ 307174406Sjkoshy return (-1); 308145256Sjkoshy c = 0; /* count of mask keywords seen */ 309145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 310183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 311183725Sjkoshy pm++) 312145256Sjkoshy ; 313145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 314174406Sjkoshy return (-1); 315145256Sjkoshy *evmask |= pm->pm_value; 316145256Sjkoshy c++; 317145256Sjkoshy } 318174406Sjkoshy return (c); 319145256Sjkoshy} 320145340Smarcel#endif 321145256Sjkoshy 322145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 323145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 324145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 325145256Sjkoshy 326145340Smarcel#if defined(__i386__) 327145256Sjkoshy 328145256Sjkoshy/* 329145256Sjkoshy * AMD K7 (Athlon) CPUs. 330145256Sjkoshy */ 331145256Sjkoshy 332145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 333145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 334145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 335145351Sjkoshy EV_ALIAS("cycles", "tsc"), 336183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 337145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 338145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 339145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 340145351Sjkoshy EV_ALIAS(NULL, NULL) 341145256Sjkoshy}; 342145256Sjkoshy 343145256Sjkoshy#define K7_KW_COUNT "count" 344145256Sjkoshy#define K7_KW_EDGE "edge" 345145256Sjkoshy#define K7_KW_INV "inv" 346145256Sjkoshy#define K7_KW_OS "os" 347145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 348145256Sjkoshy#define K7_KW_USR "usr" 349145256Sjkoshy 350145256Sjkoshystatic int 351145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 352145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 353145256Sjkoshy{ 354183107Sjkoshy char *e, *p, *q; 355183107Sjkoshy int c, has_unitmask; 356145256Sjkoshy uint32_t count, unitmask; 357145256Sjkoshy 358147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 359183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 360145256Sjkoshy 361145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 362145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 363145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 364145256Sjkoshy has_unitmask = 1; 365147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 366145256Sjkoshy } else 367145256Sjkoshy unitmask = has_unitmask = 0; 368145256Sjkoshy 369145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 370145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 371145256Sjkoshy q = strchr(p, '='); 372145256Sjkoshy if (*++q == '\0') /* skip '=' */ 373174406Sjkoshy return (-1); 374145256Sjkoshy 375145256Sjkoshy count = strtol(q, &e, 0); 376145256Sjkoshy if (e == q || *e != '\0') 377174406Sjkoshy return (-1); 378145256Sjkoshy 379145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 380147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 381147191Sjkoshy AMD_PMC_TO_COUNTER(count); 382145256Sjkoshy 383145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 384145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 385145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 386145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 387145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 388145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 389145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 390145256Sjkoshy if (has_unitmask == 0) 391174406Sjkoshy return (-1); 392145256Sjkoshy unitmask = 0; 393145256Sjkoshy q = strchr(p, '='); 394145256Sjkoshy if (*++q == '\0') /* skip '=' */ 395174406Sjkoshy return (-1); 396145256Sjkoshy 397145256Sjkoshy while ((c = tolower(*q++)) != 0) 398145256Sjkoshy if (c == 'm') 399147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 400145256Sjkoshy else if (c == 'o') 401147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 402145256Sjkoshy else if (c == 'e') 403147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 404145256Sjkoshy else if (c == 's') 405147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 406145256Sjkoshy else if (c == 'i') 407147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 408145256Sjkoshy else if (c == '+') 409145256Sjkoshy continue; 410145256Sjkoshy else 411174406Sjkoshy return (-1); 412145256Sjkoshy 413145256Sjkoshy if (unitmask == 0) 414174406Sjkoshy return (-1); 415145256Sjkoshy 416145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 417145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 418145256Sjkoshy } else 419174406Sjkoshy return (-1); 420145256Sjkoshy } 421145256Sjkoshy 422145256Sjkoshy if (has_unitmask) { 423145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 424147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 425147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 426145256Sjkoshy } 427145256Sjkoshy 428174406Sjkoshy return (0); 429145256Sjkoshy 430145256Sjkoshy} 431145256Sjkoshy 432147191Sjkoshy#endif 433147191Sjkoshy 434147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 435147191Sjkoshy 436145256Sjkoshy/* 437185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 438185363Sjkoshy */ 439185363Sjkoshy 440185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 441185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 442185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 443185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 444185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 445185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 446185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 447185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 448185363Sjkoshy EV_ALIAS(NULL, NULL) 449185363Sjkoshy}; 450185363Sjkoshy 451185363Sjkoshy/* 452185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 453185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 454198433Sjkoshy * 455198433Sjkoshy * We map aliases to events on the fixed-function counters if these 456198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 457198433Sjkoshy * counters. 458185363Sjkoshy */ 459185363Sjkoshy 460185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 461185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 462185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 463185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 464185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 465185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 466185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 467185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 468185363Sjkoshy EV_ALIAS(NULL, NULL) 469185363Sjkoshy}; 470185363Sjkoshy 471198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 472198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 473198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 474198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 475198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 476198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 477198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 478198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 479198433Sjkoshy EV_ALIAS(NULL, NULL) 480198433Sjkoshy}; 481198433Sjkoshy 482198433Sjkoshy#define atom_aliases core2_aliases 483198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 484198433Sjkoshy#define corei7_aliases core2_aliases 485198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 486198433Sjkoshy 487185363Sjkoshy#define IAF_KW_OS "os" 488185363Sjkoshy#define IAF_KW_USR "usr" 489185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 490185363Sjkoshy 491185363Sjkoshy/* 492185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 493185363Sjkoshy */ 494185363Sjkoshystatic int 495185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 496185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 497185363Sjkoshy{ 498185363Sjkoshy char *p; 499185363Sjkoshy 500185363Sjkoshy (void) pe; 501185363Sjkoshy 502185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 503185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 504185363Sjkoshy 505185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 506185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 507185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 508185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 509185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 510185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 511185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 512185363Sjkoshy else 513185363Sjkoshy return (-1); 514185363Sjkoshy } 515185363Sjkoshy 516185363Sjkoshy return (0); 517185363Sjkoshy} 518185363Sjkoshy 519185363Sjkoshy/* 520185363Sjkoshy * Core/Core2 support. 521185363Sjkoshy */ 522185363Sjkoshy 523185363Sjkoshy#define IAP_KW_AGENT "agent" 524185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 525185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 526185363Sjkoshy#define IAP_KW_CMASK "cmask" 527185363Sjkoshy#define IAP_KW_CORE "core" 528185363Sjkoshy#define IAP_KW_EDGE "edge" 529185363Sjkoshy#define IAP_KW_INV "inv" 530185363Sjkoshy#define IAP_KW_OS "os" 531185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 532185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 533185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 534185363Sjkoshy#define IAP_KW_TRANSITION "trans" 535185363Sjkoshy#define IAP_KW_USR "usr" 536185363Sjkoshy 537185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 538185363Sjkoshy PMCMASK(all, (0x3 << 14)), 539185363Sjkoshy PMCMASK(this, (0x1 << 14)), 540185363Sjkoshy NULLMASK 541185363Sjkoshy}; 542185363Sjkoshy 543185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 544185363Sjkoshy PMCMASK(this, 0), 545185363Sjkoshy PMCMASK(any, (0x1 << 13)), 546185363Sjkoshy NULLMASK 547185363Sjkoshy}; 548185363Sjkoshy 549185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 550185363Sjkoshy PMCMASK(both, (0x3 << 12)), 551185363Sjkoshy PMCMASK(only, (0x1 << 12)), 552185363Sjkoshy PMCMASK(exclude, 0), 553185363Sjkoshy NULLMASK 554185363Sjkoshy}; 555185363Sjkoshy 556185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 557185363Sjkoshy PMCMASK(i, (1 << 8)), 558185363Sjkoshy PMCMASK(s, (1 << 9)), 559185363Sjkoshy PMCMASK(e, (1 << 10)), 560185363Sjkoshy PMCMASK(m, (1 << 11)), 561185363Sjkoshy NULLMASK 562185363Sjkoshy}; 563185363Sjkoshy 564185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 565185363Sjkoshy PMCMASK(clean, (1 << 8)), 566185363Sjkoshy PMCMASK(hit, (1 << 9)), 567185363Sjkoshy PMCMASK(hitm, (1 << 11)), 568185363Sjkoshy NULLMASK 569185363Sjkoshy}; 570185363Sjkoshy 571185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 572185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 573185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 574185363Sjkoshy NULLMASK 575185363Sjkoshy}; 576185363Sjkoshy 577185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 578185363Sjkoshy PMCMASK(any, 0x00), 579185363Sjkoshy PMCMASK(frequency, 0x10), 580185363Sjkoshy NULLMASK 581185363Sjkoshy}; 582185363Sjkoshy 583185363Sjkoshystatic int 584185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 585185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 586185363Sjkoshy{ 587185363Sjkoshy char *e, *p, *q; 588185363Sjkoshy uint32_t cachestate, evmask; 589185363Sjkoshy int count, n; 590185363Sjkoshy 591185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 592185363Sjkoshy PMC_CAP_QUALIFIER); 593185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 594185363Sjkoshy 595185363Sjkoshy cachestate = evmask = 0; 596185363Sjkoshy 597185363Sjkoshy /* Parse additional modifiers if present */ 598185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 599185363Sjkoshy 600185363Sjkoshy n = 0; 601185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 602185363Sjkoshy q = strchr(p, '='); 603185363Sjkoshy if (*++q == '\0') /* skip '=' */ 604185363Sjkoshy return (-1); 605185363Sjkoshy count = strtol(q, &e, 0); 606185363Sjkoshy if (e == q || *e != '\0') 607185363Sjkoshy return (-1); 608185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 609185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 610185363Sjkoshy IAP_CMASK(count); 611185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 612185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 613185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 614185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 615185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 616185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 617185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 618185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 619185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 620185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 621193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 622185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 623185363Sjkoshy if (n != 1) 624185363Sjkoshy return (-1); 625193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 626185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 627185363Sjkoshy if (n != 1) 628185363Sjkoshy return (-1); 629193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 630185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 631185363Sjkoshy if (n != 1) 632185363Sjkoshy return (-1); 633193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 634185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 635185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 636193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 637185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 638185363Sjkoshy if (n != 1) 639185363Sjkoshy return (-1); 640185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 641185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 642187761Sjeff cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME || 643187761Sjeff cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7) { 644193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 645185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 646185363Sjkoshy &evmask); 647193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 648185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 649185363Sjkoshy &evmask); 650185363Sjkoshy } else 651185363Sjkoshy return (-1); 652185363Sjkoshy } else 653185363Sjkoshy return (-1); 654185363Sjkoshy 655185363Sjkoshy if (n < 0) /* Parsing failed. */ 656185363Sjkoshy return (-1); 657185363Sjkoshy } 658185363Sjkoshy 659185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 660185363Sjkoshy 661185363Sjkoshy /* 662185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 663185363Sjkoshy * specified by the user, use a sensible default. 664185363Sjkoshy */ 665185363Sjkoshy switch (pe) { 666185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 667185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 668185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 669185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 670185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 671185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 672185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 673185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 674185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 675185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 676185363Sjkoshy case PMC_EV_IAP_EVENT_77H: /* Core */ 677185363Sjkoshy if (cachestate == 0) 678185363Sjkoshy cachestate = (0xF << 8); 679185363Sjkoshy default: 680185363Sjkoshy break; 681185363Sjkoshy } 682185363Sjkoshy 683185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 684185363Sjkoshy 685185363Sjkoshy return (0); 686185363Sjkoshy} 687185363Sjkoshy 688185363Sjkoshy/* 689147191Sjkoshy * AMD K8 PMCs. 690147191Sjkoshy * 691147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 692147191Sjkoshy * events. 693147191Sjkoshy */ 694147191Sjkoshy 695147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 696147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 697147191Sjkoshy EV_ALIAS("branch-mispredicts", 698147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 699147191Sjkoshy EV_ALIAS("cycles", "tsc"), 700147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 701147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 702183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 703147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 704155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 705147191Sjkoshy EV_ALIAS(NULL, NULL) 706147191Sjkoshy}; 707147191Sjkoshy 708147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 709147191Sjkoshy 710147191Sjkoshy/* 711147191Sjkoshy * Parsing tables 712147191Sjkoshy */ 713147191Sjkoshy 714147191Sjkoshy/* fp dispatched fpu ops */ 715147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 716147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 717147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 718147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 719147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 720147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 721147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 722147191Sjkoshy NULLMASK 723147191Sjkoshy}; 724147191Sjkoshy 725147191Sjkoshy/* ls segment register loads */ 726147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 727147191Sjkoshy __K8MASK(es, 0), 728147191Sjkoshy __K8MASK(cs, 1), 729147191Sjkoshy __K8MASK(ss, 2), 730147191Sjkoshy __K8MASK(ds, 3), 731147191Sjkoshy __K8MASK(fs, 4), 732147191Sjkoshy __K8MASK(gs, 5), 733147191Sjkoshy __K8MASK(hs, 6), 734147191Sjkoshy NULLMASK 735147191Sjkoshy}; 736147191Sjkoshy 737147191Sjkoshy/* ls locked operation */ 738147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 739147191Sjkoshy __K8MASK(locked-instructions, 0), 740147191Sjkoshy __K8MASK(cycles-in-request, 1), 741147191Sjkoshy __K8MASK(cycles-to-complete, 2), 742147191Sjkoshy NULLMASK 743147191Sjkoshy}; 744147191Sjkoshy 745147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 746147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 747147191Sjkoshy __K8MASK(invalid, 0), 748147191Sjkoshy __K8MASK(shared, 1), 749147191Sjkoshy __K8MASK(exclusive, 2), 750147191Sjkoshy __K8MASK(owner, 3), 751147191Sjkoshy __K8MASK(modified, 4), 752147191Sjkoshy NULLMASK 753147191Sjkoshy}; 754147191Sjkoshy 755147191Sjkoshy/* dc one bit ecc error */ 756147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 757147191Sjkoshy __K8MASK(scrubber, 0), 758147191Sjkoshy __K8MASK(piggyback, 1), 759147191Sjkoshy NULLMASK 760147191Sjkoshy}; 761147191Sjkoshy 762147191Sjkoshy/* dc dispatched prefetch instructions */ 763147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 764147191Sjkoshy __K8MASK(load, 0), 765147191Sjkoshy __K8MASK(store, 1), 766147191Sjkoshy __K8MASK(nta, 2), 767147191Sjkoshy NULLMASK 768147191Sjkoshy}; 769147191Sjkoshy 770147191Sjkoshy/* dc dcache accesses by locks */ 771147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 772147191Sjkoshy __K8MASK(accesses, 0), 773147191Sjkoshy __K8MASK(misses, 1), 774147191Sjkoshy NULLMASK 775147191Sjkoshy}; 776147191Sjkoshy 777147191Sjkoshy/* bu internal l2 request */ 778147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 779147191Sjkoshy __K8MASK(ic-fill, 0), 780147191Sjkoshy __K8MASK(dc-fill, 1), 781147191Sjkoshy __K8MASK(tlb-reload, 2), 782147191Sjkoshy __K8MASK(tag-snoop, 3), 783147191Sjkoshy __K8MASK(cancelled, 4), 784147191Sjkoshy NULLMASK 785147191Sjkoshy}; 786147191Sjkoshy 787147191Sjkoshy/* bu fill request l2 miss */ 788147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 789147191Sjkoshy __K8MASK(ic-fill, 0), 790147191Sjkoshy __K8MASK(dc-fill, 1), 791147191Sjkoshy __K8MASK(tlb-reload, 2), 792147191Sjkoshy NULLMASK 793147191Sjkoshy}; 794147191Sjkoshy 795147191Sjkoshy/* bu fill into l2 */ 796147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 797147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 798147191Sjkoshy __K8MASK(victim-from-l2, 1), 799147191Sjkoshy NULLMASK 800147191Sjkoshy}; 801147191Sjkoshy 802147191Sjkoshy/* fr retired fpu instructions */ 803147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 804147191Sjkoshy __K8MASK(x87, 0), 805147191Sjkoshy __K8MASK(mmx-3dnow, 1), 806147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 807147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 808147191Sjkoshy NULLMASK 809147191Sjkoshy}; 810147191Sjkoshy 811147191Sjkoshy/* fr retired fastpath double op instructions */ 812147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 813147191Sjkoshy __K8MASK(low-op-pos-0, 0), 814147191Sjkoshy __K8MASK(low-op-pos-1, 1), 815147191Sjkoshy __K8MASK(low-op-pos-2, 2), 816147191Sjkoshy NULLMASK 817147191Sjkoshy}; 818147191Sjkoshy 819147191Sjkoshy/* fr fpu exceptions */ 820147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 821147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 822147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 823147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 824147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 825147191Sjkoshy NULLMASK 826147191Sjkoshy}; 827147191Sjkoshy 828147191Sjkoshy/* nb memory controller page access event */ 829147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 830147191Sjkoshy __K8MASK(page-hit, 0), 831147191Sjkoshy __K8MASK(page-miss, 1), 832147191Sjkoshy __K8MASK(page-conflict, 2), 833147191Sjkoshy NULLMASK 834147191Sjkoshy}; 835147191Sjkoshy 836147191Sjkoshy/* nb memory controller turnaround */ 837147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 838147191Sjkoshy __K8MASK(dimm-turnaround, 0), 839147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 840147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 841147191Sjkoshy NULLMASK 842147191Sjkoshy}; 843147191Sjkoshy 844147191Sjkoshy/* nb memory controller bypass saturation */ 845147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 846147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 847147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 848147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 849147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 850147191Sjkoshy NULLMASK 851147191Sjkoshy}; 852147191Sjkoshy 853147191Sjkoshy/* nb sized commands */ 854147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 855147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 856147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 857147191Sjkoshy __K8MASK(postwrszbyte, 2), 858147191Sjkoshy __K8MASK(postwrszdword, 3), 859147191Sjkoshy __K8MASK(rdszbyte, 4), 860147191Sjkoshy __K8MASK(rdszdword, 5), 861147191Sjkoshy __K8MASK(rdmodwr, 6), 862147191Sjkoshy NULLMASK 863147191Sjkoshy}; 864147191Sjkoshy 865147191Sjkoshy/* nb probe result */ 866147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 867147191Sjkoshy __K8MASK(probe-miss, 0), 868147191Sjkoshy __K8MASK(probe-hit, 1), 869147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 870147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 871147191Sjkoshy NULLMASK 872147191Sjkoshy}; 873147191Sjkoshy 874147191Sjkoshy/* nb hypertransport bus bandwidth */ 875147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 876147191Sjkoshy __K8MASK(command, 0), 877183107Sjkoshy __K8MASK(data, 1), 878147191Sjkoshy __K8MASK(buffer-release, 2), 879147191Sjkoshy __K8MASK(nop, 3), 880147191Sjkoshy NULLMASK 881147191Sjkoshy}; 882147191Sjkoshy 883147191Sjkoshy#undef __K8MASK 884147191Sjkoshy 885147191Sjkoshy#define K8_KW_COUNT "count" 886147191Sjkoshy#define K8_KW_EDGE "edge" 887147191Sjkoshy#define K8_KW_INV "inv" 888147191Sjkoshy#define K8_KW_MASK "mask" 889147191Sjkoshy#define K8_KW_OS "os" 890147191Sjkoshy#define K8_KW_USR "usr" 891147191Sjkoshy 892147191Sjkoshystatic int 893147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 894147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 895147191Sjkoshy{ 896183107Sjkoshy char *e, *p, *q; 897183107Sjkoshy int n; 898147191Sjkoshy uint32_t count, evmask; 899147191Sjkoshy const struct pmc_masks *pm, *pmask; 900147191Sjkoshy 901183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 902147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 903147191Sjkoshy 904147191Sjkoshy pmask = NULL; 905147191Sjkoshy evmask = 0; 906147191Sjkoshy 907147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 908147191Sjkoshy 909147191Sjkoshy /* setup parsing tables */ 910147191Sjkoshy switch (pe) { 911147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 912147191Sjkoshy __K8SETMASK(fdfo); 913147191Sjkoshy break; 914147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 915147191Sjkoshy __K8SETMASK(lsrl); 916147191Sjkoshy break; 917147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 918147191Sjkoshy __K8SETMASK(llo); 919147191Sjkoshy break; 920147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 921147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 922147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 923147191Sjkoshy __K8SETMASK(dc); 924147191Sjkoshy break; 925147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 926147191Sjkoshy __K8SETMASK(dobee); 927147191Sjkoshy break; 928147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 929147191Sjkoshy __K8SETMASK(ddpi); 930147191Sjkoshy break; 931147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 932147191Sjkoshy __K8SETMASK(dabl); 933147191Sjkoshy break; 934147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 935147191Sjkoshy __K8SETMASK(bilr); 936147191Sjkoshy break; 937147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 938147191Sjkoshy __K8SETMASK(bfrlm); 939147191Sjkoshy break; 940147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 941147191Sjkoshy __K8SETMASK(bfil); 942147191Sjkoshy break; 943147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 944147191Sjkoshy __K8SETMASK(frfi); 945147191Sjkoshy break; 946147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 947147191Sjkoshy __K8SETMASK(frfdoi); 948147191Sjkoshy break; 949147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 950147191Sjkoshy __K8SETMASK(ffe); 951147191Sjkoshy break; 952147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 953147191Sjkoshy __K8SETMASK(nmcpae); 954147191Sjkoshy break; 955147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 956147191Sjkoshy __K8SETMASK(nmct); 957147191Sjkoshy break; 958147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 959147191Sjkoshy __K8SETMASK(nmcbs); 960147191Sjkoshy break; 961147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 962147191Sjkoshy __K8SETMASK(nsc); 963147191Sjkoshy break; 964147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 965147191Sjkoshy __K8SETMASK(npr); 966147191Sjkoshy break; 967147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 968147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 969147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 970147191Sjkoshy __K8SETMASK(nhbb); 971147191Sjkoshy break; 972147191Sjkoshy 973147191Sjkoshy default: 974147191Sjkoshy break; /* no options defined */ 975147191Sjkoshy } 976147191Sjkoshy 977147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 978147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 979147191Sjkoshy q = strchr(p, '='); 980147191Sjkoshy if (*++q == '\0') /* skip '=' */ 981174406Sjkoshy return (-1); 982147191Sjkoshy 983147191Sjkoshy count = strtol(q, &e, 0); 984147191Sjkoshy if (e == q || *e != '\0') 985174406Sjkoshy return (-1); 986147191Sjkoshy 987147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 988147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 989147191Sjkoshy AMD_PMC_TO_COUNTER(count); 990147191Sjkoshy 991147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 992147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 993147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 994147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 995147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 996147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 997174406Sjkoshy return (-1); 998147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 999147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1000147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1001147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1002147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1003147191Sjkoshy } else 1004174406Sjkoshy return (-1); 1005147191Sjkoshy } 1006147191Sjkoshy 1007147191Sjkoshy /* other post processing */ 1008147191Sjkoshy switch (pe) { 1009147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1010147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1011147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1012147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1013147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1014147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1015147191Sjkoshy /* XXX only available in rev B and later */ 1016147191Sjkoshy break; 1017147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1018147191Sjkoshy /* XXX only available in rev C and later */ 1019147191Sjkoshy break; 1020147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1021147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1022147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1023174406Sjkoshy return (-1); 1024147191Sjkoshy if (evmask == 0) { 1025147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1026147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1027147191Sjkoshy } 1028147191Sjkoshy break; 1029147191Sjkoshy default: 1030147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1031147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1032147191Sjkoshy evmask |= pm->pm_value; 1033147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1034147191Sjkoshy } 1035147191Sjkoshy } 1036147191Sjkoshy 1037147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1038147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1039147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1040147191Sjkoshy 1041174406Sjkoshy return (0); 1042147191Sjkoshy} 1043147191Sjkoshy 1044147191Sjkoshy#endif 1045147191Sjkoshy 1046147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1047147191Sjkoshy 1048147191Sjkoshy/* 1049145256Sjkoshy * Intel P4 PMCs 1050145256Sjkoshy */ 1051145256Sjkoshy 1052145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1053145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1054145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1055145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1056145351Sjkoshy EV_ALIAS("instructions", 1057145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1058155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1059145256Sjkoshy EV_ALIAS(NULL, NULL) 1060145256Sjkoshy}; 1061145256Sjkoshy 1062145256Sjkoshy#define P4_KW_ACTIVE "active" 1063145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1064145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1065145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1066145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1067145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1068145256Sjkoshy#define P4_KW_CASCADE "cascade" 1069145256Sjkoshy#define P4_KW_EDGE "edge" 1070145256Sjkoshy#define P4_KW_INV "complement" 1071145256Sjkoshy#define P4_KW_OS "os" 1072145256Sjkoshy#define P4_KW_MASK "mask" 1073145256Sjkoshy#define P4_KW_PRECISE "precise" 1074145256Sjkoshy#define P4_KW_TAG "tag" 1075145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1076145256Sjkoshy#define P4_KW_USR "usr" 1077145256Sjkoshy 1078145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1079145256Sjkoshy 1080145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1081145256Sjkoshy __P4MASK(dd, 0), 1082145256Sjkoshy __P4MASK(db, 1), 1083145256Sjkoshy __P4MASK(di, 2), 1084145256Sjkoshy __P4MASK(bd, 3), 1085145256Sjkoshy __P4MASK(bb, 4), 1086145256Sjkoshy __P4MASK(bi, 5), 1087145256Sjkoshy __P4MASK(id, 6), 1088145256Sjkoshy __P4MASK(ib, 7), 1089145256Sjkoshy NULLMASK 1090145256Sjkoshy}; 1091145256Sjkoshy 1092145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1093145256Sjkoshy __P4MASK(tcmiss, 0), 1094145256Sjkoshy NULLMASK, 1095145256Sjkoshy}; 1096145256Sjkoshy 1097145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1098145256Sjkoshy __P4MASK(hit, 0), 1099145256Sjkoshy __P4MASK(miss, 1), 1100145256Sjkoshy __P4MASK(hit-uc, 2), 1101145256Sjkoshy NULLMASK 1102145256Sjkoshy}; 1103145256Sjkoshy 1104145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1105145256Sjkoshy __P4MASK(st-rb-full, 2), 1106145256Sjkoshy __P4MASK(64k-conf, 3), 1107145256Sjkoshy NULLMASK 1108145256Sjkoshy}; 1109145256Sjkoshy 1110145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1111145256Sjkoshy __P4MASK(lsc, 0), 1112145256Sjkoshy __P4MASK(ssc, 1), 1113145256Sjkoshy NULLMASK 1114145256Sjkoshy}; 1115145256Sjkoshy 1116145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1117145256Sjkoshy __P4MASK(split-ld, 1), 1118145256Sjkoshy NULLMASK 1119145256Sjkoshy}; 1120145256Sjkoshy 1121145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1122145256Sjkoshy __P4MASK(split-st, 1), 1123145256Sjkoshy NULLMASK 1124145256Sjkoshy}; 1125145256Sjkoshy 1126145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1127145256Sjkoshy __P4MASK(no-sta, 1), 1128145256Sjkoshy __P4MASK(no-std, 3), 1129145256Sjkoshy __P4MASK(partial-data, 4), 1130145256Sjkoshy __P4MASK(unalgn-addr, 5), 1131145256Sjkoshy NULLMASK 1132145256Sjkoshy}; 1133145256Sjkoshy 1134145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1135145256Sjkoshy __P4MASK(dtmiss, 0), 1136145256Sjkoshy __P4MASK(itmiss, 1), 1137145256Sjkoshy NULLMASK 1138145256Sjkoshy}; 1139145256Sjkoshy 1140145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1141145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1142145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1143145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1144145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1145145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1146145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1147145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1148145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1149145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1150145256Sjkoshy NULLMASK 1151145256Sjkoshy}; 1152145256Sjkoshy 1153145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1154145256Sjkoshy __P4MASK(all-read, 5), 1155145256Sjkoshy __P4MASK(all-write, 6), 1156145256Sjkoshy __P4MASK(mem-uc, 7), 1157145256Sjkoshy __P4MASK(mem-wc, 8), 1158145256Sjkoshy __P4MASK(mem-wt, 9), 1159145256Sjkoshy __P4MASK(mem-wp, 10), 1160145256Sjkoshy __P4MASK(mem-wb, 11), 1161145256Sjkoshy __P4MASK(own, 13), 1162145256Sjkoshy __P4MASK(other, 14), 1163145256Sjkoshy __P4MASK(prefetch, 15), 1164145256Sjkoshy NULLMASK 1165145256Sjkoshy}; 1166145256Sjkoshy 1167145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1168145256Sjkoshy __P4MASK(all-read, 5), 1169145256Sjkoshy __P4MASK(all-write, 6), 1170145256Sjkoshy __P4MASK(mem-uc, 7), 1171145256Sjkoshy __P4MASK(mem-wc, 8), 1172145256Sjkoshy __P4MASK(mem-wt, 9), 1173145256Sjkoshy __P4MASK(mem-wp, 10), 1174145256Sjkoshy __P4MASK(mem-wb, 11), 1175145256Sjkoshy __P4MASK(own, 13), 1176145256Sjkoshy __P4MASK(other, 14), 1177145256Sjkoshy __P4MASK(prefetch, 15), 1178145256Sjkoshy NULLMASK 1179145256Sjkoshy}; 1180145256Sjkoshy 1181145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1182145256Sjkoshy __P4MASK(drdy-drv, 0), 1183145256Sjkoshy __P4MASK(drdy-own, 1), 1184145256Sjkoshy __P4MASK(drdy-other, 2), 1185145256Sjkoshy __P4MASK(dbsy-drv, 3), 1186145256Sjkoshy __P4MASK(dbsy-own, 4), 1187145256Sjkoshy __P4MASK(dbsy-other, 5), 1188145256Sjkoshy NULLMASK 1189145256Sjkoshy}; 1190145256Sjkoshy 1191145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1192145256Sjkoshy __P4MASK(req-type0, 0), 1193145256Sjkoshy __P4MASK(req-type1, 1), 1194145256Sjkoshy __P4MASK(req-len0, 2), 1195145256Sjkoshy __P4MASK(req-len1, 3), 1196145256Sjkoshy __P4MASK(req-io-type, 5), 1197145256Sjkoshy __P4MASK(req-lock-type, 6), 1198145256Sjkoshy __P4MASK(req-cache-type, 7), 1199145256Sjkoshy __P4MASK(req-split-type, 8), 1200145256Sjkoshy __P4MASK(req-dem-type, 9), 1201145256Sjkoshy __P4MASK(req-ord-type, 10), 1202145256Sjkoshy __P4MASK(mem-type0, 11), 1203145256Sjkoshy __P4MASK(mem-type1, 12), 1204145256Sjkoshy __P4MASK(mem-type2, 13), 1205145256Sjkoshy NULLMASK 1206145256Sjkoshy}; 1207145256Sjkoshy 1208145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1209145256Sjkoshy __P4MASK(all, 15), 1210145256Sjkoshy NULLMASK 1211145256Sjkoshy}; 1212145256Sjkoshy 1213145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1214145256Sjkoshy __P4MASK(all, 15), 1215145256Sjkoshy NULLMASK 1216145256Sjkoshy}; 1217145256Sjkoshy 1218145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1219145256Sjkoshy __P4MASK(all, 15), 1220145256Sjkoshy NULLMASK 1221145256Sjkoshy}; 1222145256Sjkoshy 1223145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1224145256Sjkoshy __P4MASK(all, 15), 1225145256Sjkoshy NULLMASK 1226145256Sjkoshy}; 1227145256Sjkoshy 1228145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1229145256Sjkoshy __P4MASK(all, 15), 1230145256Sjkoshy NULLMASK 1231145256Sjkoshy}; 1232145256Sjkoshy 1233145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1234145256Sjkoshy __P4MASK(all, 15), 1235145256Sjkoshy NULLMASK 1236145256Sjkoshy}; 1237145256Sjkoshy 1238145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1239145256Sjkoshy __P4MASK(all, 15), 1240145256Sjkoshy NULLMASK 1241145256Sjkoshy}; 1242145256Sjkoshy 1243145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1244145256Sjkoshy __P4MASK(all, 15), 1245145256Sjkoshy NULLMASK 1246145256Sjkoshy}; 1247145256Sjkoshy 1248145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1249145256Sjkoshy __P4MASK(allp0, 3), 1250145256Sjkoshy __P4MASK(allp2, 4), 1251145256Sjkoshy NULLMASK 1252145256Sjkoshy}; 1253145256Sjkoshy 1254145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1255145256Sjkoshy __P4MASK(running, 0), 1256145256Sjkoshy NULLMASK 1257145256Sjkoshy}; 1258145256Sjkoshy 1259145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1260145256Sjkoshy __P4MASK(cisc, 0), 1261145256Sjkoshy NULLMASK 1262145256Sjkoshy}; 1263145256Sjkoshy 1264145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1265145256Sjkoshy __P4MASK(from-tc-build, 0), 1266145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1267145256Sjkoshy __P4MASK(from-rom, 2), 1268145256Sjkoshy NULLMASK 1269145256Sjkoshy}; 1270145256Sjkoshy 1271145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1272145351Sjkoshy /* retired mispred branch type */ 1273145256Sjkoshy __P4MASK(conditional, 1), 1274145256Sjkoshy __P4MASK(call, 2), 1275145256Sjkoshy __P4MASK(return, 3), 1276145256Sjkoshy __P4MASK(indirect, 4), 1277145256Sjkoshy NULLMASK 1278145256Sjkoshy}; 1279145256Sjkoshy 1280145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1281145256Sjkoshy __P4MASK(conditional, 1), 1282145256Sjkoshy __P4MASK(call, 2), 1283145256Sjkoshy __P4MASK(retired, 3), 1284145256Sjkoshy __P4MASK(indirect, 4), 1285145256Sjkoshy NULLMASK 1286145256Sjkoshy}; 1287145256Sjkoshy 1288145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1289145256Sjkoshy __P4MASK(sbfull, 5), 1290145256Sjkoshy NULLMASK 1291145256Sjkoshy}; 1292145256Sjkoshy 1293145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1294145256Sjkoshy __P4MASK(wcb-evicts, 0), 1295145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1296145256Sjkoshy NULLMASK 1297145256Sjkoshy}; 1298145256Sjkoshy 1299145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1300145256Sjkoshy __P4MASK(nbogus, 0), 1301145256Sjkoshy __P4MASK(bogus, 1), 1302145256Sjkoshy NULLMASK 1303145256Sjkoshy}; 1304145256Sjkoshy 1305145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1306145256Sjkoshy __P4MASK(nbogus0, 0), 1307145256Sjkoshy __P4MASK(nbogus1, 1), 1308145256Sjkoshy __P4MASK(nbogus2, 2), 1309145256Sjkoshy __P4MASK(nbogus3, 3), 1310145256Sjkoshy __P4MASK(bogus0, 4), 1311145256Sjkoshy __P4MASK(bogus1, 5), 1312145256Sjkoshy __P4MASK(bogus2, 6), 1313145256Sjkoshy __P4MASK(bogus3, 7), 1314145256Sjkoshy NULLMASK 1315145256Sjkoshy}; 1316145256Sjkoshy 1317145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1318145256Sjkoshy __P4MASK(nbogus, 0), 1319145256Sjkoshy __P4MASK(bogus, 1), 1320145256Sjkoshy NULLMASK 1321145256Sjkoshy}; 1322145256Sjkoshy 1323145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1324145256Sjkoshy __P4MASK(nbogusntag, 0), 1325145256Sjkoshy __P4MASK(nbogustag, 1), 1326145256Sjkoshy __P4MASK(bogusntag, 2), 1327145256Sjkoshy __P4MASK(bogustag, 3), 1328145256Sjkoshy NULLMASK 1329145256Sjkoshy}; 1330145256Sjkoshy 1331145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1332145256Sjkoshy __P4MASK(nbogus, 0), 1333145256Sjkoshy __P4MASK(bogus, 1), 1334145256Sjkoshy NULLMASK 1335145256Sjkoshy}; 1336145256Sjkoshy 1337145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1338145256Sjkoshy __P4MASK(tagloads, 1), 1339145256Sjkoshy __P4MASK(tagstores, 2), 1340145256Sjkoshy NULLMASK 1341145256Sjkoshy}; 1342145256Sjkoshy 1343145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1344145256Sjkoshy __P4MASK(mmnp, 0), 1345145256Sjkoshy __P4MASK(mmnm, 1), 1346145256Sjkoshy __P4MASK(mmtp, 2), 1347145256Sjkoshy __P4MASK(mmtm, 3), 1348145256Sjkoshy NULLMASK 1349145256Sjkoshy}; 1350145256Sjkoshy 1351145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1352145256Sjkoshy __P4MASK(nbogus, 0), 1353145256Sjkoshy NULLMASK 1354145256Sjkoshy}; 1355145256Sjkoshy 1356145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1357145256Sjkoshy __P4MASK(fpsu, 0), 1358145256Sjkoshy __P4MASK(fpso, 1), 1359145256Sjkoshy __P4MASK(poao, 2), 1360145256Sjkoshy __P4MASK(poau, 3), 1361145256Sjkoshy __P4MASK(prea, 4), 1362145256Sjkoshy NULLMASK 1363145256Sjkoshy}; 1364145256Sjkoshy 1365145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1366145256Sjkoshy __P4MASK(clear, 0), 1367145256Sjkoshy __P4MASK(moclear, 2), 1368145256Sjkoshy __P4MASK(smclear, 3), 1369145256Sjkoshy NULLMASK 1370145256Sjkoshy}; 1371145256Sjkoshy 1372145256Sjkoshy/* P4 event parser */ 1373145256Sjkoshystatic int 1374145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1375145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1376145256Sjkoshy{ 1377145256Sjkoshy 1378145256Sjkoshy char *e, *p, *q; 1379145256Sjkoshy int count, has_tag, has_busreqtype, n; 1380145256Sjkoshy uint32_t evmask, cccractivemask; 1381145256Sjkoshy const struct pmc_masks *pm, *pmask; 1382145256Sjkoshy 1383183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1384147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1385147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1386145256Sjkoshy 1387145256Sjkoshy pmask = NULL; 1388145256Sjkoshy evmask = 0; 1389145256Sjkoshy cccractivemask = 0x3; 1390145256Sjkoshy has_tag = has_busreqtype = 0; 1391145256Sjkoshy 1392145256Sjkoshy#define __P4SETMASK(M) do { \ 1393183107Sjkoshy pmask = p4_mask_##M; \ 1394145256Sjkoshy} while (0) 1395145256Sjkoshy 1396145256Sjkoshy switch (pe) { 1397145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1398145256Sjkoshy __P4SETMASK(tcdm); 1399145256Sjkoshy break; 1400145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1401145256Sjkoshy __P4SETMASK(bfr); 1402145256Sjkoshy break; 1403145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1404145256Sjkoshy __P4SETMASK(ir); 1405145256Sjkoshy break; 1406145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1407145256Sjkoshy __P4SETMASK(memcan); 1408145256Sjkoshy break; 1409145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1410145256Sjkoshy __P4SETMASK(memcomp); 1411145256Sjkoshy break; 1412145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1413145256Sjkoshy __P4SETMASK(lpr); 1414145256Sjkoshy break; 1415145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1416145256Sjkoshy __P4SETMASK(spr); 1417145256Sjkoshy break; 1418145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1419145256Sjkoshy __P4SETMASK(mlr); 1420145256Sjkoshy break; 1421145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1422145256Sjkoshy __P4SETMASK(pwt); 1423145256Sjkoshy break; 1424145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1425145256Sjkoshy __P4SETMASK(bcr); 1426145256Sjkoshy break; 1427145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1428145256Sjkoshy __P4SETMASK(ia); 1429145256Sjkoshy has_busreqtype = 1; 1430145256Sjkoshy break; 1431145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1432145256Sjkoshy __P4SETMASK(iae); 1433145256Sjkoshy has_busreqtype = 1; 1434145256Sjkoshy break; 1435145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1436145256Sjkoshy __P4SETMASK(fda); 1437145256Sjkoshy break; 1438145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1439145256Sjkoshy __P4SETMASK(ba); 1440145256Sjkoshy break; 1441145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1442145256Sjkoshy __P4SETMASK(sia); 1443145256Sjkoshy break; 1444145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1445145256Sjkoshy __P4SETMASK(psu); 1446145256Sjkoshy break; 1447145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1448145256Sjkoshy __P4SETMASK(pdu); 1449145256Sjkoshy break; 1450145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1451145256Sjkoshy __P4SETMASK(ssu); 1452145256Sjkoshy break; 1453145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1454145256Sjkoshy __P4SETMASK(sdu); 1455145256Sjkoshy break; 1456145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1457145256Sjkoshy __P4SETMASK(64bmu); 1458145256Sjkoshy break; 1459145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1460145256Sjkoshy __P4SETMASK(128bmu); 1461145256Sjkoshy break; 1462145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1463145256Sjkoshy __P4SETMASK(xfu); 1464145256Sjkoshy break; 1465145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1466145256Sjkoshy __P4SETMASK(xsmu); 1467145256Sjkoshy break; 1468145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1469145256Sjkoshy __P4SETMASK(gpe); 1470145256Sjkoshy break; 1471145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1472145256Sjkoshy __P4SETMASK(tmx); 1473145256Sjkoshy break; 1474145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1475145256Sjkoshy __P4SETMASK(uqw); 1476145256Sjkoshy break; 1477145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1478145256Sjkoshy __P4SETMASK(rmbt); 1479145256Sjkoshy break; 1480145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1481145256Sjkoshy __P4SETMASK(rbt); 1482145256Sjkoshy break; 1483145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1484145256Sjkoshy __P4SETMASK(rs); 1485145256Sjkoshy break; 1486145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1487145256Sjkoshy __P4SETMASK(wb); 1488145256Sjkoshy break; 1489145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1490145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1491145256Sjkoshy case PMC_EV_P4_BNR: 1492145256Sjkoshy case PMC_EV_P4_SNOOP: 1493145256Sjkoshy case PMC_EV_P4_RESPONSE: 1494145256Sjkoshy break; 1495145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1496145256Sjkoshy __P4SETMASK(fee); 1497145256Sjkoshy break; 1498145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1499145256Sjkoshy __P4SETMASK(ee); 1500145256Sjkoshy break; 1501145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1502145256Sjkoshy __P4SETMASK(re); 1503145256Sjkoshy break; 1504145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1505145256Sjkoshy __P4SETMASK(insret); 1506145256Sjkoshy break; 1507145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1508145256Sjkoshy __P4SETMASK(ur); 1509145256Sjkoshy break; 1510145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1511145256Sjkoshy __P4SETMASK(ut); 1512145256Sjkoshy break; 1513145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1514145256Sjkoshy __P4SETMASK(br); 1515145256Sjkoshy break; 1516145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1517145256Sjkoshy __P4SETMASK(mbr); 1518145256Sjkoshy break; 1519145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1520145256Sjkoshy __P4SETMASK(xa); 1521145256Sjkoshy break; 1522145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1523145256Sjkoshy __P4SETMASK(machclr); 1524145256Sjkoshy break; 1525145256Sjkoshy default: 1526174406Sjkoshy return (-1); 1527145256Sjkoshy } 1528145256Sjkoshy 1529145256Sjkoshy /* process additional flags */ 1530145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1531145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1532145256Sjkoshy q = strchr(p, '='); 1533145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1534174406Sjkoshy return (-1); 1535145256Sjkoshy 1536183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1537145256Sjkoshy cccractivemask = 0x0; 1538183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1539145256Sjkoshy cccractivemask = 0x1; 1540183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1541145256Sjkoshy cccractivemask = 0x2; 1542183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1543145256Sjkoshy cccractivemask = 0x3; 1544145256Sjkoshy else 1545174406Sjkoshy return (-1); 1546145256Sjkoshy 1547145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1548145256Sjkoshy if (has_busreqtype == 0) 1549174406Sjkoshy return (-1); 1550145256Sjkoshy 1551145256Sjkoshy q = strchr(p, '='); 1552145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1553174406Sjkoshy return (-1); 1554145256Sjkoshy 1555145256Sjkoshy count = strtol(q, &e, 0); 1556145256Sjkoshy if (e == q || *e != '\0') 1557174406Sjkoshy return (-1); 1558145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1559145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1560145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1561145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1562145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1563145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1564145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1565145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1566145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1567174406Sjkoshy return (-1); 1568145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1569145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1570145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1571145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1572145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1573145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1574145256Sjkoshy if (has_tag == 0) 1575174406Sjkoshy return (-1); 1576145256Sjkoshy 1577145256Sjkoshy q = strchr(p, '='); 1578145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1579174406Sjkoshy return (-1); 1580145256Sjkoshy 1581145256Sjkoshy count = strtol(q, &e, 0); 1582145256Sjkoshy if (e == q || *e != '\0') 1583174406Sjkoshy return (-1); 1584145256Sjkoshy 1585145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1586147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1587145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1588145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1589145256Sjkoshy q = strchr(p, '='); 1590145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1591174406Sjkoshy return (-1); 1592145256Sjkoshy 1593145256Sjkoshy count = strtol(q, &e, 0); 1594145256Sjkoshy if (e == q || *e != '\0') 1595174406Sjkoshy return (-1); 1596145256Sjkoshy 1597145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1598147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1599147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1600147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1601147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1602145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1603145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1604145256Sjkoshy else 1605174406Sjkoshy return (-1); 1606145256Sjkoshy } 1607145256Sjkoshy 1608145256Sjkoshy /* other post processing */ 1609145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1610145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1611145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1612145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1613145256Sjkoshy 1614145256Sjkoshy /* fill in thread activity mask */ 1615147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1616145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1617145256Sjkoshy 1618145256Sjkoshy if (evmask) 1619145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1620145256Sjkoshy 1621145256Sjkoshy switch (pe) { 1622145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1623145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1624145256Sjkoshy (evmask & 0x18) == 0x18) 1625174406Sjkoshy return (-1); /* can't have own+other bits together */ 1626145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1627145256Sjkoshy evmask = 0x1D; 1628145256Sjkoshy break; 1629145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1630145256Sjkoshy /* only one bit is allowed to be set */ 1631145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1632174406Sjkoshy return (-1); 1633145256Sjkoshy if (evmask == 0) { 1634183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1635145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1636145256Sjkoshy } 1637145256Sjkoshy break; 1638145256Sjkoshy default: 1639145256Sjkoshy if (evmask == 0 && pmask) { 1640145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1641145256Sjkoshy evmask |= pm->pm_value; 1642145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1643145256Sjkoshy } 1644145256Sjkoshy } 1645145256Sjkoshy 1646147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1647147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1648145256Sjkoshy 1649174406Sjkoshy return (0); 1650145256Sjkoshy} 1651145256Sjkoshy 1652147759Sjkoshy#endif 1653147759Sjkoshy 1654147759Sjkoshy#if defined(__i386__) 1655147759Sjkoshy 1656145256Sjkoshy/* 1657147191Sjkoshy * Pentium style PMCs 1658147191Sjkoshy */ 1659147191Sjkoshy 1660147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1661183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1662183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1663183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1664183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1665183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1666183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1667183105Sjkoshy EV_ALIAS("unhalted-cycles", 1668183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1669147191Sjkoshy EV_ALIAS(NULL, NULL) 1670147191Sjkoshy}; 1671147191Sjkoshy 1672147191Sjkoshystatic int 1673147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1674147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1675147191Sjkoshy{ 1676174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1677147191Sjkoshy} 1678147191Sjkoshy 1679147191Sjkoshy/* 1680145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1681145256Sjkoshy * and Pentium M CPUs. 1682145256Sjkoshy */ 1683145256Sjkoshy 1684145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1685145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1686145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1687145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1688145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1689168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1690145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1691145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1692155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1693145351Sjkoshy EV_ALIAS(NULL, NULL) 1694145256Sjkoshy}; 1695145256Sjkoshy 1696145256Sjkoshy#define P6_KW_CMASK "cmask" 1697145256Sjkoshy#define P6_KW_EDGE "edge" 1698145256Sjkoshy#define P6_KW_INV "inv" 1699145256Sjkoshy#define P6_KW_OS "os" 1700145256Sjkoshy#define P6_KW_UMASK "umask" 1701145256Sjkoshy#define P6_KW_USR "usr" 1702145256Sjkoshy 1703145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1704145256Sjkoshy PMCMASK(m, 0x01), 1705145256Sjkoshy PMCMASK(e, 0x02), 1706145256Sjkoshy PMCMASK(s, 0x04), 1707145256Sjkoshy PMCMASK(i, 0x08), 1708145256Sjkoshy NULLMASK 1709145256Sjkoshy}; 1710145256Sjkoshy 1711145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1712145256Sjkoshy PMCMASK(m, 0x01), 1713145256Sjkoshy PMCMASK(e, 0x02), 1714145256Sjkoshy PMCMASK(s, 0x04), 1715145256Sjkoshy PMCMASK(i, 0x08), 1716145256Sjkoshy PMCMASK(nonhw, 0x00), 1717145256Sjkoshy PMCMASK(hw, 0x10), 1718145256Sjkoshy PMCMASK(both, 0x30), 1719145256Sjkoshy NULLMASK 1720145256Sjkoshy}; 1721145256Sjkoshy 1722145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1723145256Sjkoshy PMCMASK(nonhw, 0x00), 1724145256Sjkoshy PMCMASK(hw, 0x10), 1725145256Sjkoshy PMCMASK(both, 0x30), 1726145256Sjkoshy NULLMASK 1727145256Sjkoshy}; 1728145256Sjkoshy 1729145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1730145256Sjkoshy PMCMASK(self, 0x00), 1731145256Sjkoshy PMCMASK(any, 0x20), 1732145256Sjkoshy NULLMASK 1733145256Sjkoshy}; 1734145256Sjkoshy 1735145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1736145256Sjkoshy PMCMASK(nta, 0x00), 1737145256Sjkoshy PMCMASK(t1, 0x01), 1738145256Sjkoshy PMCMASK(t2, 0x02), 1739145256Sjkoshy PMCMASK(wos, 0x03), 1740145256Sjkoshy NULLMASK 1741145256Sjkoshy}; 1742145256Sjkoshy 1743145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1744145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1745145256Sjkoshy PMCMASK(scalar, 0x01), 1746145256Sjkoshy NULLMASK 1747145256Sjkoshy}; 1748145256Sjkoshy 1749145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1750145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1751145256Sjkoshy PMCMASK(packed-shift, 0x02), 1752145256Sjkoshy PMCMASK(pack, 0x04), 1753145256Sjkoshy PMCMASK(unpack, 0x08), 1754145256Sjkoshy PMCMASK(packed-logical, 0x10), 1755145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1756145256Sjkoshy NULLMASK 1757145256Sjkoshy}; 1758145256Sjkoshy 1759145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1760145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1761145256Sjkoshy PMCMASK(fptommx, 0x01), 1762145256Sjkoshy NULLMASK 1763145256Sjkoshy}; 1764145256Sjkoshy 1765145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 1766145256Sjkoshy PMCMASK(es, 0x01), 1767145256Sjkoshy PMCMASK(ds, 0x02), 1768145256Sjkoshy PMCMASK(fs, 0x04), 1769145256Sjkoshy PMCMASK(gs, 0x08), 1770145256Sjkoshy NULLMASK 1771145256Sjkoshy}; 1772145256Sjkoshy 1773145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 1774145256Sjkoshy PMCMASK(all, 0x00), 1775145256Sjkoshy PMCMASK(freq, 0x02), 1776145256Sjkoshy NULLMASK 1777145256Sjkoshy}; 1778145256Sjkoshy 1779145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1780145256Sjkoshy PMCMASK(all, 0x00), 1781145256Sjkoshy PMCMASK(loadop, 0x01), 1782145256Sjkoshy PMCMASK(stdsta, 0x02), 1783145256Sjkoshy NULLMASK 1784145256Sjkoshy}; 1785145256Sjkoshy 1786145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1787145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1788145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1789145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1790145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1791145256Sjkoshy NULLMASK 1792145256Sjkoshy}; 1793145256Sjkoshy 1794145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1795145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1796145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1797145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1798145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1799145256Sjkoshy NULLMASK 1800145256Sjkoshy}; 1801145256Sjkoshy 1802145256Sjkoshy/* P6 event parser */ 1803145256Sjkoshystatic int 1804145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1805145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1806145256Sjkoshy{ 1807145256Sjkoshy char *e, *p, *q; 1808145256Sjkoshy uint32_t evmask; 1809145256Sjkoshy int count, n; 1810145256Sjkoshy const struct pmc_masks *pm, *pmask; 1811145256Sjkoshy 1812183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1813147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 1814145256Sjkoshy 1815145256Sjkoshy evmask = 0; 1816145256Sjkoshy 1817145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1818145256Sjkoshy 1819145256Sjkoshy switch(pe) { 1820183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1821145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1822145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 1823145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 1824145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1825145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1826145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1827145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1828145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1829145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1830145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1831145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1832145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1833145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1834145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1835145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1836145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1837145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1838145256Sjkoshy P6MASKSET(any); break; 1839145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1840145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1841145256Sjkoshy P6MASKSET(ekp); break; 1842145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1843145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1844145256Sjkoshy P6MASKSET(pps); break; 1845145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 1846145256Sjkoshy P6MASKSET(mite); break; 1847145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1848145256Sjkoshy P6MASKSET(fmt); break; 1849145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 1850145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 1851145256Sjkoshy P6MASKSET(sr); break; 1852145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1853145256Sjkoshy P6MASKSET(eet); break; 1854145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1855145256Sjkoshy P6MASKSET(efur); break; 1856145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1857145256Sjkoshy P6MASKSET(essir); break; 1858145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1859145256Sjkoshy P6MASKSET(esscir); break; 1860145256Sjkoshy default: 1861145256Sjkoshy pmask = NULL; 1862145256Sjkoshy break; 1863145256Sjkoshy } 1864145256Sjkoshy 1865145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 1866145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 1867145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 1868145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 1869145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 1870145256Sjkoshy P6MASKSET(mesihw); 1871145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 1872145256Sjkoshy P6MASKSET(hw); 1873145256Sjkoshy } 1874145256Sjkoshy 1875145256Sjkoshy /* Parse additional modifiers if present */ 1876145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1877145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 1878145256Sjkoshy q = strchr(p, '='); 1879145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1880174406Sjkoshy return (-1); 1881145256Sjkoshy count = strtol(q, &e, 0); 1882145256Sjkoshy if (e == q || *e != '\0') 1883174406Sjkoshy return (-1); 1884145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1885147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1886147191Sjkoshy P6_EVSEL_TO_CMASK(count); 1887145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 1888145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1889145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 1890145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1891145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 1892145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1893145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 1894145256Sjkoshy evmask = 0; 1895145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1896174406Sjkoshy return (-1); 1897145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 1898145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 1899145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 1900145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 1901145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 1902145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 1903145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 1904145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 1905145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 1906145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 1907145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 1908145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 1909145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 1910145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 1911145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 1912145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 1913145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 1914145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 1915145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 1916145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 1917145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 1918145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 1919145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 1920174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 1921174406Sjkoshy return (-1); 1922145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1923145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 1924145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1925145256Sjkoshy } else 1926174406Sjkoshy return (-1); 1927145256Sjkoshy } 1928145256Sjkoshy 1929145256Sjkoshy /* post processing */ 1930145256Sjkoshy switch (pe) { 1931145256Sjkoshy 1932145256Sjkoshy /* 1933145256Sjkoshy * The following events default to an evmask of 0 1934145256Sjkoshy */ 1935145256Sjkoshy 1936145256Sjkoshy /* default => 'self' */ 1937145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1938145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1939145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1940145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1941145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1942145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1943145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1944145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1945145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1946145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1947145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1948145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1949145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1950145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1951145256Sjkoshy 1952145256Sjkoshy /* default => 'nta' */ 1953145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1954145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1955145256Sjkoshy 1956145256Sjkoshy /* default => 'packed and scalar' */ 1957145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1958145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1959145256Sjkoshy 1960145256Sjkoshy /* default => 'mmx to fp transitions' */ 1961145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1962145256Sjkoshy 1963145256Sjkoshy /* default => 'SSE Packed Single' */ 1964145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1965145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1966145256Sjkoshy 1967145256Sjkoshy /* default => 'all fused micro-ops' */ 1968145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1969145256Sjkoshy 1970145256Sjkoshy /* default => 'all transitions' */ 1971145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1972145256Sjkoshy break; 1973145256Sjkoshy 1974145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 1975145256Sjkoshy evmask = 0x0F; /* only value allowed */ 1976145256Sjkoshy break; 1977145256Sjkoshy 1978145256Sjkoshy default: 1979145256Sjkoshy /* 1980145256Sjkoshy * For all other events, set the default event mask 1981145256Sjkoshy * to a logical OR of all the allowed event mask bits. 1982145256Sjkoshy */ 1983145256Sjkoshy if (evmask == 0 && pmask) { 1984145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1985145256Sjkoshy evmask |= pm->pm_value; 1986145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1987145256Sjkoshy } 1988145256Sjkoshy 1989145256Sjkoshy break; 1990145256Sjkoshy } 1991145256Sjkoshy 1992145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1993147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1994147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 1995145256Sjkoshy 1996174406Sjkoshy return (0); 1997145256Sjkoshy} 1998145256Sjkoshy 1999147191Sjkoshy#endif 2000147191Sjkoshy 2001183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2002183725Sjkoshystatic int 2003183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2004183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2005183725Sjkoshy{ 2006183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2007183725Sjkoshy return (-1); 2008183725Sjkoshy 2009183725Sjkoshy /* TSC events must be unqualified. */ 2010183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2011183725Sjkoshy return (-1); 2012183725Sjkoshy 2013183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2014183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2015183725Sjkoshy 2016183725Sjkoshy return (0); 2017183725Sjkoshy} 2018183725Sjkoshy#endif 2019183725Sjkoshy 2020200928Srpaulo#if defined(__XSCALE__) 2021200928Srpaulo 2022200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2023200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2024200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2025200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2026200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2027200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2028200928Srpaulo EV_ALIAS(NULL, NULL) 2029200928Srpaulo}; 2030200928Srpaulostatic int 2031200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2032200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2033200928Srpaulo{ 2034200928Srpaulo switch (pe) { 2035200928Srpaulo default: 2036200928Srpaulo break; 2037200928Srpaulo } 2038200928Srpaulo 2039200928Srpaulo return (0); 2040200928Srpaulo} 2041200928Srpaulo#endif 2042200928Srpaulo 2043145256Sjkoshy/* 2044183725Sjkoshy * Match an event name `name' with its canonical form. 2045183725Sjkoshy * 2046185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2047185363Sjkoshy * hyphen characters are considered to match each other. 2048185363Sjkoshy * 2049183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2050183725Sjkoshy */ 2051183725Sjkoshy 2052183725Sjkoshystatic int 2053183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2054183725Sjkoshy{ 2055183725Sjkoshy int cc, nc; 2056183725Sjkoshy const unsigned char *c, *n; 2057183725Sjkoshy 2058183725Sjkoshy c = (const unsigned char *) canonicalname; 2059183725Sjkoshy n = (const unsigned char *) name; 2060183725Sjkoshy 2061183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2062183725Sjkoshy 2063185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2064185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2065183725Sjkoshy continue; 2066183725Sjkoshy 2067185363Sjkoshy if (toupper(nc) == toupper(cc)) 2068183725Sjkoshy continue; 2069183725Sjkoshy 2070185363Sjkoshy 2071183725Sjkoshy return (0); 2072183725Sjkoshy } 2073183725Sjkoshy 2074183725Sjkoshy if (*n == '\0' && *c == '\0') 2075183725Sjkoshy return (1); 2076183725Sjkoshy 2077183725Sjkoshy return (0); 2078183725Sjkoshy} 2079183725Sjkoshy 2080183725Sjkoshy/* 2081183725Sjkoshy * Match an event name against all the event named supported by a 2082183725Sjkoshy * PMC class. 2083183725Sjkoshy * 2084183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2085183725Sjkoshy */ 2086183725Sjkoshystatic const struct pmc_event_descr * 2087183725Sjkoshypmc_match_event_class(const char *name, 2088183725Sjkoshy const struct pmc_class_descr *pcd) 2089183725Sjkoshy{ 2090183725Sjkoshy size_t n; 2091183725Sjkoshy const struct pmc_event_descr *ev; 2092185363Sjkoshy 2093183725Sjkoshy ev = pcd->pm_evc_event_table; 2094183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2095183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2096183725Sjkoshy return (ev); 2097183725Sjkoshy 2098183725Sjkoshy return (NULL); 2099183725Sjkoshy} 2100183725Sjkoshy 2101183725Sjkoshystatic int 2102183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2103183725Sjkoshy{ 2104183725Sjkoshy size_t n; 2105183725Sjkoshy 2106183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2107183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2108183725Sjkoshy return (1); 2109183725Sjkoshy return (0); 2110183725Sjkoshy} 2111183725Sjkoshy 2112183725Sjkoshy/* 2113147191Sjkoshy * API entry points 2114145256Sjkoshy */ 2115145256Sjkoshy 2116147191Sjkoshyint 2117147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2118147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2119145256Sjkoshy{ 2120183725Sjkoshy size_t n; 2121147191Sjkoshy int retval; 2122147191Sjkoshy char *r, *spec_copy; 2123147191Sjkoshy const char *ctrname; 2124183725Sjkoshy const struct pmc_event_descr *ev; 2125183725Sjkoshy const struct pmc_event_alias *alias; 2126147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2127183725Sjkoshy const struct pmc_class_descr *pcd; 2128145256Sjkoshy 2129147191Sjkoshy spec_copy = NULL; 2130147191Sjkoshy retval = -1; 2131145256Sjkoshy 2132147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2133147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2134147191Sjkoshy errno = EINVAL; 2135147191Sjkoshy goto out; 2136147191Sjkoshy } 2137145256Sjkoshy 2138147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2139147191Sjkoshy if (pmc_mdep_event_aliases) 2140183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2141183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2142183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2143147191Sjkoshy break; 2144147191Sjkoshy } 2145145256Sjkoshy 2146147191Sjkoshy if (spec_copy == NULL) 2147147191Sjkoshy spec_copy = strdup(ctrspec); 2148145256Sjkoshy 2149147191Sjkoshy r = spec_copy; 2150147191Sjkoshy ctrname = strsep(&r, ","); 2151145256Sjkoshy 2152183725Sjkoshy /* 2153183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2154183725Sjkoshy * search for the event to the specified PMC class. 2155183725Sjkoshy */ 2156183725Sjkoshy ev = NULL; 2157185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2158185363Sjkoshy pcd = pmc_class_table[n]; 2159183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2160183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2161183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2162183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2163183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2164183725Sjkoshy errno = EINVAL; 2165183725Sjkoshy goto out; 2166183725Sjkoshy } 2167147191Sjkoshy break; 2168183725Sjkoshy } 2169183725Sjkoshy } 2170145256Sjkoshy 2171183725Sjkoshy /* 2172183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2173183725Sjkoshy * classes. 2174183725Sjkoshy */ 2175185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2176185363Sjkoshy pcd = pmc_class_table[n]; 2177183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2178183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2179183725Sjkoshy } 2180183725Sjkoshy 2181183725Sjkoshy if (ev == NULL) { 2182147191Sjkoshy errno = EINVAL; 2183147191Sjkoshy goto out; 2184147191Sjkoshy } 2185145256Sjkoshy 2186147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2187183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2188183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2189147191Sjkoshy pmc_config.pm_cpu = cpu; 2190147191Sjkoshy pmc_config.pm_mode = mode; 2191147191Sjkoshy pmc_config.pm_flags = flags; 2192145256Sjkoshy 2193147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2194147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2195145256Sjkoshy 2196183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2197147191Sjkoshy errno = EINVAL; 2198147191Sjkoshy goto out; 2199147191Sjkoshy } 2200145256Sjkoshy 2201147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2202147191Sjkoshy goto out; 2203145256Sjkoshy 2204147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2205145256Sjkoshy 2206147191Sjkoshy retval = 0; 2207145256Sjkoshy 2208147191Sjkoshy out: 2209147191Sjkoshy if (spec_copy) 2210147191Sjkoshy free(spec_copy); 2211145256Sjkoshy 2212174406Sjkoshy return (retval); 2213147191Sjkoshy} 2214145256Sjkoshy 2215147191Sjkoshyint 2216147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2217147191Sjkoshy{ 2218147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2219145256Sjkoshy 2220147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2221147191Sjkoshy pmc_attach_args.pm_pid = pid; 2222145256Sjkoshy 2223174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2224147191Sjkoshy} 2225145256Sjkoshy 2226147191Sjkoshyint 2227147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2228147191Sjkoshy{ 2229147191Sjkoshy unsigned int i; 2230147191Sjkoshy enum pmc_class cl; 2231145256Sjkoshy 2232147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2233147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2234147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2235147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2236174406Sjkoshy return (0); 2237147191Sjkoshy } 2238177107Sjkoshy errno = EINVAL; 2239177107Sjkoshy return (-1); 2240147191Sjkoshy} 2241145256Sjkoshy 2242147191Sjkoshyint 2243147191Sjkoshypmc_configure_logfile(int fd) 2244147191Sjkoshy{ 2245147191Sjkoshy struct pmc_op_configurelog cla; 2246145256Sjkoshy 2247147191Sjkoshy cla.pm_logfd = fd; 2248147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2249174406Sjkoshy return (-1); 2250174406Sjkoshy return (0); 2251147191Sjkoshy} 2252145256Sjkoshy 2253147191Sjkoshyint 2254147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2255147191Sjkoshy{ 2256147191Sjkoshy if (pmc_syscall == -1) { 2257147191Sjkoshy errno = ENXIO; 2258174406Sjkoshy return (-1); 2259147191Sjkoshy } 2260145256Sjkoshy 2261147219Sjkoshy *pci = &cpu_info; 2262174406Sjkoshy return (0); 2263147191Sjkoshy} 2264145256Sjkoshy 2265147191Sjkoshyint 2266147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2267147191Sjkoshy{ 2268147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2269145256Sjkoshy 2270147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2271147191Sjkoshy pmc_detach_args.pm_pid = pid; 2272174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2273147191Sjkoshy} 2274147191Sjkoshy 2275147191Sjkoshyint 2276147191Sjkoshypmc_disable(int cpu, int pmc) 2277145256Sjkoshy{ 2278147191Sjkoshy struct pmc_op_pmcadmin ssa; 2279145256Sjkoshy 2280147191Sjkoshy ssa.pm_cpu = cpu; 2281147191Sjkoshy ssa.pm_pmc = pmc; 2282147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2283174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2284147191Sjkoshy} 2285145256Sjkoshy 2286147191Sjkoshyint 2287147191Sjkoshypmc_enable(int cpu, int pmc) 2288147191Sjkoshy{ 2289147191Sjkoshy struct pmc_op_pmcadmin ssa; 2290145256Sjkoshy 2291147191Sjkoshy ssa.pm_cpu = cpu; 2292147191Sjkoshy ssa.pm_pmc = pmc; 2293147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2294174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2295147191Sjkoshy} 2296145256Sjkoshy 2297147191Sjkoshy/* 2298147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2299147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2300147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2301147191Sjkoshy * the number of event name pointers returned. 2302147191Sjkoshy * 2303147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2304147191Sjkoshy * is responsible for freeing this space when done. 2305147191Sjkoshy */ 2306147191Sjkoshyint 2307147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2308147191Sjkoshy int *nevents) 2309147191Sjkoshy{ 2310147191Sjkoshy int count; 2311147191Sjkoshy const char **names; 2312147191Sjkoshy const struct pmc_event_descr *ev; 2313147191Sjkoshy 2314147191Sjkoshy switch (cl) 2315147191Sjkoshy { 2316185363Sjkoshy case PMC_CLASS_IAF: 2317185363Sjkoshy ev = iaf_event_table; 2318185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2319185363Sjkoshy break; 2320185363Sjkoshy case PMC_CLASS_IAP: 2321185363Sjkoshy /* 2322185363Sjkoshy * Return the most appropriate set of event name 2323185363Sjkoshy * spellings for the current CPU. 2324185363Sjkoshy */ 2325185363Sjkoshy switch (cpu_info.pm_cputype) { 2326185363Sjkoshy default: 2327185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2328185363Sjkoshy ev = atom_event_table; 2329185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2330185363Sjkoshy break; 2331185363Sjkoshy case PMC_CPU_INTEL_CORE: 2332185363Sjkoshy ev = core_event_table; 2333185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2334185363Sjkoshy break; 2335185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2336185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2337185363Sjkoshy ev = core2_event_table; 2338185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2339185363Sjkoshy break; 2340187761Sjeff case PMC_CPU_INTEL_COREI7: 2341187761Sjeff ev = corei7_event_table; 2342187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2343187761Sjeff break; 2344185363Sjkoshy } 2345185363Sjkoshy break; 2346147191Sjkoshy case PMC_CLASS_TSC: 2347183725Sjkoshy ev = tsc_event_table; 2348183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2349145256Sjkoshy break; 2350147191Sjkoshy case PMC_CLASS_K7: 2351183725Sjkoshy ev = k7_event_table; 2352183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2353145256Sjkoshy break; 2354147191Sjkoshy case PMC_CLASS_K8: 2355183725Sjkoshy ev = k8_event_table; 2356183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2357145256Sjkoshy break; 2358183725Sjkoshy case PMC_CLASS_P4: 2359183725Sjkoshy ev = p4_event_table; 2360183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2361183725Sjkoshy break; 2362147191Sjkoshy case PMC_CLASS_P5: 2363183725Sjkoshy ev = p5_event_table; 2364183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2365145256Sjkoshy break; 2366147191Sjkoshy case PMC_CLASS_P6: 2367183725Sjkoshy ev = p6_event_table; 2368183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2369145256Sjkoshy break; 2370200928Srpaulo case PMC_CLASS_XSCALE: 2371200928Srpaulo ev = xscale_event_table; 2372200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2373200928Srpaulo break; 2374145256Sjkoshy default: 2375147191Sjkoshy errno = EINVAL; 2376174406Sjkoshy return (-1); 2377145256Sjkoshy } 2378145256Sjkoshy 2379147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2380174406Sjkoshy return (-1); 2381145256Sjkoshy 2382147191Sjkoshy *eventnames = names; 2383147191Sjkoshy *nevents = count; 2384145256Sjkoshy 2385147191Sjkoshy for (;count--; ev++, names++) 2386147191Sjkoshy *names = ev->pm_ev_name; 2387174406Sjkoshy return (0); 2388147191Sjkoshy} 2389145256Sjkoshy 2390147191Sjkoshyint 2391147191Sjkoshypmc_flush_logfile(void) 2392147191Sjkoshy{ 2393174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2394147191Sjkoshy} 2395145256Sjkoshy 2396147191Sjkoshyint 2397147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2398147191Sjkoshy{ 2399147191Sjkoshy struct pmc_op_getdriverstats gms; 2400145256Sjkoshy 2401147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2402174406Sjkoshy return (-1); 2403145256Sjkoshy 2404147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2405147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2406147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2407147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2408147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2409147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2410147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2411147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2412147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2413174406Sjkoshy return (0); 2414147191Sjkoshy} 2415145256Sjkoshy 2416147191Sjkoshyint 2417147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2418147191Sjkoshy{ 2419147191Sjkoshy struct pmc_op_getmsr gm; 2420147191Sjkoshy 2421147191Sjkoshy gm.pm_pmcid = pmc; 2422147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2423174406Sjkoshy return (-1); 2424147191Sjkoshy *msr = gm.pm_msr; 2425174406Sjkoshy return (0); 2426145256Sjkoshy} 2427145256Sjkoshy 2428145256Sjkoshyint 2429145256Sjkoshypmc_init(void) 2430145256Sjkoshy{ 2431145256Sjkoshy int error, pmc_mod_id; 2432147219Sjkoshy unsigned int n; 2433145256Sjkoshy uint32_t abi_version; 2434145256Sjkoshy struct module_stat pmc_modstat; 2435147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2436198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2437198433Sjkoshy int cpu_has_iaf_counters; 2438198433Sjkoshy unsigned int t; 2439198433Sjkoshy#endif 2440145256Sjkoshy 2441145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2442174406Sjkoshy return (0); 2443145256Sjkoshy 2444145256Sjkoshy /* retrieve the system call number from the KLD */ 2445145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2446174406Sjkoshy return (-1); 2447145256Sjkoshy 2448145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2449145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2450174406Sjkoshy return (-1); 2451145256Sjkoshy 2452145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2453145256Sjkoshy 2454147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2455147191Sjkoshy abi_version = PMC_VERSION; 2456145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2457145256Sjkoshy return (pmc_syscall = -1); 2458145256Sjkoshy 2459147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2460147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2461145256Sjkoshy errno = EPROGMISMATCH; 2462145256Sjkoshy return (pmc_syscall = -1); 2463145256Sjkoshy } 2464145256Sjkoshy 2465147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2466145256Sjkoshy return (pmc_syscall = -1); 2467145256Sjkoshy 2468147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2469147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2470147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2471147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2472147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2473147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2474147219Sjkoshy 2475185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2476185363Sjkoshy sizeof(struct pmc_class_descr *)); 2477185363Sjkoshy 2478185363Sjkoshy if (pmc_class_table == NULL) 2479185363Sjkoshy return (-1); 2480185363Sjkoshy 2481198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2482198433Sjkoshy pmc_class_table[n] = NULL; 2483185363Sjkoshy 2484185363Sjkoshy /* 2485185363Sjkoshy * Fill in the class table. 2486185363Sjkoshy */ 2487185363Sjkoshy n = 0; 2488185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 2489185363Sjkoshy pmc_class_table[n++] = &tsc_class_table_descr; 2490198433Sjkoshy 2491198433Sjkoshy /* 2492198433Sjkoshy * Check if this CPU has fixed function counters. 2493198433Sjkoshy */ 2494198433Sjkoshy cpu_has_iaf_counters = 0; 2495198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 2496198433Sjkoshy if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF) 2497198433Sjkoshy cpu_has_iaf_counters = 1; 2498185363Sjkoshy#endif 2499185363Sjkoshy 2500183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 2501183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 2502183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 2503183725Sjkoshy pmc_mdep_class_list_size = \ 2504183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 2505183725Sjkoshy } while (0) 2506183725Sjkoshy 2507198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 2508198433Sjkoshy PMC_MDEP_INIT(C); \ 2509198433Sjkoshy if (cpu_has_iaf_counters) \ 2510198433Sjkoshy pmc_class_table[n++] = &iaf_class_table_descr; \ 2511198433Sjkoshy else \ 2512198433Sjkoshy pmc_mdep_event_aliases = \ 2513198433Sjkoshy C##_aliases_without_iaf; \ 2514198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 2515198433Sjkoshy } while (0) 2516198433Sjkoshy 2517183725Sjkoshy /* Configure the event name parser. */ 2518145256Sjkoshy switch (cpu_info.pm_cputype) { 2519145340Smarcel#if defined(__i386__) 2520145256Sjkoshy case PMC_CPU_AMD_K7: 2521183725Sjkoshy PMC_MDEP_INIT(k7); 2522185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 2523145256Sjkoshy break; 2524145256Sjkoshy case PMC_CPU_INTEL_P5: 2525183725Sjkoshy PMC_MDEP_INIT(p5); 2526185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 2527145256Sjkoshy break; 2528145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 2529145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 2530145256Sjkoshy case PMC_CPU_INTEL_PIII: 2531145256Sjkoshy case PMC_CPU_INTEL_PM: 2532183725Sjkoshy PMC_MDEP_INIT(p6); 2533185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 2534145256Sjkoshy break; 2535147759Sjkoshy#endif 2536147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 2537183725Sjkoshy case PMC_CPU_AMD_K8: 2538183725Sjkoshy PMC_MDEP_INIT(k8); 2539185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 2540183725Sjkoshy break; 2541185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2542198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 2543185363Sjkoshy break; 2544185363Sjkoshy case PMC_CPU_INTEL_CORE: 2545185363Sjkoshy PMC_MDEP_INIT(core); 2546185363Sjkoshy break; 2547185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2548185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2549198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 2550185363Sjkoshy break; 2551187761Sjeff case PMC_CPU_INTEL_COREI7: 2552198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 2553187761Sjeff break; 2554145256Sjkoshy case PMC_CPU_INTEL_PIV: 2555183725Sjkoshy PMC_MDEP_INIT(p4); 2556185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 2557145256Sjkoshy break; 2558145256Sjkoshy#endif 2559200928Srpaulo#if defined(__XSCALE__) 2560200928Srpaulo case PMC_CPU_INTEL_XSCALE: 2561200928Srpaulo PMC_MDEP_INIT(xscale); 2562200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 2563200928Srpaulo break; 2564200928Srpaulo#endif 2565145256Sjkoshy 2566185363Sjkoshy 2567145256Sjkoshy default: 2568145256Sjkoshy /* 2569145256Sjkoshy * Some kind of CPU this version of the library knows nothing 2570145256Sjkoshy * about. This shouldn't happen since the abi version check 2571145256Sjkoshy * should have caught this. 2572145256Sjkoshy */ 2573145256Sjkoshy errno = ENXIO; 2574145256Sjkoshy return (pmc_syscall = -1); 2575145256Sjkoshy } 2576145256Sjkoshy 2577174406Sjkoshy return (0); 2578145256Sjkoshy} 2579145256Sjkoshy 2580147191Sjkoshyconst char * 2581147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 2582145256Sjkoshy{ 2583147191Sjkoshy int i; 2584145256Sjkoshy 2585147191Sjkoshy /* 2586147191Sjkoshy * 'cap' should have a single bit set and should be in 2587147191Sjkoshy * range. 2588147191Sjkoshy */ 2589147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 2590147191Sjkoshy cap > PMC_CAP_LAST) { 2591145256Sjkoshy errno = EINVAL; 2592174406Sjkoshy return (NULL); 2593145256Sjkoshy } 2594145256Sjkoshy 2595147191Sjkoshy i = ffs(cap); 2596174406Sjkoshy return (pmc_capability_names[i - 1]); 2597147191Sjkoshy} 2598145256Sjkoshy 2599147191Sjkoshyconst char * 2600147191Sjkoshypmc_name_of_class(enum pmc_class pc) 2601147191Sjkoshy{ 2602147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 2603147191Sjkoshy pc <= PMC_CLASS_LAST) 2604174406Sjkoshy return (pmc_class_names[pc]); 2605145256Sjkoshy 2606147191Sjkoshy errno = EINVAL; 2607174406Sjkoshy return (NULL); 2608147191Sjkoshy} 2609145256Sjkoshy 2610147191Sjkoshyconst char * 2611147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 2612147191Sjkoshy{ 2613183725Sjkoshy size_t n; 2614183725Sjkoshy 2615183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 2616183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 2617183725Sjkoshy return (pmc_cputype_names[n].pm_name); 2618183725Sjkoshy 2619147191Sjkoshy errno = EINVAL; 2620174406Sjkoshy return (NULL); 2621147191Sjkoshy} 2622145256Sjkoshy 2623147191Sjkoshyconst char * 2624147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 2625147191Sjkoshy{ 2626147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 2627147191Sjkoshy pd <= PMC_DISP_LAST) 2628174406Sjkoshy return (pmc_disposition_names[pd]); 2629145256Sjkoshy 2630147191Sjkoshy errno = EINVAL; 2631174406Sjkoshy return (NULL); 2632147191Sjkoshy} 2633145256Sjkoshy 2634147191Sjkoshyconst char * 2635185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 2636147191Sjkoshy{ 2637183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 2638145256Sjkoshy 2639183725Sjkoshy ev = evfence = NULL; 2640185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 2641185363Sjkoshy ev = iaf_event_table; 2642185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 2643185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 2644185363Sjkoshy switch (cpu) { 2645185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2646185363Sjkoshy ev = atom_event_table; 2647185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 2648185363Sjkoshy break; 2649185363Sjkoshy case PMC_CPU_INTEL_CORE: 2650185363Sjkoshy ev = core_event_table; 2651185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 2652185363Sjkoshy break; 2653185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2654185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2655185363Sjkoshy ev = core2_event_table; 2656185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 2657185363Sjkoshy break; 2658187761Sjeff case PMC_CPU_INTEL_COREI7: 2659187761Sjeff ev = corei7_event_table; 2660187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 2661187761Sjeff break; 2662185363Sjkoshy default: /* Unknown CPU type. */ 2663185363Sjkoshy break; 2664185363Sjkoshy } 2665185363Sjkoshy } if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 2666183725Sjkoshy ev = k7_event_table; 2667183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 2668183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 2669183725Sjkoshy ev = k8_event_table; 2670183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 2671183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 2672183725Sjkoshy ev = p4_event_table; 2673183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 2674183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 2675183725Sjkoshy ev = p5_event_table; 2676183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 2677183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 2678183725Sjkoshy ev = p6_event_table; 2679183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 2680200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 2681200928Srpaulo ev = xscale_event_table; 2682200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 2683183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 2684183725Sjkoshy ev = tsc_event_table; 2685183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 2686183725Sjkoshy } 2687183725Sjkoshy 2688183725Sjkoshy for (; ev != evfence; ev++) 2689183725Sjkoshy if (pe == ev->pm_ev_code) 2690183725Sjkoshy return (ev->pm_ev_name); 2691183725Sjkoshy 2692185363Sjkoshy return (NULL); 2693185363Sjkoshy} 2694185363Sjkoshy 2695185363Sjkoshyconst char * 2696185363Sjkoshypmc_name_of_event(enum pmc_event pe) 2697185363Sjkoshy{ 2698185363Sjkoshy const char *n; 2699185363Sjkoshy 2700185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 2701185363Sjkoshy return (n); 2702185363Sjkoshy 2703147191Sjkoshy errno = EINVAL; 2704174406Sjkoshy return (NULL); 2705147191Sjkoshy} 2706145256Sjkoshy 2707147191Sjkoshyconst char * 2708147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 2709147191Sjkoshy{ 2710147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 2711147191Sjkoshy pm <= PMC_MODE_LAST) 2712174406Sjkoshy return (pmc_mode_names[pm]); 2713145256Sjkoshy 2714147191Sjkoshy errno = EINVAL; 2715174406Sjkoshy return (NULL); 2716147191Sjkoshy} 2717145256Sjkoshy 2718147191Sjkoshyconst char * 2719147191Sjkoshypmc_name_of_state(enum pmc_state ps) 2720147191Sjkoshy{ 2721147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 2722147191Sjkoshy ps <= PMC_STATE_LAST) 2723174406Sjkoshy return (pmc_state_names[ps]); 2724145256Sjkoshy 2725147191Sjkoshy errno = EINVAL; 2726174406Sjkoshy return (NULL); 2727145256Sjkoshy} 2728145256Sjkoshy 2729145256Sjkoshyint 2730147191Sjkoshypmc_ncpu(void) 2731145256Sjkoshy{ 2732147191Sjkoshy if (pmc_syscall == -1) { 2733147191Sjkoshy errno = ENXIO; 2734174406Sjkoshy return (-1); 2735147191Sjkoshy } 2736145256Sjkoshy 2737174406Sjkoshy return (cpu_info.pm_ncpu); 2738145256Sjkoshy} 2739145256Sjkoshy 2740145256Sjkoshyint 2741147191Sjkoshypmc_npmc(int cpu) 2742145256Sjkoshy{ 2743147191Sjkoshy if (pmc_syscall == -1) { 2744147191Sjkoshy errno = ENXIO; 2745174406Sjkoshy return (-1); 2746147191Sjkoshy } 2747145256Sjkoshy 2748147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 2749147191Sjkoshy errno = EINVAL; 2750174406Sjkoshy return (-1); 2751147191Sjkoshy } 2752145256Sjkoshy 2753174406Sjkoshy return (cpu_info.pm_npmc); 2754145256Sjkoshy} 2755145256Sjkoshy 2756145256Sjkoshyint 2757147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 2758145256Sjkoshy{ 2759147191Sjkoshy int nbytes, npmc; 2760147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 2761145256Sjkoshy 2762147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 2763174406Sjkoshy return (-1); 2764145256Sjkoshy 2765147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 2766147191Sjkoshy npmc * sizeof(struct pmc_info); 2767145256Sjkoshy 2768147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 2769174406Sjkoshy return (-1); 2770145256Sjkoshy 2771147191Sjkoshy pmci->pm_cpu = cpu; 2772145256Sjkoshy 2773147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 2774147191Sjkoshy free(pmci); 2775174406Sjkoshy return (-1); 2776147191Sjkoshy } 2777145256Sjkoshy 2778147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 2779147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 2780174406Sjkoshy return (0); 2781145256Sjkoshy} 2782145256Sjkoshy 2783145256Sjkoshyint 2784145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 2785145256Sjkoshy{ 2786145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 2787145256Sjkoshy 2788145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 2789145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 2790145256Sjkoshy pmc_read_op.pm_value = -1; 2791145256Sjkoshy 2792145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 2793174406Sjkoshy return (-1); 2794145256Sjkoshy 2795145256Sjkoshy *value = pmc_read_op.pm_value; 2796174406Sjkoshy return (0); 2797145256Sjkoshy} 2798145256Sjkoshy 2799145256Sjkoshyint 2800147191Sjkoshypmc_release(pmc_id_t pmc) 2801145256Sjkoshy{ 2802147191Sjkoshy struct pmc_op_simple pmc_release_args; 2803145256Sjkoshy 2804147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 2805174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 2806145256Sjkoshy} 2807145256Sjkoshy 2808145256Sjkoshyint 2809145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 2810145256Sjkoshy{ 2811145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 2812145256Sjkoshy 2813145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 2814145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 2815145256Sjkoshy pmc_rw_op.pm_value = newvalue; 2816145256Sjkoshy 2817145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 2818174406Sjkoshy return (-1); 2819145256Sjkoshy 2820145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 2821174406Sjkoshy return (0); 2822145256Sjkoshy} 2823145256Sjkoshy 2824145256Sjkoshyint 2825145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 2826145256Sjkoshy{ 2827145256Sjkoshy struct pmc_op_pmcsetcount sc; 2828145256Sjkoshy 2829145256Sjkoshy sc.pm_pmcid = pmc; 2830145256Sjkoshy sc.pm_count = value; 2831145256Sjkoshy 2832145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 2833174406Sjkoshy return (-1); 2834174406Sjkoshy return (0); 2835145256Sjkoshy} 2836145256Sjkoshy 2837145256Sjkoshyint 2838147191Sjkoshypmc_start(pmc_id_t pmc) 2839145256Sjkoshy{ 2840147191Sjkoshy struct pmc_op_simple pmc_start_args; 2841145256Sjkoshy 2842147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 2843174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 2844145256Sjkoshy} 2845145256Sjkoshy 2846145256Sjkoshyint 2847147191Sjkoshypmc_stop(pmc_id_t pmc) 2848145256Sjkoshy{ 2849147191Sjkoshy struct pmc_op_simple pmc_stop_args; 2850145256Sjkoshy 2851147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 2852174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 2853145256Sjkoshy} 2854145256Sjkoshy 2855145256Sjkoshyint 2856145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 2857145774Sjkoshy{ 2858145774Sjkoshy unsigned int i; 2859145774Sjkoshy enum pmc_class cl; 2860145774Sjkoshy 2861145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2862145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2863145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2864145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 2865174406Sjkoshy return (0); 2866145774Sjkoshy } 2867177107Sjkoshy errno = EINVAL; 2868177107Sjkoshy return (-1); 2869145774Sjkoshy} 2870145774Sjkoshy 2871145774Sjkoshyint 2872147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 2873145774Sjkoshy{ 2874147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 2875145774Sjkoshy 2876147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 2877147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 2878147191Sjkoshy pmc_write_op.pm_value = value; 2879174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 2880145256Sjkoshy} 2881145256Sjkoshy 2882145256Sjkoshyint 2883147191Sjkoshypmc_writelog(uint32_t userdata) 2884145256Sjkoshy{ 2885147191Sjkoshy struct pmc_op_writelog wl; 2886145256Sjkoshy 2887147191Sjkoshy wl.pm_userdata = userdata; 2888174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 2889145256Sjkoshy} 2890