libpmc.c revision 147191
1145256Sjkoshy/*- 2147191Sjkoshy * Copyright (c) 2003-2005 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 147191 2005-06-09 19:45:09Z jkoshy $"); 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 45145256Sjkoshy/* Function prototypes */ 46145340Smarcel#if defined(__i386__) 47145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 48145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 49147191Sjkoshy#endif 50147191Sjkoshy#if defined(__amd64__) 51147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 52145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 53147191Sjkoshy#endif 54147191Sjkoshy#if defined(__i386__) 55145256Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 56145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 57145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 58145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 59147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 60145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 61145256Sjkoshy#endif 62145256Sjkoshy 63145256Sjkoshy#define PMC_CALL(cmd, params) \ 64145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 65145256Sjkoshy 66145256Sjkoshy/* 67145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 68145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 69145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 70145256Sjkoshy * lookup table. 71145256Sjkoshy */ 72145256Sjkoshy 73145256Sjkoshystruct pmc_event_alias { 74145256Sjkoshy const char *pm_alias; 75145256Sjkoshy const char *pm_spec; 76145256Sjkoshy}; 77145256Sjkoshy 78145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 79145256Sjkoshy 80145256Sjkoshy/* 81145256Sjkoshy * The pmc_event_descr table maps symbolic names known to the user 82145256Sjkoshy * to integer codes used by the PMC KLD. 83145256Sjkoshy */ 84145256Sjkoshy 85145256Sjkoshystruct pmc_event_descr { 86145256Sjkoshy const char *pm_ev_name; 87145256Sjkoshy enum pmc_event pm_ev_code; 88145256Sjkoshy enum pmc_class pm_ev_class; 89145256Sjkoshy}; 90145256Sjkoshy 91145256Sjkoshystatic const struct pmc_event_descr 92145256Sjkoshypmc_event_table[] = 93145256Sjkoshy{ 94145256Sjkoshy#undef __PMC_EV 95145256Sjkoshy#define __PMC_EV(C,N,EV) { #EV, PMC_EV_ ## C ## _ ## N, PMC_CLASS_ ## C }, 96145256Sjkoshy __PMC_EVENTS() 97145256Sjkoshy}; 98145256Sjkoshy 99145256Sjkoshy/* 100145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 101145256Sjkoshy * strings. 102145256Sjkoshy */ 103145256Sjkoshy 104145256Sjkoshystatic const char * pmc_capability_names[] = { 105145256Sjkoshy#undef __PMC_CAP 106145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 107145256Sjkoshy __PMC_CAPS() 108145256Sjkoshy}; 109145256Sjkoshy 110145256Sjkoshystatic const char * pmc_class_names[] = { 111145256Sjkoshy#undef __PMC_CLASS 112145256Sjkoshy#define __PMC_CLASS(C) #C , 113145256Sjkoshy __PMC_CLASSES() 114145256Sjkoshy}; 115145256Sjkoshy 116145256Sjkoshystatic const char * pmc_cputype_names[] = { 117145256Sjkoshy#undef __PMC_CPU 118145256Sjkoshy#define __PMC_CPU(S, D) #S , 119145256Sjkoshy __PMC_CPUS() 120145256Sjkoshy}; 121145256Sjkoshy 122145256Sjkoshystatic const char * pmc_disposition_names[] = { 123145256Sjkoshy#undef __PMC_DISP 124145256Sjkoshy#define __PMC_DISP(D) #D , 125145256Sjkoshy __PMC_DISPOSITIONS() 126145256Sjkoshy}; 127145256Sjkoshy 128145256Sjkoshystatic const char * pmc_mode_names[] = { 129145256Sjkoshy#undef __PMC_MODE 130145256Sjkoshy#define __PMC_MODE(M,N) #M , 131145256Sjkoshy __PMC_MODES() 132145256Sjkoshy}; 133145256Sjkoshy 134145256Sjkoshystatic const char * pmc_state_names[] = { 135145256Sjkoshy#undef __PMC_STATE 136145256Sjkoshy#define __PMC_STATE(S) #S , 137145256Sjkoshy __PMC_STATES() 138145256Sjkoshy}; 139145256Sjkoshy 140145256Sjkoshystatic int pmc_syscall = -1; /* filled in by pmc_init() */ 141145256Sjkoshy 142145256Sjkoshystruct pmc_op_getcpuinfo cpu_info; /* filled in by pmc_init() */ 143145256Sjkoshy 144145256Sjkoshy/* Architecture dependent event parsing */ 145145256Sjkoshystatic int (*pmc_mdep_allocate_pmc)(enum pmc_event _pe, char *_ctrspec, 146145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 147145256Sjkoshy 148145256Sjkoshy/* Event masks for events */ 149145256Sjkoshystruct pmc_masks { 150145256Sjkoshy const char *pm_name; 151145256Sjkoshy const uint32_t pm_value; 152145256Sjkoshy}; 153145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 154145256Sjkoshy#define NULLMASK PMCMASK(NULL,0) 155145256Sjkoshy 156145340Smarcel#if defined(__i386__) || defined(__amd64__) 157145256Sjkoshystatic int 158145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 159145256Sjkoshy{ 160145256Sjkoshy const struct pmc_masks *pm; 161145256Sjkoshy char *q, *r; 162145256Sjkoshy int c; 163145256Sjkoshy 164145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 165145256Sjkoshy return -1; 166145256Sjkoshy q = strchr(p, '='); /* skip '=' */ 167145256Sjkoshy if (*++q == '\0') /* no more data */ 168145256Sjkoshy return -1; 169145256Sjkoshy c = 0; /* count of mask keywords seen */ 170145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 171145256Sjkoshy for (pm = pmask; pm->pm_name && strcmp(r, pm->pm_name); pm++) 172145256Sjkoshy ; 173145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 174145256Sjkoshy return -1; 175145256Sjkoshy *evmask |= pm->pm_value; 176145256Sjkoshy c++; 177145256Sjkoshy } 178145256Sjkoshy return c; 179145256Sjkoshy} 180145340Smarcel#endif 181145256Sjkoshy 182145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 183145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 184145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 185145256Sjkoshy 186145340Smarcel#if defined(__i386__) 187145256Sjkoshy 188145256Sjkoshy/* 189145256Sjkoshy * AMD K7 (Athlon) CPUs. 190145256Sjkoshy */ 191145256Sjkoshy 192145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 193145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 194145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 195145351Sjkoshy EV_ALIAS("cycles", "tsc"), 196145351Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses,mask=moesi"), 197145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 198145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 199145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 200145351Sjkoshy EV_ALIAS(NULL, NULL) 201145256Sjkoshy}; 202145256Sjkoshy 203145256Sjkoshy#define K7_KW_COUNT "count" 204145256Sjkoshy#define K7_KW_EDGE "edge" 205145256Sjkoshy#define K7_KW_INV "inv" 206145256Sjkoshy#define K7_KW_OS "os" 207145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 208145256Sjkoshy#define K7_KW_USR "usr" 209145256Sjkoshy 210145256Sjkoshystatic int 211145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 212145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 213145256Sjkoshy{ 214145256Sjkoshy char *e, *p, *q; 215145256Sjkoshy int c, has_unitmask; 216145256Sjkoshy uint32_t count, unitmask; 217145256Sjkoshy 218147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 219145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 220145256Sjkoshy 221145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 222145256Sjkoshy /* TSC events must be unqualified. */ 223145256Sjkoshy if (ctrspec && *ctrspec != '\0') 224145256Sjkoshy return -1; 225145256Sjkoshy return 0; 226145256Sjkoshy } 227145256Sjkoshy 228145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 229145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 230145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 231145256Sjkoshy has_unitmask = 1; 232147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 233145256Sjkoshy } else 234145256Sjkoshy unitmask = has_unitmask = 0; 235145256Sjkoshy 236145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 237145256Sjkoshy 238145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 239145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 240145256Sjkoshy q = strchr(p, '='); 241145256Sjkoshy if (*++q == '\0') /* skip '=' */ 242145256Sjkoshy return -1; 243145256Sjkoshy 244145256Sjkoshy count = strtol(q, &e, 0); 245145256Sjkoshy if (e == q || *e != '\0') 246145256Sjkoshy return -1; 247145256Sjkoshy 248145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 249147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 250147191Sjkoshy AMD_PMC_TO_COUNTER(count); 251145256Sjkoshy 252145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 253145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 254145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 255145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 256145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 257145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 258145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 259145256Sjkoshy if (has_unitmask == 0) 260145256Sjkoshy return -1; 261145256Sjkoshy unitmask = 0; 262145256Sjkoshy q = strchr(p, '='); 263145256Sjkoshy if (*++q == '\0') /* skip '=' */ 264145256Sjkoshy return -1; 265145256Sjkoshy 266145256Sjkoshy while ((c = tolower(*q++)) != 0) 267145256Sjkoshy if (c == 'm') 268147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 269145256Sjkoshy else if (c == 'o') 270147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 271145256Sjkoshy else if (c == 'e') 272147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 273145256Sjkoshy else if (c == 's') 274147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 275145256Sjkoshy else if (c == 'i') 276147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 277145256Sjkoshy else if (c == '+') 278145256Sjkoshy continue; 279145256Sjkoshy else 280145256Sjkoshy return -1; 281145256Sjkoshy 282145256Sjkoshy if (unitmask == 0) 283145256Sjkoshy return -1; 284145256Sjkoshy 285145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 286145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 287145256Sjkoshy } else 288145256Sjkoshy return -1; 289145256Sjkoshy } 290145256Sjkoshy 291145256Sjkoshy if (has_unitmask) { 292145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 293147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 294147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 295145256Sjkoshy } 296145256Sjkoshy 297145256Sjkoshy return 0; 298145256Sjkoshy 299145256Sjkoshy} 300145256Sjkoshy 301147191Sjkoshy#endif 302147191Sjkoshy 303147191Sjkoshy#if defined(__amd64__) 304147191Sjkoshy 305145256Sjkoshy/* 306147191Sjkoshy * AMD K8 PMCs. 307147191Sjkoshy * 308147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 309147191Sjkoshy * events. 310147191Sjkoshy */ 311147191Sjkoshy 312147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 313147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 314147191Sjkoshy EV_ALIAS("branch-mispredicts", 315147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 316147191Sjkoshy EV_ALIAS("cycles", "tsc"), 317147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 318147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 319147191Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 320147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 321147191Sjkoshy EV_ALIAS(NULL, NULL) 322147191Sjkoshy}; 323147191Sjkoshy 324147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 325147191Sjkoshy 326147191Sjkoshy/* 327147191Sjkoshy * Parsing tables 328147191Sjkoshy */ 329147191Sjkoshy 330147191Sjkoshy/* fp dispatched fpu ops */ 331147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 332147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 333147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 334147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 335147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 336147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 337147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 338147191Sjkoshy NULLMASK 339147191Sjkoshy}; 340147191Sjkoshy 341147191Sjkoshy/* ls segment register loads */ 342147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 343147191Sjkoshy __K8MASK(es, 0), 344147191Sjkoshy __K8MASK(cs, 1), 345147191Sjkoshy __K8MASK(ss, 2), 346147191Sjkoshy __K8MASK(ds, 3), 347147191Sjkoshy __K8MASK(fs, 4), 348147191Sjkoshy __K8MASK(gs, 5), 349147191Sjkoshy __K8MASK(hs, 6), 350147191Sjkoshy NULLMASK 351147191Sjkoshy}; 352147191Sjkoshy 353147191Sjkoshy/* ls locked operation */ 354147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 355147191Sjkoshy __K8MASK(locked-instructions, 0), 356147191Sjkoshy __K8MASK(cycles-in-request, 1), 357147191Sjkoshy __K8MASK(cycles-to-complete, 2), 358147191Sjkoshy NULLMASK 359147191Sjkoshy}; 360147191Sjkoshy 361147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 362147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 363147191Sjkoshy __K8MASK(invalid, 0), 364147191Sjkoshy __K8MASK(shared, 1), 365147191Sjkoshy __K8MASK(exclusive, 2), 366147191Sjkoshy __K8MASK(owner, 3), 367147191Sjkoshy __K8MASK(modified, 4), 368147191Sjkoshy NULLMASK 369147191Sjkoshy}; 370147191Sjkoshy 371147191Sjkoshy/* dc one bit ecc error */ 372147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 373147191Sjkoshy __K8MASK(scrubber, 0), 374147191Sjkoshy __K8MASK(piggyback, 1), 375147191Sjkoshy NULLMASK 376147191Sjkoshy}; 377147191Sjkoshy 378147191Sjkoshy/* dc dispatched prefetch instructions */ 379147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 380147191Sjkoshy __K8MASK(load, 0), 381147191Sjkoshy __K8MASK(store, 1), 382147191Sjkoshy __K8MASK(nta, 2), 383147191Sjkoshy NULLMASK 384147191Sjkoshy}; 385147191Sjkoshy 386147191Sjkoshy/* dc dcache accesses by locks */ 387147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 388147191Sjkoshy __K8MASK(accesses, 0), 389147191Sjkoshy __K8MASK(misses, 1), 390147191Sjkoshy NULLMASK 391147191Sjkoshy}; 392147191Sjkoshy 393147191Sjkoshy/* bu internal l2 request */ 394147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 395147191Sjkoshy __K8MASK(ic-fill, 0), 396147191Sjkoshy __K8MASK(dc-fill, 1), 397147191Sjkoshy __K8MASK(tlb-reload, 2), 398147191Sjkoshy __K8MASK(tag-snoop, 3), 399147191Sjkoshy __K8MASK(cancelled, 4), 400147191Sjkoshy NULLMASK 401147191Sjkoshy}; 402147191Sjkoshy 403147191Sjkoshy/* bu fill request l2 miss */ 404147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 405147191Sjkoshy __K8MASK(ic-fill, 0), 406147191Sjkoshy __K8MASK(dc-fill, 1), 407147191Sjkoshy __K8MASK(tlb-reload, 2), 408147191Sjkoshy NULLMASK 409147191Sjkoshy}; 410147191Sjkoshy 411147191Sjkoshy/* bu fill into l2 */ 412147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 413147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 414147191Sjkoshy __K8MASK(victim-from-l2, 1), 415147191Sjkoshy NULLMASK 416147191Sjkoshy}; 417147191Sjkoshy 418147191Sjkoshy/* fr retired fpu instructions */ 419147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 420147191Sjkoshy __K8MASK(x87, 0), 421147191Sjkoshy __K8MASK(mmx-3dnow, 1), 422147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 423147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 424147191Sjkoshy NULLMASK 425147191Sjkoshy}; 426147191Sjkoshy 427147191Sjkoshy/* fr retired fastpath double op instructions */ 428147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 429147191Sjkoshy __K8MASK(low-op-pos-0, 0), 430147191Sjkoshy __K8MASK(low-op-pos-1, 1), 431147191Sjkoshy __K8MASK(low-op-pos-2, 2), 432147191Sjkoshy NULLMASK 433147191Sjkoshy}; 434147191Sjkoshy 435147191Sjkoshy/* fr fpu exceptions */ 436147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 437147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 438147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 439147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 440147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 441147191Sjkoshy NULLMASK 442147191Sjkoshy}; 443147191Sjkoshy 444147191Sjkoshy/* nb memory controller page access event */ 445147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 446147191Sjkoshy __K8MASK(page-hit, 0), 447147191Sjkoshy __K8MASK(page-miss, 1), 448147191Sjkoshy __K8MASK(page-conflict, 2), 449147191Sjkoshy NULLMASK 450147191Sjkoshy}; 451147191Sjkoshy 452147191Sjkoshy/* nb memory controller turnaround */ 453147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 454147191Sjkoshy __K8MASK(dimm-turnaround, 0), 455147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 456147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 457147191Sjkoshy NULLMASK 458147191Sjkoshy}; 459147191Sjkoshy 460147191Sjkoshy/* nb memory controller bypass saturation */ 461147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 462147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 463147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 464147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 465147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 466147191Sjkoshy NULLMASK 467147191Sjkoshy}; 468147191Sjkoshy 469147191Sjkoshy/* nb sized commands */ 470147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 471147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 472147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 473147191Sjkoshy __K8MASK(postwrszbyte, 2), 474147191Sjkoshy __K8MASK(postwrszdword, 3), 475147191Sjkoshy __K8MASK(rdszbyte, 4), 476147191Sjkoshy __K8MASK(rdszdword, 5), 477147191Sjkoshy __K8MASK(rdmodwr, 6), 478147191Sjkoshy NULLMASK 479147191Sjkoshy}; 480147191Sjkoshy 481147191Sjkoshy/* nb probe result */ 482147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 483147191Sjkoshy __K8MASK(probe-miss, 0), 484147191Sjkoshy __K8MASK(probe-hit, 1), 485147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 486147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 487147191Sjkoshy NULLMASK 488147191Sjkoshy}; 489147191Sjkoshy 490147191Sjkoshy/* nb hypertransport bus bandwidth */ 491147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 492147191Sjkoshy __K8MASK(command, 0), 493147191Sjkoshy __K8MASK(data, 1), 494147191Sjkoshy __K8MASK(buffer-release, 2), 495147191Sjkoshy __K8MASK(nop, 3), 496147191Sjkoshy NULLMASK 497147191Sjkoshy}; 498147191Sjkoshy 499147191Sjkoshy#undef __K8MASK 500147191Sjkoshy 501147191Sjkoshy#define K8_KW_COUNT "count" 502147191Sjkoshy#define K8_KW_EDGE "edge" 503147191Sjkoshy#define K8_KW_INV "inv" 504147191Sjkoshy#define K8_KW_MASK "mask" 505147191Sjkoshy#define K8_KW_OS "os" 506147191Sjkoshy#define K8_KW_USR "usr" 507147191Sjkoshy 508147191Sjkoshystatic int 509147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 510147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 511147191Sjkoshy{ 512147191Sjkoshy char *e, *p, *q; 513147191Sjkoshy int n; 514147191Sjkoshy uint32_t count, evmask; 515147191Sjkoshy const struct pmc_masks *pm, *pmask; 516147191Sjkoshy 517147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 518147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 519147191Sjkoshy 520147191Sjkoshy if (pe == PMC_EV_TSC_TSC) { 521147191Sjkoshy /* TSC events must be unqualified. */ 522147191Sjkoshy if (ctrspec && *ctrspec != '\0') 523147191Sjkoshy return -1; 524147191Sjkoshy return 0; 525147191Sjkoshy } 526147191Sjkoshy 527147191Sjkoshy pmask = NULL; 528147191Sjkoshy evmask = 0; 529147191Sjkoshy 530147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 531147191Sjkoshy 532147191Sjkoshy /* setup parsing tables */ 533147191Sjkoshy switch (pe) { 534147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 535147191Sjkoshy __K8SETMASK(fdfo); 536147191Sjkoshy break; 537147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 538147191Sjkoshy __K8SETMASK(lsrl); 539147191Sjkoshy break; 540147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 541147191Sjkoshy __K8SETMASK(llo); 542147191Sjkoshy break; 543147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 544147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 545147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 546147191Sjkoshy __K8SETMASK(dc); 547147191Sjkoshy break; 548147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 549147191Sjkoshy __K8SETMASK(dobee); 550147191Sjkoshy break; 551147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 552147191Sjkoshy __K8SETMASK(ddpi); 553147191Sjkoshy break; 554147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 555147191Sjkoshy __K8SETMASK(dabl); 556147191Sjkoshy break; 557147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 558147191Sjkoshy __K8SETMASK(bilr); 559147191Sjkoshy break; 560147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 561147191Sjkoshy __K8SETMASK(bfrlm); 562147191Sjkoshy break; 563147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 564147191Sjkoshy __K8SETMASK(bfil); 565147191Sjkoshy break; 566147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 567147191Sjkoshy __K8SETMASK(frfi); 568147191Sjkoshy break; 569147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 570147191Sjkoshy __K8SETMASK(frfdoi); 571147191Sjkoshy break; 572147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 573147191Sjkoshy __K8SETMASK(ffe); 574147191Sjkoshy break; 575147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 576147191Sjkoshy __K8SETMASK(nmcpae); 577147191Sjkoshy break; 578147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 579147191Sjkoshy __K8SETMASK(nmct); 580147191Sjkoshy break; 581147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 582147191Sjkoshy __K8SETMASK(nmcbs); 583147191Sjkoshy break; 584147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 585147191Sjkoshy __K8SETMASK(nsc); 586147191Sjkoshy break; 587147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 588147191Sjkoshy __K8SETMASK(npr); 589147191Sjkoshy break; 590147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 591147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 592147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 593147191Sjkoshy __K8SETMASK(nhbb); 594147191Sjkoshy break; 595147191Sjkoshy 596147191Sjkoshy default: 597147191Sjkoshy break; /* no options defined */ 598147191Sjkoshy } 599147191Sjkoshy 600147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 601147191Sjkoshy 602147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 603147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 604147191Sjkoshy q = strchr(p, '='); 605147191Sjkoshy if (*++q == '\0') /* skip '=' */ 606147191Sjkoshy return -1; 607147191Sjkoshy 608147191Sjkoshy count = strtol(q, &e, 0); 609147191Sjkoshy if (e == q || *e != '\0') 610147191Sjkoshy return -1; 611147191Sjkoshy 612147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 613147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 614147191Sjkoshy AMD_PMC_TO_COUNTER(count); 615147191Sjkoshy 616147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 617147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 618147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 619147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 620147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 621147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 622147191Sjkoshy return -1; 623147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 624147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 625147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 626147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 627147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 628147191Sjkoshy } else 629147191Sjkoshy return -1; 630147191Sjkoshy } 631147191Sjkoshy 632147191Sjkoshy /* other post processing */ 633147191Sjkoshy 634147191Sjkoshy switch (pe) { 635147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 636147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 637147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 638147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 639147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 640147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 641147191Sjkoshy /* XXX only available in rev B and later */ 642147191Sjkoshy break; 643147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 644147191Sjkoshy /* XXX only available in rev C and later */ 645147191Sjkoshy break; 646147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 647147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 648147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 649147191Sjkoshy return -1; 650147191Sjkoshy if (evmask == 0) { 651147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 652147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 653147191Sjkoshy } 654147191Sjkoshy break; 655147191Sjkoshy default: 656147191Sjkoshy if (evmask == 0 && pmask != NULL) { 657147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 658147191Sjkoshy evmask |= pm->pm_value; 659147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 660147191Sjkoshy } 661147191Sjkoshy } 662147191Sjkoshy 663147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 664147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 665147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 666147191Sjkoshy 667147191Sjkoshy return 0; 668147191Sjkoshy} 669147191Sjkoshy 670147191Sjkoshy#endif 671147191Sjkoshy 672147191Sjkoshy#if defined(__i386__) 673147191Sjkoshy 674147191Sjkoshy/* 675145256Sjkoshy * Intel P4 PMCs 676145256Sjkoshy */ 677145256Sjkoshy 678145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 679145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 680145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 681145351Sjkoshy EV_ALIAS("cycles", "tsc"), 682145351Sjkoshy EV_ALIAS("instructions", 683145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 684145256Sjkoshy EV_ALIAS(NULL, NULL) 685145256Sjkoshy}; 686145256Sjkoshy 687145256Sjkoshy#define P4_KW_ACTIVE "active" 688145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 689145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 690145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 691145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 692145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 693145256Sjkoshy#define P4_KW_CASCADE "cascade" 694145256Sjkoshy#define P4_KW_EDGE "edge" 695145256Sjkoshy#define P4_KW_INV "complement" 696145256Sjkoshy#define P4_KW_OS "os" 697145256Sjkoshy#define P4_KW_MASK "mask" 698145256Sjkoshy#define P4_KW_PRECISE "precise" 699145256Sjkoshy#define P4_KW_TAG "tag" 700145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 701145256Sjkoshy#define P4_KW_USR "usr" 702145256Sjkoshy 703145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 704145256Sjkoshy 705145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 706145256Sjkoshy __P4MASK(dd, 0), 707145256Sjkoshy __P4MASK(db, 1), 708145256Sjkoshy __P4MASK(di, 2), 709145256Sjkoshy __P4MASK(bd, 3), 710145256Sjkoshy __P4MASK(bb, 4), 711145256Sjkoshy __P4MASK(bi, 5), 712145256Sjkoshy __P4MASK(id, 6), 713145256Sjkoshy __P4MASK(ib, 7), 714145256Sjkoshy NULLMASK 715145256Sjkoshy}; 716145256Sjkoshy 717145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 718145256Sjkoshy __P4MASK(tcmiss, 0), 719145256Sjkoshy NULLMASK, 720145256Sjkoshy}; 721145256Sjkoshy 722145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 723145256Sjkoshy __P4MASK(hit, 0), 724145256Sjkoshy __P4MASK(miss, 1), 725145256Sjkoshy __P4MASK(hit-uc, 2), 726145256Sjkoshy NULLMASK 727145256Sjkoshy}; 728145256Sjkoshy 729145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 730145256Sjkoshy __P4MASK(st-rb-full, 2), 731145256Sjkoshy __P4MASK(64k-conf, 3), 732145256Sjkoshy NULLMASK 733145256Sjkoshy}; 734145256Sjkoshy 735145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 736145256Sjkoshy __P4MASK(lsc, 0), 737145256Sjkoshy __P4MASK(ssc, 1), 738145256Sjkoshy NULLMASK 739145256Sjkoshy}; 740145256Sjkoshy 741145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 742145256Sjkoshy __P4MASK(split-ld, 1), 743145256Sjkoshy NULLMASK 744145256Sjkoshy}; 745145256Sjkoshy 746145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 747145256Sjkoshy __P4MASK(split-st, 1), 748145256Sjkoshy NULLMASK 749145256Sjkoshy}; 750145256Sjkoshy 751145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 752145256Sjkoshy __P4MASK(no-sta, 1), 753145256Sjkoshy __P4MASK(no-std, 3), 754145256Sjkoshy __P4MASK(partial-data, 4), 755145256Sjkoshy __P4MASK(unalgn-addr, 5), 756145256Sjkoshy NULLMASK 757145256Sjkoshy}; 758145256Sjkoshy 759145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 760145256Sjkoshy __P4MASK(dtmiss, 0), 761145256Sjkoshy __P4MASK(itmiss, 1), 762145256Sjkoshy NULLMASK 763145256Sjkoshy}; 764145256Sjkoshy 765145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 766145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 767145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 768145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 769145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 770145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 771145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 772145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 773145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 774145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 775145256Sjkoshy NULLMASK 776145256Sjkoshy}; 777145256Sjkoshy 778145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 779145256Sjkoshy __P4MASK(all-read, 5), 780145256Sjkoshy __P4MASK(all-write, 6), 781145256Sjkoshy __P4MASK(mem-uc, 7), 782145256Sjkoshy __P4MASK(mem-wc, 8), 783145256Sjkoshy __P4MASK(mem-wt, 9), 784145256Sjkoshy __P4MASK(mem-wp, 10), 785145256Sjkoshy __P4MASK(mem-wb, 11), 786145256Sjkoshy __P4MASK(own, 13), 787145256Sjkoshy __P4MASK(other, 14), 788145256Sjkoshy __P4MASK(prefetch, 15), 789145256Sjkoshy NULLMASK 790145256Sjkoshy}; 791145256Sjkoshy 792145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 793145256Sjkoshy __P4MASK(all-read, 5), 794145256Sjkoshy __P4MASK(all-write, 6), 795145256Sjkoshy __P4MASK(mem-uc, 7), 796145256Sjkoshy __P4MASK(mem-wc, 8), 797145256Sjkoshy __P4MASK(mem-wt, 9), 798145256Sjkoshy __P4MASK(mem-wp, 10), 799145256Sjkoshy __P4MASK(mem-wb, 11), 800145256Sjkoshy __P4MASK(own, 13), 801145256Sjkoshy __P4MASK(other, 14), 802145256Sjkoshy __P4MASK(prefetch, 15), 803145256Sjkoshy NULLMASK 804145256Sjkoshy}; 805145256Sjkoshy 806145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 807145256Sjkoshy __P4MASK(drdy-drv, 0), 808145256Sjkoshy __P4MASK(drdy-own, 1), 809145256Sjkoshy __P4MASK(drdy-other, 2), 810145256Sjkoshy __P4MASK(dbsy-drv, 3), 811145256Sjkoshy __P4MASK(dbsy-own, 4), 812145256Sjkoshy __P4MASK(dbsy-other, 5), 813145256Sjkoshy NULLMASK 814145256Sjkoshy}; 815145256Sjkoshy 816145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 817145256Sjkoshy __P4MASK(req-type0, 0), 818145256Sjkoshy __P4MASK(req-type1, 1), 819145256Sjkoshy __P4MASK(req-len0, 2), 820145256Sjkoshy __P4MASK(req-len1, 3), 821145256Sjkoshy __P4MASK(req-io-type, 5), 822145256Sjkoshy __P4MASK(req-lock-type, 6), 823145256Sjkoshy __P4MASK(req-cache-type, 7), 824145256Sjkoshy __P4MASK(req-split-type, 8), 825145256Sjkoshy __P4MASK(req-dem-type, 9), 826145256Sjkoshy __P4MASK(req-ord-type, 10), 827145256Sjkoshy __P4MASK(mem-type0, 11), 828145256Sjkoshy __P4MASK(mem-type1, 12), 829145256Sjkoshy __P4MASK(mem-type2, 13), 830145256Sjkoshy NULLMASK 831145256Sjkoshy}; 832145256Sjkoshy 833145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 834145256Sjkoshy __P4MASK(all, 15), 835145256Sjkoshy NULLMASK 836145256Sjkoshy}; 837145256Sjkoshy 838145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 839145256Sjkoshy __P4MASK(all, 15), 840145256Sjkoshy NULLMASK 841145256Sjkoshy}; 842145256Sjkoshy 843145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 844145256Sjkoshy __P4MASK(all, 15), 845145256Sjkoshy NULLMASK 846145256Sjkoshy}; 847145256Sjkoshy 848145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 849145256Sjkoshy __P4MASK(all, 15), 850145256Sjkoshy NULLMASK 851145256Sjkoshy}; 852145256Sjkoshy 853145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 854145256Sjkoshy __P4MASK(all, 15), 855145256Sjkoshy NULLMASK 856145256Sjkoshy}; 857145256Sjkoshy 858145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 859145256Sjkoshy __P4MASK(all, 15), 860145256Sjkoshy NULLMASK 861145256Sjkoshy}; 862145256Sjkoshy 863145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 864145256Sjkoshy __P4MASK(all, 15), 865145256Sjkoshy NULLMASK 866145256Sjkoshy}; 867145256Sjkoshy 868145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 869145256Sjkoshy __P4MASK(all, 15), 870145256Sjkoshy NULLMASK 871145256Sjkoshy}; 872145256Sjkoshy 873145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 874145256Sjkoshy __P4MASK(allp0, 3), 875145256Sjkoshy __P4MASK(allp2, 4), 876145256Sjkoshy NULLMASK 877145256Sjkoshy}; 878145256Sjkoshy 879145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 880145256Sjkoshy __P4MASK(running, 0), 881145256Sjkoshy NULLMASK 882145256Sjkoshy}; 883145256Sjkoshy 884145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 885145256Sjkoshy __P4MASK(cisc, 0), 886145256Sjkoshy NULLMASK 887145256Sjkoshy}; 888145256Sjkoshy 889145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 890145256Sjkoshy __P4MASK(from-tc-build, 0), 891145256Sjkoshy __P4MASK(from-tc-deliver, 1), 892145256Sjkoshy __P4MASK(from-rom, 2), 893145256Sjkoshy NULLMASK 894145256Sjkoshy}; 895145256Sjkoshy 896145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 897145351Sjkoshy /* retired mispred branch type */ 898145256Sjkoshy __P4MASK(conditional, 1), 899145256Sjkoshy __P4MASK(call, 2), 900145256Sjkoshy __P4MASK(return, 3), 901145256Sjkoshy __P4MASK(indirect, 4), 902145256Sjkoshy NULLMASK 903145256Sjkoshy}; 904145256Sjkoshy 905145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 906145256Sjkoshy __P4MASK(conditional, 1), 907145256Sjkoshy __P4MASK(call, 2), 908145256Sjkoshy __P4MASK(retired, 3), 909145256Sjkoshy __P4MASK(indirect, 4), 910145256Sjkoshy NULLMASK 911145256Sjkoshy}; 912145256Sjkoshy 913145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 914145256Sjkoshy __P4MASK(sbfull, 5), 915145256Sjkoshy NULLMASK 916145256Sjkoshy}; 917145256Sjkoshy 918145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 919145256Sjkoshy __P4MASK(wcb-evicts, 0), 920145256Sjkoshy __P4MASK(wcb-full-evict, 1), 921145256Sjkoshy NULLMASK 922145256Sjkoshy}; 923145256Sjkoshy 924145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 925145256Sjkoshy __P4MASK(nbogus, 0), 926145256Sjkoshy __P4MASK(bogus, 1), 927145256Sjkoshy NULLMASK 928145256Sjkoshy}; 929145256Sjkoshy 930145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 931145256Sjkoshy __P4MASK(nbogus0, 0), 932145256Sjkoshy __P4MASK(nbogus1, 1), 933145256Sjkoshy __P4MASK(nbogus2, 2), 934145256Sjkoshy __P4MASK(nbogus3, 3), 935145256Sjkoshy __P4MASK(bogus0, 4), 936145256Sjkoshy __P4MASK(bogus1, 5), 937145256Sjkoshy __P4MASK(bogus2, 6), 938145256Sjkoshy __P4MASK(bogus3, 7), 939145256Sjkoshy NULLMASK 940145256Sjkoshy}; 941145256Sjkoshy 942145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 943145256Sjkoshy __P4MASK(nbogus, 0), 944145256Sjkoshy __P4MASK(bogus, 1), 945145256Sjkoshy NULLMASK 946145256Sjkoshy}; 947145256Sjkoshy 948145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 949145256Sjkoshy __P4MASK(nbogusntag, 0), 950145256Sjkoshy __P4MASK(nbogustag, 1), 951145256Sjkoshy __P4MASK(bogusntag, 2), 952145256Sjkoshy __P4MASK(bogustag, 3), 953145256Sjkoshy NULLMASK 954145256Sjkoshy}; 955145256Sjkoshy 956145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 957145256Sjkoshy __P4MASK(nbogus, 0), 958145256Sjkoshy __P4MASK(bogus, 1), 959145256Sjkoshy NULLMASK 960145256Sjkoshy}; 961145256Sjkoshy 962145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 963145256Sjkoshy __P4MASK(tagloads, 1), 964145256Sjkoshy __P4MASK(tagstores, 2), 965145256Sjkoshy NULLMASK 966145256Sjkoshy}; 967145256Sjkoshy 968145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 969145256Sjkoshy __P4MASK(mmnp, 0), 970145256Sjkoshy __P4MASK(mmnm, 1), 971145256Sjkoshy __P4MASK(mmtp, 2), 972145256Sjkoshy __P4MASK(mmtm, 3), 973145256Sjkoshy NULLMASK 974145256Sjkoshy}; 975145256Sjkoshy 976145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 977145256Sjkoshy __P4MASK(nbogus, 0), 978145256Sjkoshy NULLMASK 979145256Sjkoshy}; 980145256Sjkoshy 981145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 982145256Sjkoshy __P4MASK(fpsu, 0), 983145256Sjkoshy __P4MASK(fpso, 1), 984145256Sjkoshy __P4MASK(poao, 2), 985145256Sjkoshy __P4MASK(poau, 3), 986145256Sjkoshy __P4MASK(prea, 4), 987145256Sjkoshy NULLMASK 988145256Sjkoshy}; 989145256Sjkoshy 990145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 991145256Sjkoshy __P4MASK(clear, 0), 992145256Sjkoshy __P4MASK(moclear, 2), 993145256Sjkoshy __P4MASK(smclear, 3), 994145256Sjkoshy NULLMASK 995145256Sjkoshy}; 996145256Sjkoshy 997145256Sjkoshy/* P4 event parser */ 998145256Sjkoshystatic int 999145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1000145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1001145256Sjkoshy{ 1002145256Sjkoshy 1003145256Sjkoshy char *e, *p, *q; 1004145256Sjkoshy int count, has_tag, has_busreqtype, n; 1005145256Sjkoshy uint32_t evmask, cccractivemask; 1006145256Sjkoshy const struct pmc_masks *pm, *pmask; 1007145256Sjkoshy 1008145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1009147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1010147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1011145256Sjkoshy 1012145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1013145256Sjkoshy /* TSC must not be further qualified */ 1014145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1015145256Sjkoshy return -1; 1016145256Sjkoshy return 0; 1017145256Sjkoshy } 1018145256Sjkoshy 1019145256Sjkoshy pmask = NULL; 1020145256Sjkoshy evmask = 0; 1021145256Sjkoshy cccractivemask = 0x3; 1022145256Sjkoshy has_tag = has_busreqtype = 0; 1023145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1024145256Sjkoshy 1025145256Sjkoshy#define __P4SETMASK(M) do { \ 1026145256Sjkoshy pmask = p4_mask_##M; \ 1027145256Sjkoshy} while (0) 1028145256Sjkoshy 1029145256Sjkoshy switch (pe) { 1030145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1031145256Sjkoshy __P4SETMASK(tcdm); 1032145256Sjkoshy break; 1033145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1034145256Sjkoshy __P4SETMASK(bfr); 1035145256Sjkoshy break; 1036145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1037145256Sjkoshy __P4SETMASK(ir); 1038145256Sjkoshy break; 1039145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1040145256Sjkoshy __P4SETMASK(memcan); 1041145256Sjkoshy break; 1042145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1043145256Sjkoshy __P4SETMASK(memcomp); 1044145256Sjkoshy break; 1045145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1046145256Sjkoshy __P4SETMASK(lpr); 1047145256Sjkoshy break; 1048145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1049145256Sjkoshy __P4SETMASK(spr); 1050145256Sjkoshy break; 1051145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1052145256Sjkoshy __P4SETMASK(mlr); 1053145256Sjkoshy break; 1054145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1055145256Sjkoshy __P4SETMASK(pwt); 1056145256Sjkoshy break; 1057145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1058145256Sjkoshy __P4SETMASK(bcr); 1059145256Sjkoshy break; 1060145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1061145256Sjkoshy __P4SETMASK(ia); 1062145256Sjkoshy has_busreqtype = 1; 1063145256Sjkoshy break; 1064145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1065145256Sjkoshy __P4SETMASK(iae); 1066145256Sjkoshy has_busreqtype = 1; 1067145256Sjkoshy break; 1068145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1069145256Sjkoshy __P4SETMASK(fda); 1070145256Sjkoshy break; 1071145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1072145256Sjkoshy __P4SETMASK(ba); 1073145256Sjkoshy break; 1074145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1075145256Sjkoshy __P4SETMASK(sia); 1076145256Sjkoshy break; 1077145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1078145256Sjkoshy __P4SETMASK(psu); 1079145256Sjkoshy break; 1080145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1081145256Sjkoshy __P4SETMASK(pdu); 1082145256Sjkoshy break; 1083145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1084145256Sjkoshy __P4SETMASK(ssu); 1085145256Sjkoshy break; 1086145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1087145256Sjkoshy __P4SETMASK(sdu); 1088145256Sjkoshy break; 1089145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1090145256Sjkoshy __P4SETMASK(64bmu); 1091145256Sjkoshy break; 1092145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1093145256Sjkoshy __P4SETMASK(128bmu); 1094145256Sjkoshy break; 1095145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1096145256Sjkoshy __P4SETMASK(xfu); 1097145256Sjkoshy break; 1098145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1099145256Sjkoshy __P4SETMASK(xsmu); 1100145256Sjkoshy break; 1101145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1102145256Sjkoshy __P4SETMASK(gpe); 1103145256Sjkoshy break; 1104145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1105145256Sjkoshy __P4SETMASK(tmx); 1106145256Sjkoshy break; 1107145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1108145256Sjkoshy __P4SETMASK(uqw); 1109145256Sjkoshy break; 1110145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1111145256Sjkoshy __P4SETMASK(rmbt); 1112145256Sjkoshy break; 1113145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1114145256Sjkoshy __P4SETMASK(rbt); 1115145256Sjkoshy break; 1116145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1117145256Sjkoshy __P4SETMASK(rs); 1118145256Sjkoshy break; 1119145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1120145256Sjkoshy __P4SETMASK(wb); 1121145256Sjkoshy break; 1122145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1123145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1124145256Sjkoshy case PMC_EV_P4_BNR: 1125145256Sjkoshy case PMC_EV_P4_SNOOP: 1126145256Sjkoshy case PMC_EV_P4_RESPONSE: 1127145256Sjkoshy break; 1128145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1129145256Sjkoshy __P4SETMASK(fee); 1130145256Sjkoshy break; 1131145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1132145256Sjkoshy __P4SETMASK(ee); 1133145256Sjkoshy break; 1134145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1135145256Sjkoshy __P4SETMASK(re); 1136145256Sjkoshy break; 1137145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1138145256Sjkoshy __P4SETMASK(insret); 1139145256Sjkoshy break; 1140145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1141145256Sjkoshy __P4SETMASK(ur); 1142145256Sjkoshy break; 1143145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1144145256Sjkoshy __P4SETMASK(ut); 1145145256Sjkoshy break; 1146145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1147145256Sjkoshy __P4SETMASK(br); 1148145256Sjkoshy break; 1149145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1150145256Sjkoshy __P4SETMASK(mbr); 1151145256Sjkoshy break; 1152145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1153145256Sjkoshy __P4SETMASK(xa); 1154145256Sjkoshy break; 1155145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1156145256Sjkoshy __P4SETMASK(machclr); 1157145256Sjkoshy break; 1158145256Sjkoshy default: 1159145256Sjkoshy return -1; 1160145256Sjkoshy } 1161145256Sjkoshy 1162145256Sjkoshy /* process additional flags */ 1163145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1164145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1165145256Sjkoshy q = strchr(p, '='); 1166145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1167145256Sjkoshy return -1; 1168145256Sjkoshy 1169145256Sjkoshy if (strcmp(q, P4_KW_ACTIVE_NONE) == 0) 1170145256Sjkoshy cccractivemask = 0x0; 1171145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1172145256Sjkoshy cccractivemask = 0x1; 1173145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_BOTH) == 0) 1174145256Sjkoshy cccractivemask = 0x2; 1175145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_ANY) == 0) 1176145256Sjkoshy cccractivemask = 0x3; 1177145256Sjkoshy else 1178145256Sjkoshy return -1; 1179145256Sjkoshy 1180145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1181145256Sjkoshy if (has_busreqtype == 0) 1182145256Sjkoshy return -1; 1183145256Sjkoshy 1184145256Sjkoshy q = strchr(p, '='); 1185145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1186145256Sjkoshy return -1; 1187145256Sjkoshy 1188145256Sjkoshy count = strtol(q, &e, 0); 1189145256Sjkoshy if (e == q || *e != '\0') 1190145256Sjkoshy return -1; 1191145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1192145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1193145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1194145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1195145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1196145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1197145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1198145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1199145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1200145256Sjkoshy return -1; 1201145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1202145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1203145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1204145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1205145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1206145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1207145256Sjkoshy if (has_tag == 0) 1208145256Sjkoshy return -1; 1209145256Sjkoshy 1210145256Sjkoshy q = strchr(p, '='); 1211145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1212145256Sjkoshy return -1; 1213145256Sjkoshy 1214145256Sjkoshy count = strtol(q, &e, 0); 1215145256Sjkoshy if (e == q || *e != '\0') 1216145256Sjkoshy return -1; 1217145256Sjkoshy 1218145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1219147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1220145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1221145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1222145256Sjkoshy q = strchr(p, '='); 1223145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1224145256Sjkoshy return -1; 1225145256Sjkoshy 1226145256Sjkoshy count = strtol(q, &e, 0); 1227145256Sjkoshy if (e == q || *e != '\0') 1228145256Sjkoshy return -1; 1229145256Sjkoshy 1230145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1231147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1232147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1233147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1234147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1235145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1236145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1237145256Sjkoshy else 1238145256Sjkoshy return -1; 1239145256Sjkoshy } 1240145256Sjkoshy 1241145256Sjkoshy /* other post processing */ 1242145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1243145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1244145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1245145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1246145256Sjkoshy 1247145256Sjkoshy /* fill in thread activity mask */ 1248147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1249145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1250145256Sjkoshy 1251145256Sjkoshy if (evmask) 1252145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1253145256Sjkoshy 1254145256Sjkoshy switch (pe) { 1255145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1256145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1257145256Sjkoshy (evmask & 0x18) == 0x18) 1258145256Sjkoshy return -1; /* can't have own+other bits together */ 1259145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1260145256Sjkoshy evmask = 0x1D; 1261145256Sjkoshy break; 1262145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1263145256Sjkoshy /* only one bit is allowed to be set */ 1264145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1265145256Sjkoshy return -1; 1266145256Sjkoshy if (evmask == 0) { 1267145256Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1268145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1269145256Sjkoshy } 1270145256Sjkoshy break; 1271145256Sjkoshy default: 1272145256Sjkoshy if (evmask == 0 && pmask) { 1273145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1274145256Sjkoshy evmask |= pm->pm_value; 1275145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1276145256Sjkoshy } 1277145256Sjkoshy } 1278145256Sjkoshy 1279147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1280147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1281145256Sjkoshy 1282145256Sjkoshy return 0; 1283145256Sjkoshy} 1284145256Sjkoshy 1285145256Sjkoshy/* 1286147191Sjkoshy * Pentium style PMCs 1287147191Sjkoshy */ 1288147191Sjkoshy 1289147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1290147191Sjkoshy EV_ALIAS("cycles", "tsc"), 1291147191Sjkoshy EV_ALIAS(NULL, NULL) 1292147191Sjkoshy}; 1293147191Sjkoshy 1294147191Sjkoshystatic int 1295147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1296147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1297147191Sjkoshy{ 1298147191Sjkoshy return -1 || pe || ctrspec || pmc_config; /* shut up gcc */ 1299147191Sjkoshy} 1300147191Sjkoshy 1301147191Sjkoshy/* 1302145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1303145256Sjkoshy * and Pentium M CPUs. 1304145256Sjkoshy */ 1305145256Sjkoshy 1306145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1307145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1308145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1309145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1310145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1311145351Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-ifetch-miss"), 1312145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1313145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1314145351Sjkoshy EV_ALIAS(NULL, NULL) 1315145256Sjkoshy}; 1316145256Sjkoshy 1317145256Sjkoshy#define P6_KW_CMASK "cmask" 1318145256Sjkoshy#define P6_KW_EDGE "edge" 1319145256Sjkoshy#define P6_KW_INV "inv" 1320145256Sjkoshy#define P6_KW_OS "os" 1321145256Sjkoshy#define P6_KW_UMASK "umask" 1322145256Sjkoshy#define P6_KW_USR "usr" 1323145256Sjkoshy 1324145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1325145256Sjkoshy PMCMASK(m, 0x01), 1326145256Sjkoshy PMCMASK(e, 0x02), 1327145256Sjkoshy PMCMASK(s, 0x04), 1328145256Sjkoshy PMCMASK(i, 0x08), 1329145256Sjkoshy NULLMASK 1330145256Sjkoshy}; 1331145256Sjkoshy 1332145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1333145256Sjkoshy PMCMASK(m, 0x01), 1334145256Sjkoshy PMCMASK(e, 0x02), 1335145256Sjkoshy PMCMASK(s, 0x04), 1336145256Sjkoshy PMCMASK(i, 0x08), 1337145256Sjkoshy PMCMASK(nonhw, 0x00), 1338145256Sjkoshy PMCMASK(hw, 0x10), 1339145256Sjkoshy PMCMASK(both, 0x30), 1340145256Sjkoshy NULLMASK 1341145256Sjkoshy}; 1342145256Sjkoshy 1343145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1344145256Sjkoshy PMCMASK(nonhw, 0x00), 1345145256Sjkoshy PMCMASK(hw, 0x10), 1346145256Sjkoshy PMCMASK(both, 0x30), 1347145256Sjkoshy NULLMASK 1348145256Sjkoshy}; 1349145256Sjkoshy 1350145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1351145256Sjkoshy PMCMASK(self, 0x00), 1352145256Sjkoshy PMCMASK(any, 0x20), 1353145256Sjkoshy NULLMASK 1354145256Sjkoshy}; 1355145256Sjkoshy 1356145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1357145256Sjkoshy PMCMASK(nta, 0x00), 1358145256Sjkoshy PMCMASK(t1, 0x01), 1359145256Sjkoshy PMCMASK(t2, 0x02), 1360145256Sjkoshy PMCMASK(wos, 0x03), 1361145256Sjkoshy NULLMASK 1362145256Sjkoshy}; 1363145256Sjkoshy 1364145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1365145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1366145256Sjkoshy PMCMASK(scalar, 0x01), 1367145256Sjkoshy NULLMASK 1368145256Sjkoshy}; 1369145256Sjkoshy 1370145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1371145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1372145256Sjkoshy PMCMASK(packed-shift, 0x02), 1373145256Sjkoshy PMCMASK(pack, 0x04), 1374145256Sjkoshy PMCMASK(unpack, 0x08), 1375145256Sjkoshy PMCMASK(packed-logical, 0x10), 1376145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1377145256Sjkoshy NULLMASK 1378145256Sjkoshy}; 1379145256Sjkoshy 1380145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1381145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1382145256Sjkoshy PMCMASK(fptommx, 0x01), 1383145256Sjkoshy NULLMASK 1384145256Sjkoshy}; 1385145256Sjkoshy 1386145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 1387145256Sjkoshy PMCMASK(es, 0x01), 1388145256Sjkoshy PMCMASK(ds, 0x02), 1389145256Sjkoshy PMCMASK(fs, 0x04), 1390145256Sjkoshy PMCMASK(gs, 0x08), 1391145256Sjkoshy NULLMASK 1392145256Sjkoshy}; 1393145256Sjkoshy 1394145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 1395145256Sjkoshy PMCMASK(all, 0x00), 1396145256Sjkoshy PMCMASK(freq, 0x02), 1397145256Sjkoshy NULLMASK 1398145256Sjkoshy}; 1399145256Sjkoshy 1400145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1401145256Sjkoshy PMCMASK(all, 0x00), 1402145256Sjkoshy PMCMASK(loadop, 0x01), 1403145256Sjkoshy PMCMASK(stdsta, 0x02), 1404145256Sjkoshy NULLMASK 1405145256Sjkoshy}; 1406145256Sjkoshy 1407145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1408145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1409145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1410145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1411145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1412145256Sjkoshy NULLMASK 1413145256Sjkoshy}; 1414145256Sjkoshy 1415145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1416145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1417145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1418145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1419145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1420145256Sjkoshy NULLMASK 1421145256Sjkoshy}; 1422145256Sjkoshy 1423145256Sjkoshy/* P6 event parser */ 1424145256Sjkoshystatic int 1425145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1426145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1427145256Sjkoshy{ 1428145256Sjkoshy char *e, *p, *q; 1429145256Sjkoshy uint32_t evmask; 1430145256Sjkoshy int count, n; 1431145256Sjkoshy const struct pmc_masks *pm, *pmask; 1432145256Sjkoshy 1433145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1434147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 1435145256Sjkoshy 1436145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1437145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1438145256Sjkoshy return -1; 1439145256Sjkoshy return 0; 1440145256Sjkoshy } 1441145256Sjkoshy 1442145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1443145256Sjkoshy evmask = 0; 1444145256Sjkoshy 1445145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1446145256Sjkoshy 1447145256Sjkoshy switch(pe) { 1448145256Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1449145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1450145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 1451145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 1452145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1453145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1454145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1455145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1456145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1457145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1458145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1459145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1460145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1461145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1462145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1463145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1464145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1465145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1466145256Sjkoshy P6MASKSET(any); break; 1467145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1468145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1469145256Sjkoshy P6MASKSET(ekp); break; 1470145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1471145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1472145256Sjkoshy P6MASKSET(pps); break; 1473145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 1474145256Sjkoshy P6MASKSET(mite); break; 1475145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1476145256Sjkoshy P6MASKSET(fmt); break; 1477145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 1478145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 1479145256Sjkoshy P6MASKSET(sr); break; 1480145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1481145256Sjkoshy P6MASKSET(eet); break; 1482145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1483145256Sjkoshy P6MASKSET(efur); break; 1484145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1485145256Sjkoshy P6MASKSET(essir); break; 1486145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1487145256Sjkoshy P6MASKSET(esscir); break; 1488145256Sjkoshy default: 1489145256Sjkoshy pmask = NULL; 1490145256Sjkoshy break; 1491145256Sjkoshy } 1492145256Sjkoshy 1493145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 1494145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 1495145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 1496145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 1497145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 1498145256Sjkoshy P6MASKSET(mesihw); 1499145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 1500145256Sjkoshy P6MASKSET(hw); 1501145256Sjkoshy } 1502145256Sjkoshy 1503145256Sjkoshy /* Parse additional modifiers if present */ 1504145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1505145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 1506145256Sjkoshy q = strchr(p, '='); 1507145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1508145256Sjkoshy return -1; 1509145256Sjkoshy count = strtol(q, &e, 0); 1510145256Sjkoshy if (e == q || *e != '\0') 1511145256Sjkoshy return -1; 1512145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1513147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1514147191Sjkoshy P6_EVSEL_TO_CMASK(count); 1515145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 1516145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1517145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 1518145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1519145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 1520145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1521145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 1522145256Sjkoshy evmask = 0; 1523145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1524145256Sjkoshy return -1; 1525145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 1526145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 1527145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 1528145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 1529145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 1530145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 1531145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 1532145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 1533145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 1534145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 1535145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 1536145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 1537145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 1538145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 1539145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 1540145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 1541145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 1542145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 1543145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 1544145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 1545145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 1546145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 1547145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 1548145256Sjkoshy && (n > 1)) 1549145256Sjkoshy return -1; /* only one mask keyword allowed */ 1550145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1551145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 1552145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1553145256Sjkoshy } else 1554145256Sjkoshy return -1; 1555145256Sjkoshy } 1556145256Sjkoshy 1557145256Sjkoshy /* post processing */ 1558145256Sjkoshy switch (pe) { 1559145256Sjkoshy 1560145256Sjkoshy /* 1561145256Sjkoshy * The following events default to an evmask of 0 1562145256Sjkoshy */ 1563145256Sjkoshy 1564145256Sjkoshy /* default => 'self' */ 1565145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1566145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1567145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1568145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1569145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1570145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1571145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1572145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1573145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1574145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1575145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1576145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1577145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1578145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1579145256Sjkoshy 1580145256Sjkoshy /* default => 'nta' */ 1581145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1582145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1583145256Sjkoshy 1584145256Sjkoshy /* default => 'packed and scalar' */ 1585145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1586145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1587145256Sjkoshy 1588145256Sjkoshy /* default => 'mmx to fp transitions' */ 1589145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1590145256Sjkoshy 1591145256Sjkoshy /* default => 'SSE Packed Single' */ 1592145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1593145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1594145256Sjkoshy 1595145256Sjkoshy /* default => 'all fused micro-ops' */ 1596145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1597145256Sjkoshy 1598145256Sjkoshy /* default => 'all transitions' */ 1599145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1600145256Sjkoshy break; 1601145256Sjkoshy 1602145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 1603145256Sjkoshy evmask = 0x0F; /* only value allowed */ 1604145256Sjkoshy break; 1605145256Sjkoshy 1606145256Sjkoshy default: 1607145256Sjkoshy 1608145256Sjkoshy /* 1609145256Sjkoshy * For all other events, set the default event mask 1610145256Sjkoshy * to a logical OR of all the allowed event mask bits. 1611145256Sjkoshy */ 1612145256Sjkoshy 1613145256Sjkoshy if (evmask == 0 && pmask) { 1614145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1615145256Sjkoshy evmask |= pm->pm_value; 1616145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1617145256Sjkoshy } 1618145256Sjkoshy 1619145256Sjkoshy break; 1620145256Sjkoshy } 1621145256Sjkoshy 1622145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1623147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1624147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 1625145256Sjkoshy 1626145256Sjkoshy return 0; 1627145256Sjkoshy} 1628145256Sjkoshy 1629147191Sjkoshy#endif 1630147191Sjkoshy 1631145256Sjkoshy/* 1632147191Sjkoshy * API entry points 1633145256Sjkoshy */ 1634145256Sjkoshy 1635145256Sjkoshy 1636147191Sjkoshyint 1637147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 1638147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 1639145256Sjkoshy{ 1640147191Sjkoshy int retval; 1641147191Sjkoshy enum pmc_event pe; 1642147191Sjkoshy char *r, *spec_copy; 1643147191Sjkoshy const char *ctrname; 1644147191Sjkoshy const struct pmc_event_alias *p; 1645147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 1646145256Sjkoshy 1647147191Sjkoshy spec_copy = NULL; 1648147191Sjkoshy retval = -1; 1649145256Sjkoshy 1650147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 1651147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 1652147191Sjkoshy errno = EINVAL; 1653147191Sjkoshy goto out; 1654147191Sjkoshy } 1655145256Sjkoshy 1656147191Sjkoshy /* replace an event alias with the canonical event specifier */ 1657147191Sjkoshy if (pmc_mdep_event_aliases) 1658147191Sjkoshy for (p = pmc_mdep_event_aliases; p->pm_alias; p++) 1659147191Sjkoshy if (!strcmp(ctrspec, p->pm_alias)) { 1660147191Sjkoshy spec_copy = strdup(p->pm_spec); 1661147191Sjkoshy break; 1662147191Sjkoshy } 1663145256Sjkoshy 1664147191Sjkoshy if (spec_copy == NULL) 1665147191Sjkoshy spec_copy = strdup(ctrspec); 1666145256Sjkoshy 1667147191Sjkoshy r = spec_copy; 1668147191Sjkoshy ctrname = strsep(&r, ","); 1669145256Sjkoshy 1670147191Sjkoshy /* look for the given counter name */ 1671145256Sjkoshy 1672147191Sjkoshy for (pe = PMC_EVENT_FIRST; pe < (PMC_EVENT_LAST+1); pe++) 1673147191Sjkoshy if (!strcmp(ctrname, pmc_event_table[pe].pm_ev_name)) 1674147191Sjkoshy break; 1675145256Sjkoshy 1676147191Sjkoshy if (pe > PMC_EVENT_LAST) { 1677147191Sjkoshy errno = EINVAL; 1678147191Sjkoshy goto out; 1679147191Sjkoshy } 1680145256Sjkoshy 1681147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 1682147191Sjkoshy pmc_config.pm_ev = pmc_event_table[pe].pm_ev_code; 1683147191Sjkoshy pmc_config.pm_class = pmc_event_table[pe].pm_ev_class; 1684147191Sjkoshy pmc_config.pm_cpu = cpu; 1685147191Sjkoshy pmc_config.pm_mode = mode; 1686147191Sjkoshy pmc_config.pm_flags = flags; 1687145256Sjkoshy 1688147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 1689147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 1690145256Sjkoshy 1691147191Sjkoshy if (pmc_mdep_allocate_pmc(pe, r, &pmc_config) < 0) { 1692147191Sjkoshy errno = EINVAL; 1693147191Sjkoshy goto out; 1694147191Sjkoshy } 1695145256Sjkoshy 1696147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 1697147191Sjkoshy goto out; 1698145256Sjkoshy 1699147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 1700145256Sjkoshy 1701147191Sjkoshy retval = 0; 1702145256Sjkoshy 1703147191Sjkoshy out: 1704147191Sjkoshy if (spec_copy) 1705147191Sjkoshy free(spec_copy); 1706145256Sjkoshy 1707147191Sjkoshy return retval; 1708147191Sjkoshy} 1709145256Sjkoshy 1710147191Sjkoshyint 1711147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 1712147191Sjkoshy{ 1713147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 1714145256Sjkoshy 1715147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 1716147191Sjkoshy pmc_attach_args.pm_pid = pid; 1717145256Sjkoshy 1718147191Sjkoshy return PMC_CALL(PMCATTACH, &pmc_attach_args); 1719147191Sjkoshy} 1720145256Sjkoshy 1721147191Sjkoshyint 1722147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 1723147191Sjkoshy{ 1724147191Sjkoshy unsigned int i; 1725147191Sjkoshy enum pmc_class cl; 1726145256Sjkoshy 1727147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 1728147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 1729147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 1730147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 1731147191Sjkoshy return 0; 1732147191Sjkoshy } 1733147191Sjkoshy return EINVAL; 1734147191Sjkoshy} 1735145256Sjkoshy 1736147191Sjkoshyint 1737147191Sjkoshypmc_configure_logfile(int fd) 1738147191Sjkoshy{ 1739147191Sjkoshy struct pmc_op_configurelog cla; 1740145256Sjkoshy 1741147191Sjkoshy cla.pm_logfd = fd; 1742147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 1743147191Sjkoshy return -1; 1744147191Sjkoshy return 0; 1745147191Sjkoshy} 1746145256Sjkoshy 1747147191Sjkoshyint 1748147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 1749147191Sjkoshy{ 1750147191Sjkoshy if (pmc_syscall == -1) { 1751147191Sjkoshy errno = ENXIO; 1752147191Sjkoshy return -1; 1753147191Sjkoshy } 1754145256Sjkoshy 1755147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 1756147191Sjkoshy *pci = (struct pmc_cpuinfo *) &cpu_info; 1757147191Sjkoshy return 0; 1758147191Sjkoshy} 1759145256Sjkoshy 1760147191Sjkoshyint 1761147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 1762147191Sjkoshy{ 1763147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 1764145256Sjkoshy 1765147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 1766147191Sjkoshy pmc_detach_args.pm_pid = pid; 1767147191Sjkoshy 1768147191Sjkoshy return PMC_CALL(PMCDETACH, &pmc_detach_args); 1769147191Sjkoshy} 1770147191Sjkoshy 1771147191Sjkoshyint 1772147191Sjkoshypmc_disable(int cpu, int pmc) 1773145256Sjkoshy{ 1774147191Sjkoshy struct pmc_op_pmcadmin ssa; 1775145256Sjkoshy 1776147191Sjkoshy ssa.pm_cpu = cpu; 1777147191Sjkoshy ssa.pm_pmc = pmc; 1778147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 1779147191Sjkoshy return PMC_CALL(PMCADMIN, &ssa); 1780147191Sjkoshy} 1781145256Sjkoshy 1782147191Sjkoshyint 1783147191Sjkoshypmc_enable(int cpu, int pmc) 1784147191Sjkoshy{ 1785147191Sjkoshy struct pmc_op_pmcadmin ssa; 1786145256Sjkoshy 1787147191Sjkoshy ssa.pm_cpu = cpu; 1788147191Sjkoshy ssa.pm_pmc = pmc; 1789147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 1790147191Sjkoshy return PMC_CALL(PMCADMIN, &ssa); 1791147191Sjkoshy} 1792145256Sjkoshy 1793147191Sjkoshy/* 1794147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 1795147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 1796147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 1797147191Sjkoshy * the number of event name pointers returned. 1798147191Sjkoshy * 1799147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 1800147191Sjkoshy * is responsible for freeing this space when done. 1801147191Sjkoshy */ 1802145256Sjkoshy 1803147191Sjkoshyint 1804147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 1805147191Sjkoshy int *nevents) 1806147191Sjkoshy{ 1807147191Sjkoshy int count; 1808147191Sjkoshy const char **names; 1809147191Sjkoshy const struct pmc_event_descr *ev; 1810147191Sjkoshy 1811147191Sjkoshy switch (cl) 1812147191Sjkoshy { 1813147191Sjkoshy case PMC_CLASS_TSC: 1814147191Sjkoshy ev = &pmc_event_table[PMC_EV_TSC_TSC]; 1815147191Sjkoshy count = 1; 1816145256Sjkoshy break; 1817147191Sjkoshy case PMC_CLASS_K7: 1818147191Sjkoshy ev = &pmc_event_table[PMC_EV_K7_FIRST]; 1819147191Sjkoshy count = PMC_EV_K7_LAST - PMC_EV_K7_FIRST + 1; 1820145256Sjkoshy break; 1821147191Sjkoshy case PMC_CLASS_K8: 1822147191Sjkoshy ev = &pmc_event_table[PMC_EV_K8_FIRST]; 1823147191Sjkoshy count = PMC_EV_K8_LAST - PMC_EV_K8_FIRST + 1; 1824145256Sjkoshy break; 1825147191Sjkoshy case PMC_CLASS_P5: 1826147191Sjkoshy ev = &pmc_event_table[PMC_EV_P5_FIRST]; 1827147191Sjkoshy count = PMC_EV_P5_LAST - PMC_EV_P5_FIRST + 1; 1828145256Sjkoshy break; 1829147191Sjkoshy case PMC_CLASS_P6: 1830147191Sjkoshy ev = &pmc_event_table[PMC_EV_P6_FIRST]; 1831147191Sjkoshy count = PMC_EV_P6_LAST - PMC_EV_P6_FIRST + 1; 1832145256Sjkoshy break; 1833147191Sjkoshy case PMC_CLASS_P4: 1834147191Sjkoshy ev = &pmc_event_table[PMC_EV_P4_FIRST]; 1835147191Sjkoshy count = PMC_EV_P4_LAST - PMC_EV_P4_FIRST + 1; 1836145256Sjkoshy break; 1837145256Sjkoshy default: 1838147191Sjkoshy errno = EINVAL; 1839147191Sjkoshy return -1; 1840145256Sjkoshy } 1841145256Sjkoshy 1842147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 1843147191Sjkoshy return -1; 1844145256Sjkoshy 1845147191Sjkoshy *eventnames = names; 1846147191Sjkoshy *nevents = count; 1847145256Sjkoshy 1848147191Sjkoshy for (;count--; ev++, names++) 1849147191Sjkoshy *names = ev->pm_ev_name; 1850147191Sjkoshy return 0; 1851147191Sjkoshy} 1852145256Sjkoshy 1853147191Sjkoshyint 1854147191Sjkoshypmc_flush_logfile(void) 1855147191Sjkoshy{ 1856147191Sjkoshy return PMC_CALL(FLUSHLOG,0); 1857147191Sjkoshy} 1858145256Sjkoshy 1859147191Sjkoshyint 1860147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 1861147191Sjkoshy{ 1862147191Sjkoshy struct pmc_op_getdriverstats gms; 1863145256Sjkoshy 1864147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 1865147191Sjkoshy return -1; 1866145256Sjkoshy 1867147191Sjkoshy /* copy out fields in the current userland<->library interface */ 1868147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 1869147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 1870147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 1871147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 1872147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 1873147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 1874147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 1875147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 1876145256Sjkoshy 1877147191Sjkoshy return 0; 1878147191Sjkoshy} 1879145256Sjkoshy 1880147191Sjkoshyint 1881147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 1882147191Sjkoshy{ 1883147191Sjkoshy struct pmc_op_getmsr gm; 1884147191Sjkoshy 1885147191Sjkoshy gm.pm_pmcid = pmc; 1886147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 1887147191Sjkoshy return -1; 1888147191Sjkoshy *msr = gm.pm_msr; 1889145256Sjkoshy return 0; 1890145256Sjkoshy} 1891145256Sjkoshy 1892145256Sjkoshyint 1893145256Sjkoshypmc_init(void) 1894145256Sjkoshy{ 1895145256Sjkoshy int error, pmc_mod_id; 1896145256Sjkoshy uint32_t abi_version; 1897145256Sjkoshy struct module_stat pmc_modstat; 1898145256Sjkoshy 1899145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 1900145256Sjkoshy return 0; 1901145256Sjkoshy 1902145256Sjkoshy /* retrieve the system call number from the KLD */ 1903145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 1904145256Sjkoshy return -1; 1905145256Sjkoshy 1906145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 1907145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 1908145256Sjkoshy return -1; 1909145256Sjkoshy 1910145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 1911145256Sjkoshy 1912147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 1913147191Sjkoshy abi_version = PMC_VERSION; 1914145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 1915145256Sjkoshy return (pmc_syscall = -1); 1916145256Sjkoshy 1917147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 1918147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 1919145256Sjkoshy errno = EPROGMISMATCH; 1920145256Sjkoshy return (pmc_syscall = -1); 1921145256Sjkoshy } 1922145256Sjkoshy 1923145256Sjkoshy if (PMC_CALL(GETCPUINFO, &cpu_info) < 0) 1924145256Sjkoshy return (pmc_syscall = -1); 1925145256Sjkoshy 1926145256Sjkoshy /* set parser pointer */ 1927145256Sjkoshy switch (cpu_info.pm_cputype) { 1928145340Smarcel#if defined(__i386__) 1929145256Sjkoshy case PMC_CPU_AMD_K7: 1930145256Sjkoshy pmc_mdep_event_aliases = k7_aliases; 1931145256Sjkoshy pmc_mdep_allocate_pmc = k7_allocate_pmc; 1932145256Sjkoshy break; 1933145256Sjkoshy case PMC_CPU_INTEL_P5: 1934145256Sjkoshy pmc_mdep_event_aliases = p5_aliases; 1935145256Sjkoshy pmc_mdep_allocate_pmc = p5_allocate_pmc; 1936145256Sjkoshy break; 1937145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 1938145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 1939145256Sjkoshy case PMC_CPU_INTEL_PIII: 1940145256Sjkoshy case PMC_CPU_INTEL_PM: 1941145256Sjkoshy pmc_mdep_event_aliases = p6_aliases; 1942145256Sjkoshy pmc_mdep_allocate_pmc = p6_allocate_pmc; 1943145256Sjkoshy break; 1944145256Sjkoshy case PMC_CPU_INTEL_PIV: 1945145256Sjkoshy pmc_mdep_event_aliases = p4_aliases; 1946145256Sjkoshy pmc_mdep_allocate_pmc = p4_allocate_pmc; 1947145256Sjkoshy break; 1948145340Smarcel#elif defined(__amd64__) 1949145256Sjkoshy case PMC_CPU_AMD_K8: 1950145256Sjkoshy pmc_mdep_event_aliases = k8_aliases; 1951145256Sjkoshy pmc_mdep_allocate_pmc = k8_allocate_pmc; 1952145256Sjkoshy break; 1953145256Sjkoshy#endif 1954145256Sjkoshy 1955145256Sjkoshy default: 1956145256Sjkoshy /* 1957145256Sjkoshy * Some kind of CPU this version of the library knows nothing 1958145256Sjkoshy * about. This shouldn't happen since the abi version check 1959145256Sjkoshy * should have caught this. 1960145256Sjkoshy */ 1961145256Sjkoshy errno = ENXIO; 1962145256Sjkoshy return (pmc_syscall = -1); 1963145256Sjkoshy } 1964145256Sjkoshy 1965145256Sjkoshy return 0; 1966145256Sjkoshy} 1967145256Sjkoshy 1968147191Sjkoshyconst char * 1969147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 1970145256Sjkoshy{ 1971147191Sjkoshy int i; 1972145256Sjkoshy 1973147191Sjkoshy /* 1974147191Sjkoshy * 'cap' should have a single bit set and should be in 1975147191Sjkoshy * range. 1976147191Sjkoshy */ 1977145256Sjkoshy 1978147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 1979147191Sjkoshy cap > PMC_CAP_LAST) { 1980145256Sjkoshy errno = EINVAL; 1981147191Sjkoshy return NULL; 1982145256Sjkoshy } 1983145256Sjkoshy 1984147191Sjkoshy i = ffs(cap); 1985145256Sjkoshy 1986147191Sjkoshy return pmc_capability_names[i - 1]; 1987147191Sjkoshy} 1988145256Sjkoshy 1989147191Sjkoshyconst char * 1990147191Sjkoshypmc_name_of_class(enum pmc_class pc) 1991147191Sjkoshy{ 1992147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 1993147191Sjkoshy pc <= PMC_CLASS_LAST) 1994147191Sjkoshy return pmc_class_names[pc]; 1995145256Sjkoshy 1996147191Sjkoshy errno = EINVAL; 1997147191Sjkoshy return NULL; 1998147191Sjkoshy} 1999145256Sjkoshy 2000147191Sjkoshyconst char * 2001147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 2002147191Sjkoshy{ 2003147191Sjkoshy if ((int) cp >= PMC_CPU_FIRST && 2004147191Sjkoshy cp <= PMC_CPU_LAST) 2005147191Sjkoshy return pmc_cputype_names[cp]; 2006147191Sjkoshy errno = EINVAL; 2007147191Sjkoshy return NULL; 2008147191Sjkoshy} 2009145256Sjkoshy 2010147191Sjkoshyconst char * 2011147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 2012147191Sjkoshy{ 2013147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 2014147191Sjkoshy pd <= PMC_DISP_LAST) 2015147191Sjkoshy return pmc_disposition_names[pd]; 2016145256Sjkoshy 2017147191Sjkoshy errno = EINVAL; 2018147191Sjkoshy return NULL; 2019147191Sjkoshy} 2020145256Sjkoshy 2021147191Sjkoshyconst char * 2022147191Sjkoshypmc_name_of_event(enum pmc_event pe) 2023147191Sjkoshy{ 2024147191Sjkoshy if ((int) pe >= PMC_EVENT_FIRST && 2025147191Sjkoshy pe <= PMC_EVENT_LAST) 2026147191Sjkoshy return pmc_event_table[pe].pm_ev_name; 2027145256Sjkoshy 2028147191Sjkoshy errno = EINVAL; 2029147191Sjkoshy return NULL; 2030147191Sjkoshy} 2031145256Sjkoshy 2032147191Sjkoshyconst char * 2033147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 2034147191Sjkoshy{ 2035147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 2036147191Sjkoshy pm <= PMC_MODE_LAST) 2037147191Sjkoshy return pmc_mode_names[pm]; 2038145256Sjkoshy 2039147191Sjkoshy errno = EINVAL; 2040147191Sjkoshy return NULL; 2041147191Sjkoshy} 2042145256Sjkoshy 2043147191Sjkoshyconst char * 2044147191Sjkoshypmc_name_of_state(enum pmc_state ps) 2045147191Sjkoshy{ 2046147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 2047147191Sjkoshy ps <= PMC_STATE_LAST) 2048147191Sjkoshy return pmc_state_names[ps]; 2049145256Sjkoshy 2050147191Sjkoshy errno = EINVAL; 2051147191Sjkoshy return NULL; 2052145256Sjkoshy} 2053145256Sjkoshy 2054145256Sjkoshyint 2055147191Sjkoshypmc_ncpu(void) 2056145256Sjkoshy{ 2057147191Sjkoshy if (pmc_syscall == -1) { 2058147191Sjkoshy errno = ENXIO; 2059147191Sjkoshy return -1; 2060147191Sjkoshy } 2061145256Sjkoshy 2062147191Sjkoshy return cpu_info.pm_ncpu; 2063145256Sjkoshy} 2064145256Sjkoshy 2065145256Sjkoshyint 2066147191Sjkoshypmc_npmc(int cpu) 2067145256Sjkoshy{ 2068147191Sjkoshy if (pmc_syscall == -1) { 2069147191Sjkoshy errno = ENXIO; 2070147191Sjkoshy return -1; 2071147191Sjkoshy } 2072145256Sjkoshy 2073147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 2074147191Sjkoshy errno = EINVAL; 2075147191Sjkoshy return -1; 2076147191Sjkoshy } 2077145256Sjkoshy 2078147191Sjkoshy return cpu_info.pm_npmc; 2079145256Sjkoshy} 2080145256Sjkoshy 2081145256Sjkoshyint 2082147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 2083145256Sjkoshy{ 2084147191Sjkoshy int nbytes, npmc; 2085147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 2086145256Sjkoshy 2087147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 2088147191Sjkoshy return -1; 2089145256Sjkoshy 2090147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 2091147191Sjkoshy npmc * sizeof(struct pmc_info); 2092145256Sjkoshy 2093147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 2094147191Sjkoshy return -1; 2095145256Sjkoshy 2096147191Sjkoshy pmci->pm_cpu = cpu; 2097145256Sjkoshy 2098147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 2099147191Sjkoshy free(pmci); 2100147191Sjkoshy return -1; 2101147191Sjkoshy } 2102145256Sjkoshy 2103147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 2104147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 2105147191Sjkoshy 2106147191Sjkoshy return 0; 2107145256Sjkoshy} 2108145256Sjkoshy 2109145256Sjkoshyint 2110145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 2111145256Sjkoshy{ 2112145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 2113145256Sjkoshy 2114145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 2115145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 2116145256Sjkoshy pmc_read_op.pm_value = -1; 2117145256Sjkoshy 2118145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 2119145256Sjkoshy return -1; 2120145256Sjkoshy 2121145256Sjkoshy *value = pmc_read_op.pm_value; 2122145256Sjkoshy 2123145256Sjkoshy return 0; 2124145256Sjkoshy} 2125145256Sjkoshy 2126145256Sjkoshyint 2127147191Sjkoshypmc_release(pmc_id_t pmc) 2128145256Sjkoshy{ 2129147191Sjkoshy struct pmc_op_simple pmc_release_args; 2130145256Sjkoshy 2131147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 2132145256Sjkoshy 2133147191Sjkoshy return PMC_CALL(PMCRELEASE, &pmc_release_args); 2134145256Sjkoshy} 2135145256Sjkoshy 2136145256Sjkoshyint 2137145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 2138145256Sjkoshy{ 2139145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 2140145256Sjkoshy 2141145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 2142145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 2143145256Sjkoshy pmc_rw_op.pm_value = newvalue; 2144145256Sjkoshy 2145145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 2146145256Sjkoshy return -1; 2147145256Sjkoshy 2148145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 2149145256Sjkoshy 2150145256Sjkoshy return 0; 2151145256Sjkoshy} 2152145256Sjkoshy 2153145256Sjkoshyint 2154145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 2155145256Sjkoshy{ 2156145256Sjkoshy struct pmc_op_pmcsetcount sc; 2157145256Sjkoshy 2158145256Sjkoshy sc.pm_pmcid = pmc; 2159145256Sjkoshy sc.pm_count = value; 2160145256Sjkoshy 2161145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 2162145256Sjkoshy return -1; 2163145256Sjkoshy 2164145256Sjkoshy return 0; 2165145256Sjkoshy 2166145256Sjkoshy} 2167145256Sjkoshy 2168145256Sjkoshyint 2169147191Sjkoshypmc_start(pmc_id_t pmc) 2170145256Sjkoshy{ 2171147191Sjkoshy struct pmc_op_simple pmc_start_args; 2172145256Sjkoshy 2173147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 2174147191Sjkoshy return PMC_CALL(PMCSTART, &pmc_start_args); 2175145256Sjkoshy} 2176145256Sjkoshy 2177145256Sjkoshyint 2178147191Sjkoshypmc_stop(pmc_id_t pmc) 2179145256Sjkoshy{ 2180147191Sjkoshy struct pmc_op_simple pmc_stop_args; 2181145256Sjkoshy 2182147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 2183147191Sjkoshy return PMC_CALL(PMCSTOP, &pmc_stop_args); 2184145256Sjkoshy} 2185145256Sjkoshy 2186145256Sjkoshyint 2187145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 2188145774Sjkoshy{ 2189145774Sjkoshy unsigned int i; 2190145774Sjkoshy enum pmc_class cl; 2191145774Sjkoshy 2192145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2193145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2194145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2195145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 2196145774Sjkoshy return 0; 2197145774Sjkoshy } 2198145774Sjkoshy return EINVAL; 2199145774Sjkoshy} 2200145774Sjkoshy 2201145774Sjkoshyint 2202147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 2203145774Sjkoshy{ 2204147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 2205145774Sjkoshy 2206147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 2207147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 2208147191Sjkoshy pmc_write_op.pm_value = value; 2209145774Sjkoshy 2210147191Sjkoshy return PMC_CALL(PMCRW, &pmc_write_op); 2211145256Sjkoshy} 2212145256Sjkoshy 2213145256Sjkoshyint 2214147191Sjkoshypmc_writelog(uint32_t userdata) 2215145256Sjkoshy{ 2216147191Sjkoshy struct pmc_op_writelog wl; 2217145256Sjkoshy 2218147191Sjkoshy wl.pm_userdata = userdata; 2219147191Sjkoshy return PMC_CALL(WRITELOG, &wl); 2220145256Sjkoshy} 2221