libpmc.c revision 233320
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 233320 2012-03-22 18:07:44Z gonzo $"); 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); 57206089Sfabientstatic int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 58206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 59206089Sfabientstatic int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 60206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 61147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 62145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 63147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 64147759Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 65147191Sjkoshy#endif 66147191Sjkoshy#if defined(__i386__) 67145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 68145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 69147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 70145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 71145256Sjkoshy#endif 72183725Sjkoshy#if defined(__amd64__) || defined(__i386__) 73183725Sjkoshystatic int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 74183725Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 75183725Sjkoshy#endif 76200928Srpaulo#if defined(__XSCALE__) 77200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 78200928Srpaulo struct pmc_op_pmcallocate *_pmc_config); 79200928Srpaulo#endif 80145256Sjkoshy 81204635Sgnn#if defined(__mips__) 82233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 83204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 84204635Sgnn#endif /* __mips__ */ 85204635Sgnn 86228869Sjhibbits#if defined(__powerpc__) 87228869Sjhibbitsstatic int ppc7450_allocate_pmc(enum pmc_event _pe, char* ctrspec, 88228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 89228869Sjhibbits#endif /* __powerpc__ */ 90204635Sgnn 91145256Sjkoshy#define PMC_CALL(cmd, params) \ 92145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 93145256Sjkoshy 94145256Sjkoshy/* 95145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 96145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 97145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 98145256Sjkoshy * lookup table. 99145256Sjkoshy */ 100145256Sjkoshystruct pmc_event_alias { 101145256Sjkoshy const char *pm_alias; 102145256Sjkoshy const char *pm_spec; 103145256Sjkoshy}; 104145256Sjkoshy 105145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 106145256Sjkoshy 107145256Sjkoshy/* 108183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 109145256Sjkoshy * to integer codes used by the PMC KLD. 110145256Sjkoshy */ 111145256Sjkoshystruct pmc_event_descr { 112145256Sjkoshy const char *pm_ev_name; 113145256Sjkoshy enum pmc_event pm_ev_code; 114145256Sjkoshy}; 115145256Sjkoshy 116183725Sjkoshy/* 117183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 118183725Sjkoshy * event names to event tables and other PMC class data. 119183725Sjkoshy */ 120183725Sjkoshystruct pmc_class_descr { 121183725Sjkoshy const char *pm_evc_name; 122183725Sjkoshy size_t pm_evc_name_size; 123183725Sjkoshy enum pmc_class pm_evc_class; 124183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 125183725Sjkoshy size_t pm_evc_event_table_size; 126183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 127183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 128183725Sjkoshy}; 129183725Sjkoshy 130183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 131183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 132183725Sjkoshy 133183725Sjkoshy#undef __PMC_EV 134183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 135183725Sjkoshy 136183725Sjkoshy/* 137185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 138183725Sjkoshy * 139185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 140183725Sjkoshy */ 141185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 142183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 143183725Sjkoshy { \ 144183725Sjkoshy __PMC_EV_##C() \ 145185363Sjkoshy } 146185363Sjkoshy 147185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 148185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 149185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 150185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 151185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 152185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 153200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 154204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 155206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 156228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 157185363Sjkoshy 158185363Sjkoshy#undef __PMC_EV_ALIAS 159185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 160185363Sjkoshy 161185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 162185363Sjkoshy{ 163185363Sjkoshy __PMC_EV_ALIAS_ATOM() 164185363Sjkoshy}; 165185363Sjkoshy 166185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 167185363Sjkoshy{ 168185363Sjkoshy __PMC_EV_ALIAS_CORE() 169185363Sjkoshy}; 170185363Sjkoshy 171185363Sjkoshy 172185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 173185363Sjkoshy{ 174185363Sjkoshy __PMC_EV_ALIAS_CORE2() 175185363Sjkoshy}; 176185363Sjkoshy 177187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 178187761Sjeff{ 179187761Sjeff __PMC_EV_ALIAS_COREI7() 180187761Sjeff}; 181187761Sjeff 182232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 183232366Sdavide{ 184232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 185232366Sdavide}; 186232366Sdavide 187206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 188206089Sfabient{ 189206089Sfabient __PMC_EV_ALIAS_WESTMERE() 190206089Sfabient}; 191206089Sfabient 192206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 193206089Sfabient{ 194206089Sfabient __PMC_EV_ALIAS_COREI7UC() 195206089Sfabient}; 196206089Sfabient 197232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 198232366Sdavide{ 199232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 200232366Sdavide}; 201232366Sdavide 202206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 203206089Sfabient{ 204206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 205206089Sfabient}; 206206089Sfabient 207185363Sjkoshy/* 208185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 209185363Sjkoshy * 210185363Sjkoshy * Map a CPU to the PMC classes it supports. 211185363Sjkoshy */ 212185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 213183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 214183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 215183725Sjkoshy } 216183725Sjkoshy 217185363SjkoshyPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); 218185363SjkoshyPMC_MDEP_TABLE(core, IAP, PMC_CLASS_TSC); 219185363SjkoshyPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); 220206089SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 221232366SdavidePMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 222206089SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 223183725SjkoshyPMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC); 224183725SjkoshyPMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC); 225183725SjkoshyPMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC); 226183725SjkoshyPMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC); 227183725SjkoshyPMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC); 228200928SrpauloPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_XSCALE); 229204635SgnnPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_MIPS24K); 230228869SjhibbitsPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_PPC7450); 231183725Sjkoshy 232183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 233145256Sjkoshy{ 234183725Sjkoshy __PMC_EV_TSC() 235145256Sjkoshy}; 236145256Sjkoshy 237183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 238185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 239185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 240185363Sjkoshy { \ 241185363Sjkoshy .pm_evc_name = #CLASS "-", \ 242185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 243185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 244185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 245183725Sjkoshy .pm_evc_event_table_size = \ 246185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 247185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 248183725Sjkoshy } 249183725Sjkoshy 250185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 251185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 252185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 253185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 254185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 255187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 256232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 257206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 258206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 259206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 260232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 261206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 262185363Sjkoshy#endif 263183725Sjkoshy#if defined(__i386__) 264185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 265183725Sjkoshy#endif 266183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 267185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 268185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 269183725Sjkoshy#endif 270183725Sjkoshy#if defined(__i386__) 271185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 272185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 273183725Sjkoshy#endif 274183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 275185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 276183725Sjkoshy#endif 277200928Srpaulo#if defined(__XSCALE__) 278200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 279200928Srpaulo#endif 280183725Sjkoshy 281204635Sgnn#if defined(__mips__) 282233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 283204635Sgnn#endif /* __mips__ */ 284204635Sgnn 285228869Sjhibbits#if defined(__powerpc__) 286228869SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450); 287228869Sjhibbits#endif 288228869Sjhibbits 289183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 290183725Sjkoshy 291185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 292185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 293185363Sjkoshy 294183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 295183725Sjkoshystatic size_t pmc_mdep_class_list_size; 296183725Sjkoshy 297145256Sjkoshy/* 298145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 299145256Sjkoshy * strings. 300145256Sjkoshy */ 301145256Sjkoshy 302145256Sjkoshystatic const char * pmc_capability_names[] = { 303145256Sjkoshy#undef __PMC_CAP 304145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 305145256Sjkoshy __PMC_CAPS() 306145256Sjkoshy}; 307145256Sjkoshy 308145256Sjkoshystatic const char * pmc_class_names[] = { 309145256Sjkoshy#undef __PMC_CLASS 310145256Sjkoshy#define __PMC_CLASS(C) #C , 311145256Sjkoshy __PMC_CLASSES() 312145256Sjkoshy}; 313145256Sjkoshy 314183725Sjkoshystruct pmc_cputype_map { 315228557Sdim enum pmc_cputype pm_cputype; 316183725Sjkoshy const char *pm_name; 317183725Sjkoshy}; 318183725Sjkoshy 319183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 320145256Sjkoshy#undef __PMC_CPU 321183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 322145256Sjkoshy __PMC_CPUS() 323145256Sjkoshy}; 324145256Sjkoshy 325145256Sjkoshystatic const char * pmc_disposition_names[] = { 326145256Sjkoshy#undef __PMC_DISP 327145256Sjkoshy#define __PMC_DISP(D) #D , 328145256Sjkoshy __PMC_DISPOSITIONS() 329145256Sjkoshy}; 330145256Sjkoshy 331145256Sjkoshystatic const char * pmc_mode_names[] = { 332145256Sjkoshy#undef __PMC_MODE 333145256Sjkoshy#define __PMC_MODE(M,N) #M , 334145256Sjkoshy __PMC_MODES() 335145256Sjkoshy}; 336145256Sjkoshy 337145256Sjkoshystatic const char * pmc_state_names[] = { 338145256Sjkoshy#undef __PMC_STATE 339145256Sjkoshy#define __PMC_STATE(S) #S , 340145256Sjkoshy __PMC_STATES() 341145256Sjkoshy}; 342145256Sjkoshy 343145256Sjkoshystatic int pmc_syscall = -1; /* filled in by pmc_init() */ 344145256Sjkoshy 345147219Sjkoshystatic struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */ 346145256Sjkoshy 347145256Sjkoshy/* Event masks for events */ 348145256Sjkoshystruct pmc_masks { 349145256Sjkoshy const char *pm_name; 350145256Sjkoshy const uint32_t pm_value; 351145256Sjkoshy}; 352145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 353206089Sfabient#define NULLMASK { .pm_name = NULL } 354145256Sjkoshy 355147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 356145256Sjkoshystatic int 357145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 358145256Sjkoshy{ 359145256Sjkoshy const struct pmc_masks *pm; 360145256Sjkoshy char *q, *r; 361145256Sjkoshy int c; 362145256Sjkoshy 363145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 364174406Sjkoshy return (-1); 365183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 366145256Sjkoshy if (*++q == '\0') /* no more data */ 367174406Sjkoshy return (-1); 368145256Sjkoshy c = 0; /* count of mask keywords seen */ 369145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 370183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 371183725Sjkoshy pm++) 372145256Sjkoshy ; 373145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 374174406Sjkoshy return (-1); 375145256Sjkoshy *evmask |= pm->pm_value; 376145256Sjkoshy c++; 377145256Sjkoshy } 378174406Sjkoshy return (c); 379145256Sjkoshy} 380145340Smarcel#endif 381145256Sjkoshy 382145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 383145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 384145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 385145256Sjkoshy 386145340Smarcel#if defined(__i386__) 387145256Sjkoshy 388145256Sjkoshy/* 389145256Sjkoshy * AMD K7 (Athlon) CPUs. 390145256Sjkoshy */ 391145256Sjkoshy 392145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 393145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 394145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 395145351Sjkoshy EV_ALIAS("cycles", "tsc"), 396183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 397145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 398145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 399145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 400145351Sjkoshy EV_ALIAS(NULL, NULL) 401145256Sjkoshy}; 402145256Sjkoshy 403145256Sjkoshy#define K7_KW_COUNT "count" 404145256Sjkoshy#define K7_KW_EDGE "edge" 405145256Sjkoshy#define K7_KW_INV "inv" 406145256Sjkoshy#define K7_KW_OS "os" 407145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 408145256Sjkoshy#define K7_KW_USR "usr" 409145256Sjkoshy 410145256Sjkoshystatic int 411145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 412145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 413145256Sjkoshy{ 414183107Sjkoshy char *e, *p, *q; 415183107Sjkoshy int c, has_unitmask; 416145256Sjkoshy uint32_t count, unitmask; 417145256Sjkoshy 418147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 419183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 420145256Sjkoshy 421145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 422145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 423145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 424145256Sjkoshy has_unitmask = 1; 425147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 426145256Sjkoshy } else 427145256Sjkoshy unitmask = has_unitmask = 0; 428145256Sjkoshy 429145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 430145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 431145256Sjkoshy q = strchr(p, '='); 432145256Sjkoshy if (*++q == '\0') /* skip '=' */ 433174406Sjkoshy return (-1); 434145256Sjkoshy 435145256Sjkoshy count = strtol(q, &e, 0); 436145256Sjkoshy if (e == q || *e != '\0') 437174406Sjkoshy return (-1); 438145256Sjkoshy 439145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 440147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 441147191Sjkoshy AMD_PMC_TO_COUNTER(count); 442145256Sjkoshy 443145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 444145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 445145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 446145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 447145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 448145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 449145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 450145256Sjkoshy if (has_unitmask == 0) 451174406Sjkoshy return (-1); 452145256Sjkoshy unitmask = 0; 453145256Sjkoshy q = strchr(p, '='); 454145256Sjkoshy if (*++q == '\0') /* skip '=' */ 455174406Sjkoshy return (-1); 456145256Sjkoshy 457145256Sjkoshy while ((c = tolower(*q++)) != 0) 458145256Sjkoshy if (c == 'm') 459147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 460145256Sjkoshy else if (c == 'o') 461147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 462145256Sjkoshy else if (c == 'e') 463147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 464145256Sjkoshy else if (c == 's') 465147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 466145256Sjkoshy else if (c == 'i') 467147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 468145256Sjkoshy else if (c == '+') 469145256Sjkoshy continue; 470145256Sjkoshy else 471174406Sjkoshy return (-1); 472145256Sjkoshy 473145256Sjkoshy if (unitmask == 0) 474174406Sjkoshy return (-1); 475145256Sjkoshy 476145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 477145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 478145256Sjkoshy } else 479174406Sjkoshy return (-1); 480145256Sjkoshy } 481145256Sjkoshy 482145256Sjkoshy if (has_unitmask) { 483145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 484147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 485147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 486145256Sjkoshy } 487145256Sjkoshy 488174406Sjkoshy return (0); 489145256Sjkoshy 490145256Sjkoshy} 491145256Sjkoshy 492147191Sjkoshy#endif 493147191Sjkoshy 494147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 495147191Sjkoshy 496145256Sjkoshy/* 497185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 498185363Sjkoshy */ 499185363Sjkoshy 500185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 501185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 502185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 503185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 504185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 505185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 506185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 507185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 508185363Sjkoshy EV_ALIAS(NULL, NULL) 509185363Sjkoshy}; 510185363Sjkoshy 511185363Sjkoshy/* 512185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 513185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 514198433Sjkoshy * 515198433Sjkoshy * We map aliases to events on the fixed-function counters if these 516198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 517198433Sjkoshy * counters. 518185363Sjkoshy */ 519185363Sjkoshy 520185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 521185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 522185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 523185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 524185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 525185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 526185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 527185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 528185363Sjkoshy EV_ALIAS(NULL, NULL) 529185363Sjkoshy}; 530185363Sjkoshy 531198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 532198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 533198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 534198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 535198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 536198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 537198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 538198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 539198433Sjkoshy EV_ALIAS(NULL, NULL) 540198433Sjkoshy}; 541198433Sjkoshy 542198433Sjkoshy#define atom_aliases core2_aliases 543198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 544198433Sjkoshy#define corei7_aliases core2_aliases 545198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 546232366Sdavide#define sandybridge_aliases core2_aliases 547232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 548206089Sfabient#define westmere_aliases core2_aliases 549206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 550198433Sjkoshy 551185363Sjkoshy#define IAF_KW_OS "os" 552185363Sjkoshy#define IAF_KW_USR "usr" 553185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 554185363Sjkoshy 555185363Sjkoshy/* 556185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 557185363Sjkoshy */ 558185363Sjkoshystatic int 559185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 560185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 561185363Sjkoshy{ 562185363Sjkoshy char *p; 563185363Sjkoshy 564185363Sjkoshy (void) pe; 565185363Sjkoshy 566185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 567185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 568185363Sjkoshy 569185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 570185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 571185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 572185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 573185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 574185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 575185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 576185363Sjkoshy else 577185363Sjkoshy return (-1); 578185363Sjkoshy } 579185363Sjkoshy 580185363Sjkoshy return (0); 581185363Sjkoshy} 582185363Sjkoshy 583185363Sjkoshy/* 584185363Sjkoshy * Core/Core2 support. 585185363Sjkoshy */ 586185363Sjkoshy 587185363Sjkoshy#define IAP_KW_AGENT "agent" 588185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 589185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 590185363Sjkoshy#define IAP_KW_CMASK "cmask" 591185363Sjkoshy#define IAP_KW_CORE "core" 592185363Sjkoshy#define IAP_KW_EDGE "edge" 593185363Sjkoshy#define IAP_KW_INV "inv" 594185363Sjkoshy#define IAP_KW_OS "os" 595185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 596185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 597185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 598185363Sjkoshy#define IAP_KW_TRANSITION "trans" 599185363Sjkoshy#define IAP_KW_USR "usr" 600206089Sfabient#define IAP_KW_RSP "rsp" 601185363Sjkoshy 602185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 603185363Sjkoshy PMCMASK(all, (0x3 << 14)), 604185363Sjkoshy PMCMASK(this, (0x1 << 14)), 605185363Sjkoshy NULLMASK 606185363Sjkoshy}; 607185363Sjkoshy 608185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 609185363Sjkoshy PMCMASK(this, 0), 610185363Sjkoshy PMCMASK(any, (0x1 << 13)), 611185363Sjkoshy NULLMASK 612185363Sjkoshy}; 613185363Sjkoshy 614185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 615185363Sjkoshy PMCMASK(both, (0x3 << 12)), 616185363Sjkoshy PMCMASK(only, (0x1 << 12)), 617185363Sjkoshy PMCMASK(exclude, 0), 618185363Sjkoshy NULLMASK 619185363Sjkoshy}; 620185363Sjkoshy 621185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 622185363Sjkoshy PMCMASK(i, (1 << 8)), 623185363Sjkoshy PMCMASK(s, (1 << 9)), 624185363Sjkoshy PMCMASK(e, (1 << 10)), 625185363Sjkoshy PMCMASK(m, (1 << 11)), 626185363Sjkoshy NULLMASK 627185363Sjkoshy}; 628185363Sjkoshy 629185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 630185363Sjkoshy PMCMASK(clean, (1 << 8)), 631185363Sjkoshy PMCMASK(hit, (1 << 9)), 632185363Sjkoshy PMCMASK(hitm, (1 << 11)), 633185363Sjkoshy NULLMASK 634185363Sjkoshy}; 635185363Sjkoshy 636185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 637185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 638185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 639185363Sjkoshy NULLMASK 640185363Sjkoshy}; 641185363Sjkoshy 642185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 643185363Sjkoshy PMCMASK(any, 0x00), 644185363Sjkoshy PMCMASK(frequency, 0x10), 645185363Sjkoshy NULLMASK 646185363Sjkoshy}; 647185363Sjkoshy 648206089Sfabientstatic struct pmc_masks iap_rsp_mask[] = { 649206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 650206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 651206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 652206089Sfabient PMCMASK(WB, (1 << 3)), 653206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 654206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 655206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 656206089Sfabient PMCMASK(OTHER, (1 << 7)), 657206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 658206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 659206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 660206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 661206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 662206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 663206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 664206089Sfabient NULLMASK 665206089Sfabient}; 666206089Sfabient 667185363Sjkoshystatic int 668185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 669185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 670185363Sjkoshy{ 671185363Sjkoshy char *e, *p, *q; 672206089Sfabient uint32_t cachestate, evmask, rsp; 673185363Sjkoshy int count, n; 674185363Sjkoshy 675185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 676185363Sjkoshy PMC_CAP_QUALIFIER); 677185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 678185363Sjkoshy 679206089Sfabient cachestate = evmask = rsp = 0; 680185363Sjkoshy 681185363Sjkoshy /* Parse additional modifiers if present */ 682185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 683185363Sjkoshy 684185363Sjkoshy n = 0; 685185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 686185363Sjkoshy q = strchr(p, '='); 687185363Sjkoshy if (*++q == '\0') /* skip '=' */ 688185363Sjkoshy return (-1); 689185363Sjkoshy count = strtol(q, &e, 0); 690185363Sjkoshy if (e == q || *e != '\0') 691185363Sjkoshy return (-1); 692185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 693185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 694185363Sjkoshy IAP_CMASK(count); 695185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 696185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 697185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 698185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 699185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 700185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 701185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 702185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 703185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 704185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 705193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 706185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 707185363Sjkoshy if (n != 1) 708185363Sjkoshy return (-1); 709193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 710185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 711185363Sjkoshy if (n != 1) 712185363Sjkoshy return (-1); 713193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 714185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 715185363Sjkoshy if (n != 1) 716185363Sjkoshy return (-1); 717193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 718185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 719185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 720193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 721185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 722185363Sjkoshy if (n != 1) 723185363Sjkoshy return (-1); 724185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 725185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 726206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 727193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 728185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 729185363Sjkoshy &evmask); 730193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 731185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 732185363Sjkoshy &evmask); 733185363Sjkoshy } else 734185363Sjkoshy return (-1); 735206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 736206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) { 737206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 738206089Sfabient n = pmc_parse_mask(iap_rsp_mask, p, &rsp); 739206089Sfabient } else 740206089Sfabient return (-1); 741185363Sjkoshy } else 742185363Sjkoshy return (-1); 743185363Sjkoshy 744185363Sjkoshy if (n < 0) /* Parsing failed. */ 745185363Sjkoshy return (-1); 746185363Sjkoshy } 747185363Sjkoshy 748185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 749185363Sjkoshy 750185363Sjkoshy /* 751185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 752185363Sjkoshy * specified by the user, use a sensible default. 753185363Sjkoshy */ 754185363Sjkoshy switch (pe) { 755185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 756185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 757185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 758185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 759185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 760185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 761185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 762185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 763185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 764185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 765185363Sjkoshy if (cachestate == 0) 766185363Sjkoshy cachestate = (0xF << 8); 767207482Srstone break; 768207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 769207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 770207482Srstone * Atom processor 771207482Srstone */ 772207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 773207482Srstone cachestate = (0xF << 8); 774207482Srstone break; 775185363Sjkoshy default: 776185363Sjkoshy break; 777185363Sjkoshy } 778185363Sjkoshy 779185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 780206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 781185363Sjkoshy 782185363Sjkoshy return (0); 783185363Sjkoshy} 784185363Sjkoshy 785185363Sjkoshy/* 786206089Sfabient * Intel Uncore. 787206089Sfabient */ 788206089Sfabient 789206089Sfabientstatic int 790206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 791206089Sfabient struct pmc_op_pmcallocate *pmc_config) 792206089Sfabient{ 793206089Sfabient (void) pe; 794206089Sfabient (void) ctrspec; 795206089Sfabient 796206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 797206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 798206089Sfabient 799206089Sfabient return (0); 800206089Sfabient} 801206089Sfabient 802206089Sfabient#define UCP_KW_CMASK "cmask" 803206089Sfabient#define UCP_KW_EDGE "edge" 804206089Sfabient#define UCP_KW_INV "inv" 805206089Sfabient 806206089Sfabientstatic int 807206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 808206089Sfabient struct pmc_op_pmcallocate *pmc_config) 809206089Sfabient{ 810206089Sfabient char *e, *p, *q; 811206089Sfabient int count, n; 812206089Sfabient 813206089Sfabient (void) pe; 814206089Sfabient 815206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 816206089Sfabient PMC_CAP_QUALIFIER); 817206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 818206089Sfabient 819206089Sfabient /* Parse additional modifiers if present */ 820206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 821206089Sfabient 822206089Sfabient n = 0; 823206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 824206089Sfabient q = strchr(p, '='); 825206089Sfabient if (*++q == '\0') /* skip '=' */ 826206089Sfabient return (-1); 827206089Sfabient count = strtol(q, &e, 0); 828206089Sfabient if (e == q || *e != '\0') 829206089Sfabient return (-1); 830206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 831206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 832206089Sfabient UCP_CMASK(count); 833206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 834206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 835206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 836206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 837206089Sfabient } else 838206089Sfabient return (-1); 839206089Sfabient 840206089Sfabient if (n < 0) /* Parsing failed. */ 841206089Sfabient return (-1); 842206089Sfabient } 843206089Sfabient 844206089Sfabient return (0); 845206089Sfabient} 846206089Sfabient 847206089Sfabient/* 848147191Sjkoshy * AMD K8 PMCs. 849147191Sjkoshy * 850147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 851147191Sjkoshy * events. 852147191Sjkoshy */ 853147191Sjkoshy 854147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 855147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 856147191Sjkoshy EV_ALIAS("branch-mispredicts", 857147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 858147191Sjkoshy EV_ALIAS("cycles", "tsc"), 859147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 860147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 861183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 862147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 863155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 864147191Sjkoshy EV_ALIAS(NULL, NULL) 865147191Sjkoshy}; 866147191Sjkoshy 867147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 868147191Sjkoshy 869147191Sjkoshy/* 870147191Sjkoshy * Parsing tables 871147191Sjkoshy */ 872147191Sjkoshy 873147191Sjkoshy/* fp dispatched fpu ops */ 874147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 875147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 876147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 877147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 878147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 879147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 880147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 881147191Sjkoshy NULLMASK 882147191Sjkoshy}; 883147191Sjkoshy 884147191Sjkoshy/* ls segment register loads */ 885147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 886147191Sjkoshy __K8MASK(es, 0), 887147191Sjkoshy __K8MASK(cs, 1), 888147191Sjkoshy __K8MASK(ss, 2), 889147191Sjkoshy __K8MASK(ds, 3), 890147191Sjkoshy __K8MASK(fs, 4), 891147191Sjkoshy __K8MASK(gs, 5), 892147191Sjkoshy __K8MASK(hs, 6), 893147191Sjkoshy NULLMASK 894147191Sjkoshy}; 895147191Sjkoshy 896147191Sjkoshy/* ls locked operation */ 897147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 898147191Sjkoshy __K8MASK(locked-instructions, 0), 899147191Sjkoshy __K8MASK(cycles-in-request, 1), 900147191Sjkoshy __K8MASK(cycles-to-complete, 2), 901147191Sjkoshy NULLMASK 902147191Sjkoshy}; 903147191Sjkoshy 904147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 905147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 906147191Sjkoshy __K8MASK(invalid, 0), 907147191Sjkoshy __K8MASK(shared, 1), 908147191Sjkoshy __K8MASK(exclusive, 2), 909147191Sjkoshy __K8MASK(owner, 3), 910147191Sjkoshy __K8MASK(modified, 4), 911147191Sjkoshy NULLMASK 912147191Sjkoshy}; 913147191Sjkoshy 914147191Sjkoshy/* dc one bit ecc error */ 915147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 916147191Sjkoshy __K8MASK(scrubber, 0), 917147191Sjkoshy __K8MASK(piggyback, 1), 918147191Sjkoshy NULLMASK 919147191Sjkoshy}; 920147191Sjkoshy 921147191Sjkoshy/* dc dispatched prefetch instructions */ 922147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 923147191Sjkoshy __K8MASK(load, 0), 924147191Sjkoshy __K8MASK(store, 1), 925147191Sjkoshy __K8MASK(nta, 2), 926147191Sjkoshy NULLMASK 927147191Sjkoshy}; 928147191Sjkoshy 929147191Sjkoshy/* dc dcache accesses by locks */ 930147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 931147191Sjkoshy __K8MASK(accesses, 0), 932147191Sjkoshy __K8MASK(misses, 1), 933147191Sjkoshy NULLMASK 934147191Sjkoshy}; 935147191Sjkoshy 936147191Sjkoshy/* bu internal l2 request */ 937147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 938147191Sjkoshy __K8MASK(ic-fill, 0), 939147191Sjkoshy __K8MASK(dc-fill, 1), 940147191Sjkoshy __K8MASK(tlb-reload, 2), 941147191Sjkoshy __K8MASK(tag-snoop, 3), 942147191Sjkoshy __K8MASK(cancelled, 4), 943147191Sjkoshy NULLMASK 944147191Sjkoshy}; 945147191Sjkoshy 946147191Sjkoshy/* bu fill request l2 miss */ 947147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 948147191Sjkoshy __K8MASK(ic-fill, 0), 949147191Sjkoshy __K8MASK(dc-fill, 1), 950147191Sjkoshy __K8MASK(tlb-reload, 2), 951147191Sjkoshy NULLMASK 952147191Sjkoshy}; 953147191Sjkoshy 954147191Sjkoshy/* bu fill into l2 */ 955147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 956147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 957147191Sjkoshy __K8MASK(victim-from-l2, 1), 958147191Sjkoshy NULLMASK 959147191Sjkoshy}; 960147191Sjkoshy 961147191Sjkoshy/* fr retired fpu instructions */ 962147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 963147191Sjkoshy __K8MASK(x87, 0), 964147191Sjkoshy __K8MASK(mmx-3dnow, 1), 965147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 966147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 967147191Sjkoshy NULLMASK 968147191Sjkoshy}; 969147191Sjkoshy 970147191Sjkoshy/* fr retired fastpath double op instructions */ 971147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 972147191Sjkoshy __K8MASK(low-op-pos-0, 0), 973147191Sjkoshy __K8MASK(low-op-pos-1, 1), 974147191Sjkoshy __K8MASK(low-op-pos-2, 2), 975147191Sjkoshy NULLMASK 976147191Sjkoshy}; 977147191Sjkoshy 978147191Sjkoshy/* fr fpu exceptions */ 979147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 980147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 981147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 982147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 983147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 984147191Sjkoshy NULLMASK 985147191Sjkoshy}; 986147191Sjkoshy 987147191Sjkoshy/* nb memory controller page access event */ 988147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 989147191Sjkoshy __K8MASK(page-hit, 0), 990147191Sjkoshy __K8MASK(page-miss, 1), 991147191Sjkoshy __K8MASK(page-conflict, 2), 992147191Sjkoshy NULLMASK 993147191Sjkoshy}; 994147191Sjkoshy 995147191Sjkoshy/* nb memory controller turnaround */ 996147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 997147191Sjkoshy __K8MASK(dimm-turnaround, 0), 998147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 999147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1000147191Sjkoshy NULLMASK 1001147191Sjkoshy}; 1002147191Sjkoshy 1003147191Sjkoshy/* nb memory controller bypass saturation */ 1004147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1005147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1006147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1007147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1008147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1009147191Sjkoshy NULLMASK 1010147191Sjkoshy}; 1011147191Sjkoshy 1012147191Sjkoshy/* nb sized commands */ 1013147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1014147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1015147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1016147191Sjkoshy __K8MASK(postwrszbyte, 2), 1017147191Sjkoshy __K8MASK(postwrszdword, 3), 1018147191Sjkoshy __K8MASK(rdszbyte, 4), 1019147191Sjkoshy __K8MASK(rdszdword, 5), 1020147191Sjkoshy __K8MASK(rdmodwr, 6), 1021147191Sjkoshy NULLMASK 1022147191Sjkoshy}; 1023147191Sjkoshy 1024147191Sjkoshy/* nb probe result */ 1025147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1026147191Sjkoshy __K8MASK(probe-miss, 0), 1027147191Sjkoshy __K8MASK(probe-hit, 1), 1028147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1029147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1030147191Sjkoshy NULLMASK 1031147191Sjkoshy}; 1032147191Sjkoshy 1033147191Sjkoshy/* nb hypertransport bus bandwidth */ 1034147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1035147191Sjkoshy __K8MASK(command, 0), 1036183107Sjkoshy __K8MASK(data, 1), 1037147191Sjkoshy __K8MASK(buffer-release, 2), 1038147191Sjkoshy __K8MASK(nop, 3), 1039147191Sjkoshy NULLMASK 1040147191Sjkoshy}; 1041147191Sjkoshy 1042147191Sjkoshy#undef __K8MASK 1043147191Sjkoshy 1044147191Sjkoshy#define K8_KW_COUNT "count" 1045147191Sjkoshy#define K8_KW_EDGE "edge" 1046147191Sjkoshy#define K8_KW_INV "inv" 1047147191Sjkoshy#define K8_KW_MASK "mask" 1048147191Sjkoshy#define K8_KW_OS "os" 1049147191Sjkoshy#define K8_KW_USR "usr" 1050147191Sjkoshy 1051147191Sjkoshystatic int 1052147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1053147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1054147191Sjkoshy{ 1055183107Sjkoshy char *e, *p, *q; 1056183107Sjkoshy int n; 1057147191Sjkoshy uint32_t count, evmask; 1058147191Sjkoshy const struct pmc_masks *pm, *pmask; 1059147191Sjkoshy 1060183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1061147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1062147191Sjkoshy 1063147191Sjkoshy pmask = NULL; 1064147191Sjkoshy evmask = 0; 1065147191Sjkoshy 1066147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1067147191Sjkoshy 1068147191Sjkoshy /* setup parsing tables */ 1069147191Sjkoshy switch (pe) { 1070147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1071147191Sjkoshy __K8SETMASK(fdfo); 1072147191Sjkoshy break; 1073147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1074147191Sjkoshy __K8SETMASK(lsrl); 1075147191Sjkoshy break; 1076147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1077147191Sjkoshy __K8SETMASK(llo); 1078147191Sjkoshy break; 1079147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1080147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1081147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1082147191Sjkoshy __K8SETMASK(dc); 1083147191Sjkoshy break; 1084147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1085147191Sjkoshy __K8SETMASK(dobee); 1086147191Sjkoshy break; 1087147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1088147191Sjkoshy __K8SETMASK(ddpi); 1089147191Sjkoshy break; 1090147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1091147191Sjkoshy __K8SETMASK(dabl); 1092147191Sjkoshy break; 1093147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1094147191Sjkoshy __K8SETMASK(bilr); 1095147191Sjkoshy break; 1096147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1097147191Sjkoshy __K8SETMASK(bfrlm); 1098147191Sjkoshy break; 1099147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1100147191Sjkoshy __K8SETMASK(bfil); 1101147191Sjkoshy break; 1102147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1103147191Sjkoshy __K8SETMASK(frfi); 1104147191Sjkoshy break; 1105147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1106147191Sjkoshy __K8SETMASK(frfdoi); 1107147191Sjkoshy break; 1108147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1109147191Sjkoshy __K8SETMASK(ffe); 1110147191Sjkoshy break; 1111147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1112147191Sjkoshy __K8SETMASK(nmcpae); 1113147191Sjkoshy break; 1114147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1115147191Sjkoshy __K8SETMASK(nmct); 1116147191Sjkoshy break; 1117147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1118147191Sjkoshy __K8SETMASK(nmcbs); 1119147191Sjkoshy break; 1120147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1121147191Sjkoshy __K8SETMASK(nsc); 1122147191Sjkoshy break; 1123147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1124147191Sjkoshy __K8SETMASK(npr); 1125147191Sjkoshy break; 1126147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1127147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1128147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1129147191Sjkoshy __K8SETMASK(nhbb); 1130147191Sjkoshy break; 1131147191Sjkoshy 1132147191Sjkoshy default: 1133147191Sjkoshy break; /* no options defined */ 1134147191Sjkoshy } 1135147191Sjkoshy 1136147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1137147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1138147191Sjkoshy q = strchr(p, '='); 1139147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1140174406Sjkoshy return (-1); 1141147191Sjkoshy 1142147191Sjkoshy count = strtol(q, &e, 0); 1143147191Sjkoshy if (e == q || *e != '\0') 1144174406Sjkoshy return (-1); 1145147191Sjkoshy 1146147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1147147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1148147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1149147191Sjkoshy 1150147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1151147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1152147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1153147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1154147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1155147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1156174406Sjkoshy return (-1); 1157147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1158147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1159147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1160147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1161147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1162147191Sjkoshy } else 1163174406Sjkoshy return (-1); 1164147191Sjkoshy } 1165147191Sjkoshy 1166147191Sjkoshy /* other post processing */ 1167147191Sjkoshy switch (pe) { 1168147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1169147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1170147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1171147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1172147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1173147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1174147191Sjkoshy /* XXX only available in rev B and later */ 1175147191Sjkoshy break; 1176147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1177147191Sjkoshy /* XXX only available in rev C and later */ 1178147191Sjkoshy break; 1179147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1180147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1181147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1182174406Sjkoshy return (-1); 1183147191Sjkoshy if (evmask == 0) { 1184147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1185147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1186147191Sjkoshy } 1187147191Sjkoshy break; 1188147191Sjkoshy default: 1189147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1190147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1191147191Sjkoshy evmask |= pm->pm_value; 1192147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1193147191Sjkoshy } 1194147191Sjkoshy } 1195147191Sjkoshy 1196147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1197147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1198147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1199147191Sjkoshy 1200174406Sjkoshy return (0); 1201147191Sjkoshy} 1202147191Sjkoshy 1203147191Sjkoshy#endif 1204147191Sjkoshy 1205147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1206147191Sjkoshy 1207147191Sjkoshy/* 1208145256Sjkoshy * Intel P4 PMCs 1209145256Sjkoshy */ 1210145256Sjkoshy 1211145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1212145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1213145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1214145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1215145351Sjkoshy EV_ALIAS("instructions", 1216145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1217155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1218145256Sjkoshy EV_ALIAS(NULL, NULL) 1219145256Sjkoshy}; 1220145256Sjkoshy 1221145256Sjkoshy#define P4_KW_ACTIVE "active" 1222145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1223145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1224145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1225145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1226145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1227145256Sjkoshy#define P4_KW_CASCADE "cascade" 1228145256Sjkoshy#define P4_KW_EDGE "edge" 1229145256Sjkoshy#define P4_KW_INV "complement" 1230145256Sjkoshy#define P4_KW_OS "os" 1231145256Sjkoshy#define P4_KW_MASK "mask" 1232145256Sjkoshy#define P4_KW_PRECISE "precise" 1233145256Sjkoshy#define P4_KW_TAG "tag" 1234145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1235145256Sjkoshy#define P4_KW_USR "usr" 1236145256Sjkoshy 1237145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1238145256Sjkoshy 1239145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1240145256Sjkoshy __P4MASK(dd, 0), 1241145256Sjkoshy __P4MASK(db, 1), 1242145256Sjkoshy __P4MASK(di, 2), 1243145256Sjkoshy __P4MASK(bd, 3), 1244145256Sjkoshy __P4MASK(bb, 4), 1245145256Sjkoshy __P4MASK(bi, 5), 1246145256Sjkoshy __P4MASK(id, 6), 1247145256Sjkoshy __P4MASK(ib, 7), 1248145256Sjkoshy NULLMASK 1249145256Sjkoshy}; 1250145256Sjkoshy 1251145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1252145256Sjkoshy __P4MASK(tcmiss, 0), 1253145256Sjkoshy NULLMASK, 1254145256Sjkoshy}; 1255145256Sjkoshy 1256145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1257145256Sjkoshy __P4MASK(hit, 0), 1258145256Sjkoshy __P4MASK(miss, 1), 1259145256Sjkoshy __P4MASK(hit-uc, 2), 1260145256Sjkoshy NULLMASK 1261145256Sjkoshy}; 1262145256Sjkoshy 1263145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1264145256Sjkoshy __P4MASK(st-rb-full, 2), 1265145256Sjkoshy __P4MASK(64k-conf, 3), 1266145256Sjkoshy NULLMASK 1267145256Sjkoshy}; 1268145256Sjkoshy 1269145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1270145256Sjkoshy __P4MASK(lsc, 0), 1271145256Sjkoshy __P4MASK(ssc, 1), 1272145256Sjkoshy NULLMASK 1273145256Sjkoshy}; 1274145256Sjkoshy 1275145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1276145256Sjkoshy __P4MASK(split-ld, 1), 1277145256Sjkoshy NULLMASK 1278145256Sjkoshy}; 1279145256Sjkoshy 1280145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1281145256Sjkoshy __P4MASK(split-st, 1), 1282145256Sjkoshy NULLMASK 1283145256Sjkoshy}; 1284145256Sjkoshy 1285145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1286145256Sjkoshy __P4MASK(no-sta, 1), 1287145256Sjkoshy __P4MASK(no-std, 3), 1288145256Sjkoshy __P4MASK(partial-data, 4), 1289145256Sjkoshy __P4MASK(unalgn-addr, 5), 1290145256Sjkoshy NULLMASK 1291145256Sjkoshy}; 1292145256Sjkoshy 1293145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1294145256Sjkoshy __P4MASK(dtmiss, 0), 1295145256Sjkoshy __P4MASK(itmiss, 1), 1296145256Sjkoshy NULLMASK 1297145256Sjkoshy}; 1298145256Sjkoshy 1299145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1300145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1301145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1302145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1303145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1304145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1305145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1306145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1307145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1308145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1309145256Sjkoshy NULLMASK 1310145256Sjkoshy}; 1311145256Sjkoshy 1312145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1313145256Sjkoshy __P4MASK(all-read, 5), 1314145256Sjkoshy __P4MASK(all-write, 6), 1315145256Sjkoshy __P4MASK(mem-uc, 7), 1316145256Sjkoshy __P4MASK(mem-wc, 8), 1317145256Sjkoshy __P4MASK(mem-wt, 9), 1318145256Sjkoshy __P4MASK(mem-wp, 10), 1319145256Sjkoshy __P4MASK(mem-wb, 11), 1320145256Sjkoshy __P4MASK(own, 13), 1321145256Sjkoshy __P4MASK(other, 14), 1322145256Sjkoshy __P4MASK(prefetch, 15), 1323145256Sjkoshy NULLMASK 1324145256Sjkoshy}; 1325145256Sjkoshy 1326145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1327145256Sjkoshy __P4MASK(all-read, 5), 1328145256Sjkoshy __P4MASK(all-write, 6), 1329145256Sjkoshy __P4MASK(mem-uc, 7), 1330145256Sjkoshy __P4MASK(mem-wc, 8), 1331145256Sjkoshy __P4MASK(mem-wt, 9), 1332145256Sjkoshy __P4MASK(mem-wp, 10), 1333145256Sjkoshy __P4MASK(mem-wb, 11), 1334145256Sjkoshy __P4MASK(own, 13), 1335145256Sjkoshy __P4MASK(other, 14), 1336145256Sjkoshy __P4MASK(prefetch, 15), 1337145256Sjkoshy NULLMASK 1338145256Sjkoshy}; 1339145256Sjkoshy 1340145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1341145256Sjkoshy __P4MASK(drdy-drv, 0), 1342145256Sjkoshy __P4MASK(drdy-own, 1), 1343145256Sjkoshy __P4MASK(drdy-other, 2), 1344145256Sjkoshy __P4MASK(dbsy-drv, 3), 1345145256Sjkoshy __P4MASK(dbsy-own, 4), 1346145256Sjkoshy __P4MASK(dbsy-other, 5), 1347145256Sjkoshy NULLMASK 1348145256Sjkoshy}; 1349145256Sjkoshy 1350145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1351145256Sjkoshy __P4MASK(req-type0, 0), 1352145256Sjkoshy __P4MASK(req-type1, 1), 1353145256Sjkoshy __P4MASK(req-len0, 2), 1354145256Sjkoshy __P4MASK(req-len1, 3), 1355145256Sjkoshy __P4MASK(req-io-type, 5), 1356145256Sjkoshy __P4MASK(req-lock-type, 6), 1357145256Sjkoshy __P4MASK(req-cache-type, 7), 1358145256Sjkoshy __P4MASK(req-split-type, 8), 1359145256Sjkoshy __P4MASK(req-dem-type, 9), 1360145256Sjkoshy __P4MASK(req-ord-type, 10), 1361145256Sjkoshy __P4MASK(mem-type0, 11), 1362145256Sjkoshy __P4MASK(mem-type1, 12), 1363145256Sjkoshy __P4MASK(mem-type2, 13), 1364145256Sjkoshy NULLMASK 1365145256Sjkoshy}; 1366145256Sjkoshy 1367145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1368145256Sjkoshy __P4MASK(all, 15), 1369145256Sjkoshy NULLMASK 1370145256Sjkoshy}; 1371145256Sjkoshy 1372145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1373145256Sjkoshy __P4MASK(all, 15), 1374145256Sjkoshy NULLMASK 1375145256Sjkoshy}; 1376145256Sjkoshy 1377145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1378145256Sjkoshy __P4MASK(all, 15), 1379145256Sjkoshy NULLMASK 1380145256Sjkoshy}; 1381145256Sjkoshy 1382145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1383145256Sjkoshy __P4MASK(all, 15), 1384145256Sjkoshy NULLMASK 1385145256Sjkoshy}; 1386145256Sjkoshy 1387145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1388145256Sjkoshy __P4MASK(all, 15), 1389145256Sjkoshy NULLMASK 1390145256Sjkoshy}; 1391145256Sjkoshy 1392145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1393145256Sjkoshy __P4MASK(all, 15), 1394145256Sjkoshy NULLMASK 1395145256Sjkoshy}; 1396145256Sjkoshy 1397145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1398145256Sjkoshy __P4MASK(all, 15), 1399145256Sjkoshy NULLMASK 1400145256Sjkoshy}; 1401145256Sjkoshy 1402145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1403145256Sjkoshy __P4MASK(all, 15), 1404145256Sjkoshy NULLMASK 1405145256Sjkoshy}; 1406145256Sjkoshy 1407145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1408145256Sjkoshy __P4MASK(allp0, 3), 1409145256Sjkoshy __P4MASK(allp2, 4), 1410145256Sjkoshy NULLMASK 1411145256Sjkoshy}; 1412145256Sjkoshy 1413145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1414145256Sjkoshy __P4MASK(running, 0), 1415145256Sjkoshy NULLMASK 1416145256Sjkoshy}; 1417145256Sjkoshy 1418145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1419145256Sjkoshy __P4MASK(cisc, 0), 1420145256Sjkoshy NULLMASK 1421145256Sjkoshy}; 1422145256Sjkoshy 1423145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1424145256Sjkoshy __P4MASK(from-tc-build, 0), 1425145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1426145256Sjkoshy __P4MASK(from-rom, 2), 1427145256Sjkoshy NULLMASK 1428145256Sjkoshy}; 1429145256Sjkoshy 1430145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1431145351Sjkoshy /* retired mispred branch type */ 1432145256Sjkoshy __P4MASK(conditional, 1), 1433145256Sjkoshy __P4MASK(call, 2), 1434145256Sjkoshy __P4MASK(return, 3), 1435145256Sjkoshy __P4MASK(indirect, 4), 1436145256Sjkoshy NULLMASK 1437145256Sjkoshy}; 1438145256Sjkoshy 1439145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1440145256Sjkoshy __P4MASK(conditional, 1), 1441145256Sjkoshy __P4MASK(call, 2), 1442145256Sjkoshy __P4MASK(retired, 3), 1443145256Sjkoshy __P4MASK(indirect, 4), 1444145256Sjkoshy NULLMASK 1445145256Sjkoshy}; 1446145256Sjkoshy 1447145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1448145256Sjkoshy __P4MASK(sbfull, 5), 1449145256Sjkoshy NULLMASK 1450145256Sjkoshy}; 1451145256Sjkoshy 1452145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1453145256Sjkoshy __P4MASK(wcb-evicts, 0), 1454145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1455145256Sjkoshy NULLMASK 1456145256Sjkoshy}; 1457145256Sjkoshy 1458145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1459145256Sjkoshy __P4MASK(nbogus, 0), 1460145256Sjkoshy __P4MASK(bogus, 1), 1461145256Sjkoshy NULLMASK 1462145256Sjkoshy}; 1463145256Sjkoshy 1464145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1465145256Sjkoshy __P4MASK(nbogus0, 0), 1466145256Sjkoshy __P4MASK(nbogus1, 1), 1467145256Sjkoshy __P4MASK(nbogus2, 2), 1468145256Sjkoshy __P4MASK(nbogus3, 3), 1469145256Sjkoshy __P4MASK(bogus0, 4), 1470145256Sjkoshy __P4MASK(bogus1, 5), 1471145256Sjkoshy __P4MASK(bogus2, 6), 1472145256Sjkoshy __P4MASK(bogus3, 7), 1473145256Sjkoshy NULLMASK 1474145256Sjkoshy}; 1475145256Sjkoshy 1476145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1477145256Sjkoshy __P4MASK(nbogus, 0), 1478145256Sjkoshy __P4MASK(bogus, 1), 1479145256Sjkoshy NULLMASK 1480145256Sjkoshy}; 1481145256Sjkoshy 1482145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1483145256Sjkoshy __P4MASK(nbogusntag, 0), 1484145256Sjkoshy __P4MASK(nbogustag, 1), 1485145256Sjkoshy __P4MASK(bogusntag, 2), 1486145256Sjkoshy __P4MASK(bogustag, 3), 1487145256Sjkoshy NULLMASK 1488145256Sjkoshy}; 1489145256Sjkoshy 1490145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1491145256Sjkoshy __P4MASK(nbogus, 0), 1492145256Sjkoshy __P4MASK(bogus, 1), 1493145256Sjkoshy NULLMASK 1494145256Sjkoshy}; 1495145256Sjkoshy 1496145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1497145256Sjkoshy __P4MASK(tagloads, 1), 1498145256Sjkoshy __P4MASK(tagstores, 2), 1499145256Sjkoshy NULLMASK 1500145256Sjkoshy}; 1501145256Sjkoshy 1502145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1503145256Sjkoshy __P4MASK(mmnp, 0), 1504145256Sjkoshy __P4MASK(mmnm, 1), 1505145256Sjkoshy __P4MASK(mmtp, 2), 1506145256Sjkoshy __P4MASK(mmtm, 3), 1507145256Sjkoshy NULLMASK 1508145256Sjkoshy}; 1509145256Sjkoshy 1510145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1511145256Sjkoshy __P4MASK(nbogus, 0), 1512145256Sjkoshy NULLMASK 1513145256Sjkoshy}; 1514145256Sjkoshy 1515145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1516145256Sjkoshy __P4MASK(fpsu, 0), 1517145256Sjkoshy __P4MASK(fpso, 1), 1518145256Sjkoshy __P4MASK(poao, 2), 1519145256Sjkoshy __P4MASK(poau, 3), 1520145256Sjkoshy __P4MASK(prea, 4), 1521145256Sjkoshy NULLMASK 1522145256Sjkoshy}; 1523145256Sjkoshy 1524145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1525145256Sjkoshy __P4MASK(clear, 0), 1526145256Sjkoshy __P4MASK(moclear, 2), 1527145256Sjkoshy __P4MASK(smclear, 3), 1528145256Sjkoshy NULLMASK 1529145256Sjkoshy}; 1530145256Sjkoshy 1531145256Sjkoshy/* P4 event parser */ 1532145256Sjkoshystatic int 1533145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1534145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1535145256Sjkoshy{ 1536145256Sjkoshy 1537145256Sjkoshy char *e, *p, *q; 1538145256Sjkoshy int count, has_tag, has_busreqtype, n; 1539145256Sjkoshy uint32_t evmask, cccractivemask; 1540145256Sjkoshy const struct pmc_masks *pm, *pmask; 1541145256Sjkoshy 1542183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1543147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1544147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1545145256Sjkoshy 1546145256Sjkoshy pmask = NULL; 1547145256Sjkoshy evmask = 0; 1548145256Sjkoshy cccractivemask = 0x3; 1549145256Sjkoshy has_tag = has_busreqtype = 0; 1550145256Sjkoshy 1551145256Sjkoshy#define __P4SETMASK(M) do { \ 1552183107Sjkoshy pmask = p4_mask_##M; \ 1553145256Sjkoshy} while (0) 1554145256Sjkoshy 1555145256Sjkoshy switch (pe) { 1556145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1557145256Sjkoshy __P4SETMASK(tcdm); 1558145256Sjkoshy break; 1559145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1560145256Sjkoshy __P4SETMASK(bfr); 1561145256Sjkoshy break; 1562145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1563145256Sjkoshy __P4SETMASK(ir); 1564145256Sjkoshy break; 1565145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1566145256Sjkoshy __P4SETMASK(memcan); 1567145256Sjkoshy break; 1568145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1569145256Sjkoshy __P4SETMASK(memcomp); 1570145256Sjkoshy break; 1571145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1572145256Sjkoshy __P4SETMASK(lpr); 1573145256Sjkoshy break; 1574145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1575145256Sjkoshy __P4SETMASK(spr); 1576145256Sjkoshy break; 1577145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1578145256Sjkoshy __P4SETMASK(mlr); 1579145256Sjkoshy break; 1580145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1581145256Sjkoshy __P4SETMASK(pwt); 1582145256Sjkoshy break; 1583145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1584145256Sjkoshy __P4SETMASK(bcr); 1585145256Sjkoshy break; 1586145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1587145256Sjkoshy __P4SETMASK(ia); 1588145256Sjkoshy has_busreqtype = 1; 1589145256Sjkoshy break; 1590145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1591145256Sjkoshy __P4SETMASK(iae); 1592145256Sjkoshy has_busreqtype = 1; 1593145256Sjkoshy break; 1594145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1595145256Sjkoshy __P4SETMASK(fda); 1596145256Sjkoshy break; 1597145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1598145256Sjkoshy __P4SETMASK(ba); 1599145256Sjkoshy break; 1600145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1601145256Sjkoshy __P4SETMASK(sia); 1602145256Sjkoshy break; 1603145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1604145256Sjkoshy __P4SETMASK(psu); 1605145256Sjkoshy break; 1606145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1607145256Sjkoshy __P4SETMASK(pdu); 1608145256Sjkoshy break; 1609145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1610145256Sjkoshy __P4SETMASK(ssu); 1611145256Sjkoshy break; 1612145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1613145256Sjkoshy __P4SETMASK(sdu); 1614145256Sjkoshy break; 1615145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1616145256Sjkoshy __P4SETMASK(64bmu); 1617145256Sjkoshy break; 1618145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1619145256Sjkoshy __P4SETMASK(128bmu); 1620145256Sjkoshy break; 1621145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1622145256Sjkoshy __P4SETMASK(xfu); 1623145256Sjkoshy break; 1624145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1625145256Sjkoshy __P4SETMASK(xsmu); 1626145256Sjkoshy break; 1627145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1628145256Sjkoshy __P4SETMASK(gpe); 1629145256Sjkoshy break; 1630145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1631145256Sjkoshy __P4SETMASK(tmx); 1632145256Sjkoshy break; 1633145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1634145256Sjkoshy __P4SETMASK(uqw); 1635145256Sjkoshy break; 1636145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1637145256Sjkoshy __P4SETMASK(rmbt); 1638145256Sjkoshy break; 1639145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1640145256Sjkoshy __P4SETMASK(rbt); 1641145256Sjkoshy break; 1642145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1643145256Sjkoshy __P4SETMASK(rs); 1644145256Sjkoshy break; 1645145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1646145256Sjkoshy __P4SETMASK(wb); 1647145256Sjkoshy break; 1648145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1649145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1650145256Sjkoshy case PMC_EV_P4_BNR: 1651145256Sjkoshy case PMC_EV_P4_SNOOP: 1652145256Sjkoshy case PMC_EV_P4_RESPONSE: 1653145256Sjkoshy break; 1654145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1655145256Sjkoshy __P4SETMASK(fee); 1656145256Sjkoshy break; 1657145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1658145256Sjkoshy __P4SETMASK(ee); 1659145256Sjkoshy break; 1660145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1661145256Sjkoshy __P4SETMASK(re); 1662145256Sjkoshy break; 1663145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1664145256Sjkoshy __P4SETMASK(insret); 1665145256Sjkoshy break; 1666145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1667145256Sjkoshy __P4SETMASK(ur); 1668145256Sjkoshy break; 1669145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1670145256Sjkoshy __P4SETMASK(ut); 1671145256Sjkoshy break; 1672145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1673145256Sjkoshy __P4SETMASK(br); 1674145256Sjkoshy break; 1675145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1676145256Sjkoshy __P4SETMASK(mbr); 1677145256Sjkoshy break; 1678145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1679145256Sjkoshy __P4SETMASK(xa); 1680145256Sjkoshy break; 1681145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1682145256Sjkoshy __P4SETMASK(machclr); 1683145256Sjkoshy break; 1684145256Sjkoshy default: 1685174406Sjkoshy return (-1); 1686145256Sjkoshy } 1687145256Sjkoshy 1688145256Sjkoshy /* process additional flags */ 1689145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1690145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1691145256Sjkoshy q = strchr(p, '='); 1692145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1693174406Sjkoshy return (-1); 1694145256Sjkoshy 1695183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1696145256Sjkoshy cccractivemask = 0x0; 1697183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1698145256Sjkoshy cccractivemask = 0x1; 1699183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1700145256Sjkoshy cccractivemask = 0x2; 1701183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1702145256Sjkoshy cccractivemask = 0x3; 1703145256Sjkoshy else 1704174406Sjkoshy return (-1); 1705145256Sjkoshy 1706145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1707145256Sjkoshy if (has_busreqtype == 0) 1708174406Sjkoshy return (-1); 1709145256Sjkoshy 1710145256Sjkoshy q = strchr(p, '='); 1711145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1712174406Sjkoshy return (-1); 1713145256Sjkoshy 1714145256Sjkoshy count = strtol(q, &e, 0); 1715145256Sjkoshy if (e == q || *e != '\0') 1716174406Sjkoshy return (-1); 1717145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1718145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1719145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1720145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1721145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1722145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1723145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1724145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1725145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1726174406Sjkoshy return (-1); 1727145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1728145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1729145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1730145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1731145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1732145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1733145256Sjkoshy if (has_tag == 0) 1734174406Sjkoshy return (-1); 1735145256Sjkoshy 1736145256Sjkoshy q = strchr(p, '='); 1737145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1738174406Sjkoshy return (-1); 1739145256Sjkoshy 1740145256Sjkoshy count = strtol(q, &e, 0); 1741145256Sjkoshy if (e == q || *e != '\0') 1742174406Sjkoshy return (-1); 1743145256Sjkoshy 1744145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1745147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1746145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1747145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1748145256Sjkoshy q = strchr(p, '='); 1749145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1750174406Sjkoshy return (-1); 1751145256Sjkoshy 1752145256Sjkoshy count = strtol(q, &e, 0); 1753145256Sjkoshy if (e == q || *e != '\0') 1754174406Sjkoshy return (-1); 1755145256Sjkoshy 1756145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1757147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1758147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1759147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1760147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1761145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1762145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1763145256Sjkoshy else 1764174406Sjkoshy return (-1); 1765145256Sjkoshy } 1766145256Sjkoshy 1767145256Sjkoshy /* other post processing */ 1768145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1769145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1770145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1771145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1772145256Sjkoshy 1773145256Sjkoshy /* fill in thread activity mask */ 1774147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1775145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1776145256Sjkoshy 1777145256Sjkoshy if (evmask) 1778145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1779145256Sjkoshy 1780145256Sjkoshy switch (pe) { 1781145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1782145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1783145256Sjkoshy (evmask & 0x18) == 0x18) 1784174406Sjkoshy return (-1); /* can't have own+other bits together */ 1785145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1786145256Sjkoshy evmask = 0x1D; 1787145256Sjkoshy break; 1788145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1789145256Sjkoshy /* only one bit is allowed to be set */ 1790145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1791174406Sjkoshy return (-1); 1792145256Sjkoshy if (evmask == 0) { 1793183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1794145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1795145256Sjkoshy } 1796145256Sjkoshy break; 1797145256Sjkoshy default: 1798145256Sjkoshy if (evmask == 0 && pmask) { 1799145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1800145256Sjkoshy evmask |= pm->pm_value; 1801145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1802145256Sjkoshy } 1803145256Sjkoshy } 1804145256Sjkoshy 1805147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1806147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1807145256Sjkoshy 1808174406Sjkoshy return (0); 1809145256Sjkoshy} 1810145256Sjkoshy 1811147759Sjkoshy#endif 1812147759Sjkoshy 1813147759Sjkoshy#if defined(__i386__) 1814147759Sjkoshy 1815145256Sjkoshy/* 1816147191Sjkoshy * Pentium style PMCs 1817147191Sjkoshy */ 1818147191Sjkoshy 1819147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1820183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1821183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1822183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1823183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1824183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1825183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1826183105Sjkoshy EV_ALIAS("unhalted-cycles", 1827183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1828147191Sjkoshy EV_ALIAS(NULL, NULL) 1829147191Sjkoshy}; 1830147191Sjkoshy 1831147191Sjkoshystatic int 1832147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1833147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1834147191Sjkoshy{ 1835174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1836147191Sjkoshy} 1837147191Sjkoshy 1838147191Sjkoshy/* 1839145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1840145256Sjkoshy * and Pentium M CPUs. 1841145256Sjkoshy */ 1842145256Sjkoshy 1843145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1844145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1845145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1846145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1847145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1848168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1849145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1850145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1851155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1852145351Sjkoshy EV_ALIAS(NULL, NULL) 1853145256Sjkoshy}; 1854145256Sjkoshy 1855145256Sjkoshy#define P6_KW_CMASK "cmask" 1856145256Sjkoshy#define P6_KW_EDGE "edge" 1857145256Sjkoshy#define P6_KW_INV "inv" 1858145256Sjkoshy#define P6_KW_OS "os" 1859145256Sjkoshy#define P6_KW_UMASK "umask" 1860145256Sjkoshy#define P6_KW_USR "usr" 1861145256Sjkoshy 1862145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1863145256Sjkoshy PMCMASK(m, 0x01), 1864145256Sjkoshy PMCMASK(e, 0x02), 1865145256Sjkoshy PMCMASK(s, 0x04), 1866145256Sjkoshy PMCMASK(i, 0x08), 1867145256Sjkoshy NULLMASK 1868145256Sjkoshy}; 1869145256Sjkoshy 1870145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1871145256Sjkoshy PMCMASK(m, 0x01), 1872145256Sjkoshy PMCMASK(e, 0x02), 1873145256Sjkoshy PMCMASK(s, 0x04), 1874145256Sjkoshy PMCMASK(i, 0x08), 1875145256Sjkoshy PMCMASK(nonhw, 0x00), 1876145256Sjkoshy PMCMASK(hw, 0x10), 1877145256Sjkoshy PMCMASK(both, 0x30), 1878145256Sjkoshy NULLMASK 1879145256Sjkoshy}; 1880145256Sjkoshy 1881145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1882145256Sjkoshy PMCMASK(nonhw, 0x00), 1883145256Sjkoshy PMCMASK(hw, 0x10), 1884145256Sjkoshy PMCMASK(both, 0x30), 1885145256Sjkoshy NULLMASK 1886145256Sjkoshy}; 1887145256Sjkoshy 1888145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1889145256Sjkoshy PMCMASK(self, 0x00), 1890145256Sjkoshy PMCMASK(any, 0x20), 1891145256Sjkoshy NULLMASK 1892145256Sjkoshy}; 1893145256Sjkoshy 1894145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1895145256Sjkoshy PMCMASK(nta, 0x00), 1896145256Sjkoshy PMCMASK(t1, 0x01), 1897145256Sjkoshy PMCMASK(t2, 0x02), 1898145256Sjkoshy PMCMASK(wos, 0x03), 1899145256Sjkoshy NULLMASK 1900145256Sjkoshy}; 1901145256Sjkoshy 1902145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1903145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1904145256Sjkoshy PMCMASK(scalar, 0x01), 1905145256Sjkoshy NULLMASK 1906145256Sjkoshy}; 1907145256Sjkoshy 1908145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1909145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1910145256Sjkoshy PMCMASK(packed-shift, 0x02), 1911145256Sjkoshy PMCMASK(pack, 0x04), 1912145256Sjkoshy PMCMASK(unpack, 0x08), 1913145256Sjkoshy PMCMASK(packed-logical, 0x10), 1914145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1915145256Sjkoshy NULLMASK 1916145256Sjkoshy}; 1917145256Sjkoshy 1918145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1919145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1920145256Sjkoshy PMCMASK(fptommx, 0x01), 1921145256Sjkoshy NULLMASK 1922145256Sjkoshy}; 1923145256Sjkoshy 1924145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 1925145256Sjkoshy PMCMASK(es, 0x01), 1926145256Sjkoshy PMCMASK(ds, 0x02), 1927145256Sjkoshy PMCMASK(fs, 0x04), 1928145256Sjkoshy PMCMASK(gs, 0x08), 1929145256Sjkoshy NULLMASK 1930145256Sjkoshy}; 1931145256Sjkoshy 1932145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 1933145256Sjkoshy PMCMASK(all, 0x00), 1934145256Sjkoshy PMCMASK(freq, 0x02), 1935145256Sjkoshy NULLMASK 1936145256Sjkoshy}; 1937145256Sjkoshy 1938145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1939145256Sjkoshy PMCMASK(all, 0x00), 1940145256Sjkoshy PMCMASK(loadop, 0x01), 1941145256Sjkoshy PMCMASK(stdsta, 0x02), 1942145256Sjkoshy NULLMASK 1943145256Sjkoshy}; 1944145256Sjkoshy 1945145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1946145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1947145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1948145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1949145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1950145256Sjkoshy NULLMASK 1951145256Sjkoshy}; 1952145256Sjkoshy 1953145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1954145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1955145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1956145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1957145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1958145256Sjkoshy NULLMASK 1959145256Sjkoshy}; 1960145256Sjkoshy 1961145256Sjkoshy/* P6 event parser */ 1962145256Sjkoshystatic int 1963145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1964145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1965145256Sjkoshy{ 1966145256Sjkoshy char *e, *p, *q; 1967145256Sjkoshy uint32_t evmask; 1968145256Sjkoshy int count, n; 1969145256Sjkoshy const struct pmc_masks *pm, *pmask; 1970145256Sjkoshy 1971183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1972147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 1973145256Sjkoshy 1974145256Sjkoshy evmask = 0; 1975145256Sjkoshy 1976145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1977145256Sjkoshy 1978145256Sjkoshy switch(pe) { 1979183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1980145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1981145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 1982145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 1983145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1984145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1985145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1986145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1987145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1988145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1989145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1990145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1991145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1992145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1993145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1994145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1995145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1996145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1997145256Sjkoshy P6MASKSET(any); break; 1998145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1999145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2000145256Sjkoshy P6MASKSET(ekp); break; 2001145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2002145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2003145256Sjkoshy P6MASKSET(pps); break; 2004145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2005145256Sjkoshy P6MASKSET(mite); break; 2006145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2007145256Sjkoshy P6MASKSET(fmt); break; 2008145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2009145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2010145256Sjkoshy P6MASKSET(sr); break; 2011145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2012145256Sjkoshy P6MASKSET(eet); break; 2013145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2014145256Sjkoshy P6MASKSET(efur); break; 2015145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2016145256Sjkoshy P6MASKSET(essir); break; 2017145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2018145256Sjkoshy P6MASKSET(esscir); break; 2019145256Sjkoshy default: 2020145256Sjkoshy pmask = NULL; 2021145256Sjkoshy break; 2022145256Sjkoshy } 2023145256Sjkoshy 2024145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2025145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2026145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2027145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2028145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2029145256Sjkoshy P6MASKSET(mesihw); 2030145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2031145256Sjkoshy P6MASKSET(hw); 2032145256Sjkoshy } 2033145256Sjkoshy 2034145256Sjkoshy /* Parse additional modifiers if present */ 2035145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2036145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2037145256Sjkoshy q = strchr(p, '='); 2038145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2039174406Sjkoshy return (-1); 2040145256Sjkoshy count = strtol(q, &e, 0); 2041145256Sjkoshy if (e == q || *e != '\0') 2042174406Sjkoshy return (-1); 2043145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2044147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2045147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2046145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2047145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2048145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2049145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2050145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2051145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2052145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2053145256Sjkoshy evmask = 0; 2054145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2055174406Sjkoshy return (-1); 2056145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2057145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2058145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2059145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2060145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2061145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2062145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2063145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2064145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2065145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2066145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2067145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2068145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2069145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2070145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2071145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2072145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2073145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2074145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2075145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2076145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2077145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2078145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2079174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2080174406Sjkoshy return (-1); 2081145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2082145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2083145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2084145256Sjkoshy } else 2085174406Sjkoshy return (-1); 2086145256Sjkoshy } 2087145256Sjkoshy 2088145256Sjkoshy /* post processing */ 2089145256Sjkoshy switch (pe) { 2090145256Sjkoshy 2091145256Sjkoshy /* 2092145256Sjkoshy * The following events default to an evmask of 0 2093145256Sjkoshy */ 2094145256Sjkoshy 2095145256Sjkoshy /* default => 'self' */ 2096145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2097145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2098145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2099145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2100145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2101145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2102145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2103145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2104145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2105145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2106145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2107145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2108145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2109145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2110145256Sjkoshy 2111145256Sjkoshy /* default => 'nta' */ 2112145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2113145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2114145256Sjkoshy 2115145256Sjkoshy /* default => 'packed and scalar' */ 2116145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2117145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2118145256Sjkoshy 2119145256Sjkoshy /* default => 'mmx to fp transitions' */ 2120145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2121145256Sjkoshy 2122145256Sjkoshy /* default => 'SSE Packed Single' */ 2123145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2124145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2125145256Sjkoshy 2126145256Sjkoshy /* default => 'all fused micro-ops' */ 2127145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2128145256Sjkoshy 2129145256Sjkoshy /* default => 'all transitions' */ 2130145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2131145256Sjkoshy break; 2132145256Sjkoshy 2133145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2134145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2135145256Sjkoshy break; 2136145256Sjkoshy 2137145256Sjkoshy default: 2138145256Sjkoshy /* 2139145256Sjkoshy * For all other events, set the default event mask 2140145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2141145256Sjkoshy */ 2142145256Sjkoshy if (evmask == 0 && pmask) { 2143145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2144145256Sjkoshy evmask |= pm->pm_value; 2145145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2146145256Sjkoshy } 2147145256Sjkoshy 2148145256Sjkoshy break; 2149145256Sjkoshy } 2150145256Sjkoshy 2151145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2152147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2153147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2154145256Sjkoshy 2155174406Sjkoshy return (0); 2156145256Sjkoshy} 2157145256Sjkoshy 2158147191Sjkoshy#endif 2159147191Sjkoshy 2160183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2161183725Sjkoshystatic int 2162183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2163183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2164183725Sjkoshy{ 2165183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2166183725Sjkoshy return (-1); 2167183725Sjkoshy 2168183725Sjkoshy /* TSC events must be unqualified. */ 2169183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2170183725Sjkoshy return (-1); 2171183725Sjkoshy 2172183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2173183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2174183725Sjkoshy 2175183725Sjkoshy return (0); 2176183725Sjkoshy} 2177183725Sjkoshy#endif 2178183725Sjkoshy 2179200928Srpaulo#if defined(__XSCALE__) 2180200928Srpaulo 2181200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2182200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2183200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2184200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2185200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2186200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2187200928Srpaulo EV_ALIAS(NULL, NULL) 2188200928Srpaulo}; 2189200928Srpaulostatic int 2190200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2191200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2192200928Srpaulo{ 2193200928Srpaulo switch (pe) { 2194200928Srpaulo default: 2195200928Srpaulo break; 2196200928Srpaulo } 2197200928Srpaulo 2198200928Srpaulo return (0); 2199200928Srpaulo} 2200200928Srpaulo#endif 2201200928Srpaulo 2202204635Sgnn#if defined(__mips__) 2203204635Sgnn 2204204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2205204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2206204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2207204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2208204635Sgnn EV_ALIAS(NULL, NULL) 2209204635Sgnn}; 2210204635Sgnn 2211233320Sgonzo#define MIPS_KW_OS "os" 2212233320Sgonzo#define MIPS_KW_USR "usr" 2213233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2214204635Sgnn 2215204635Sgnnstatic int 2216233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2217204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2218204635Sgnn{ 2219204635Sgnn char *p; 2220204635Sgnn 2221204635Sgnn (void) pe; 2222204635Sgnn 2223204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2224204635Sgnn 2225204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2226233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2227204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2228233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2229204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2230233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2231204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2232204635Sgnn else 2233204635Sgnn return (-1); 2234204635Sgnn } 2235204635Sgnn 2236204635Sgnn return (0); 2237204635Sgnn} 2238233320Sgonzo 2239204635Sgnn#endif /* __mips__ */ 2240204635Sgnn 2241228869Sjhibbits#if defined(__powerpc__) 2242204635Sgnn 2243228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2244228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2245228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2246228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2247228869Sjhibbits EV_ALIAS(NULL, NULL) 2248228869Sjhibbits}; 2249228869Sjhibbits 2250228869Sjhibbits#define PPC7450_KW_OS "os" 2251228869Sjhibbits#define PPC7450_KW_USR "usr" 2252228869Sjhibbits#define PPC7450_KW_ANYTHREAD "anythread" 2253228869Sjhibbits 2254228869Sjhibbitsstatic int 2255228869Sjhibbitsppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2256228869Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2257228869Sjhibbits{ 2258228869Sjhibbits char *p; 2259228869Sjhibbits 2260228869Sjhibbits (void) pe; 2261228869Sjhibbits 2262228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2263228869Sjhibbits 2264228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2265228869Sjhibbits if (KWMATCH(p, PPC7450_KW_OS)) 2266228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2267228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_USR)) 2268228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2269228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_ANYTHREAD)) 2270228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2271228869Sjhibbits else 2272228869Sjhibbits return (-1); 2273228869Sjhibbits } 2274228869Sjhibbits 2275228869Sjhibbits return (0); 2276228869Sjhibbits} 2277228869Sjhibbits#endif /* __powerpc__ */ 2278228869Sjhibbits 2279228869Sjhibbits 2280145256Sjkoshy/* 2281183725Sjkoshy * Match an event name `name' with its canonical form. 2282183725Sjkoshy * 2283185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2284185363Sjkoshy * hyphen characters are considered to match each other. 2285185363Sjkoshy * 2286183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2287183725Sjkoshy */ 2288183725Sjkoshy 2289183725Sjkoshystatic int 2290183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2291183725Sjkoshy{ 2292183725Sjkoshy int cc, nc; 2293183725Sjkoshy const unsigned char *c, *n; 2294183725Sjkoshy 2295183725Sjkoshy c = (const unsigned char *) canonicalname; 2296183725Sjkoshy n = (const unsigned char *) name; 2297183725Sjkoshy 2298183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2299183725Sjkoshy 2300185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2301185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2302183725Sjkoshy continue; 2303183725Sjkoshy 2304185363Sjkoshy if (toupper(nc) == toupper(cc)) 2305183725Sjkoshy continue; 2306183725Sjkoshy 2307185363Sjkoshy 2308183725Sjkoshy return (0); 2309183725Sjkoshy } 2310183725Sjkoshy 2311183725Sjkoshy if (*n == '\0' && *c == '\0') 2312183725Sjkoshy return (1); 2313183725Sjkoshy 2314183725Sjkoshy return (0); 2315183725Sjkoshy} 2316183725Sjkoshy 2317183725Sjkoshy/* 2318183725Sjkoshy * Match an event name against all the event named supported by a 2319183725Sjkoshy * PMC class. 2320183725Sjkoshy * 2321183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2322183725Sjkoshy */ 2323183725Sjkoshystatic const struct pmc_event_descr * 2324183725Sjkoshypmc_match_event_class(const char *name, 2325183725Sjkoshy const struct pmc_class_descr *pcd) 2326183725Sjkoshy{ 2327183725Sjkoshy size_t n; 2328183725Sjkoshy const struct pmc_event_descr *ev; 2329185363Sjkoshy 2330183725Sjkoshy ev = pcd->pm_evc_event_table; 2331183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2332183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2333183725Sjkoshy return (ev); 2334183725Sjkoshy 2335183725Sjkoshy return (NULL); 2336183725Sjkoshy} 2337183725Sjkoshy 2338183725Sjkoshystatic int 2339183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2340183725Sjkoshy{ 2341183725Sjkoshy size_t n; 2342183725Sjkoshy 2343183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2344183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2345183725Sjkoshy return (1); 2346183725Sjkoshy return (0); 2347183725Sjkoshy} 2348183725Sjkoshy 2349183725Sjkoshy/* 2350147191Sjkoshy * API entry points 2351145256Sjkoshy */ 2352145256Sjkoshy 2353147191Sjkoshyint 2354147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2355147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2356145256Sjkoshy{ 2357183725Sjkoshy size_t n; 2358147191Sjkoshy int retval; 2359147191Sjkoshy char *r, *spec_copy; 2360147191Sjkoshy const char *ctrname; 2361183725Sjkoshy const struct pmc_event_descr *ev; 2362183725Sjkoshy const struct pmc_event_alias *alias; 2363147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2364183725Sjkoshy const struct pmc_class_descr *pcd; 2365145256Sjkoshy 2366147191Sjkoshy spec_copy = NULL; 2367147191Sjkoshy retval = -1; 2368145256Sjkoshy 2369147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2370147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2371147191Sjkoshy errno = EINVAL; 2372147191Sjkoshy goto out; 2373147191Sjkoshy } 2374145256Sjkoshy 2375147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2376147191Sjkoshy if (pmc_mdep_event_aliases) 2377183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2378183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2379183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2380147191Sjkoshy break; 2381147191Sjkoshy } 2382145256Sjkoshy 2383147191Sjkoshy if (spec_copy == NULL) 2384147191Sjkoshy spec_copy = strdup(ctrspec); 2385145256Sjkoshy 2386147191Sjkoshy r = spec_copy; 2387147191Sjkoshy ctrname = strsep(&r, ","); 2388145256Sjkoshy 2389183725Sjkoshy /* 2390183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2391183725Sjkoshy * search for the event to the specified PMC class. 2392183725Sjkoshy */ 2393183725Sjkoshy ev = NULL; 2394185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2395185363Sjkoshy pcd = pmc_class_table[n]; 2396183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2397183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2398183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2399183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2400183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2401183725Sjkoshy errno = EINVAL; 2402183725Sjkoshy goto out; 2403183725Sjkoshy } 2404147191Sjkoshy break; 2405183725Sjkoshy } 2406183725Sjkoshy } 2407145256Sjkoshy 2408183725Sjkoshy /* 2409183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2410183725Sjkoshy * classes. 2411183725Sjkoshy */ 2412185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2413185363Sjkoshy pcd = pmc_class_table[n]; 2414183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2415183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2416183725Sjkoshy } 2417183725Sjkoshy 2418183725Sjkoshy if (ev == NULL) { 2419147191Sjkoshy errno = EINVAL; 2420147191Sjkoshy goto out; 2421147191Sjkoshy } 2422145256Sjkoshy 2423147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2424183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2425183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2426147191Sjkoshy pmc_config.pm_cpu = cpu; 2427147191Sjkoshy pmc_config.pm_mode = mode; 2428147191Sjkoshy pmc_config.pm_flags = flags; 2429145256Sjkoshy 2430147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2431147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2432145256Sjkoshy 2433183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2434147191Sjkoshy errno = EINVAL; 2435147191Sjkoshy goto out; 2436147191Sjkoshy } 2437145256Sjkoshy 2438147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2439147191Sjkoshy goto out; 2440145256Sjkoshy 2441147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2442145256Sjkoshy 2443147191Sjkoshy retval = 0; 2444145256Sjkoshy 2445147191Sjkoshy out: 2446147191Sjkoshy if (spec_copy) 2447147191Sjkoshy free(spec_copy); 2448145256Sjkoshy 2449174406Sjkoshy return (retval); 2450147191Sjkoshy} 2451145256Sjkoshy 2452147191Sjkoshyint 2453147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2454147191Sjkoshy{ 2455147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2456145256Sjkoshy 2457147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2458147191Sjkoshy pmc_attach_args.pm_pid = pid; 2459145256Sjkoshy 2460174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2461147191Sjkoshy} 2462145256Sjkoshy 2463147191Sjkoshyint 2464147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2465147191Sjkoshy{ 2466147191Sjkoshy unsigned int i; 2467147191Sjkoshy enum pmc_class cl; 2468145256Sjkoshy 2469147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2470147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2471147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2472147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2473174406Sjkoshy return (0); 2474147191Sjkoshy } 2475177107Sjkoshy errno = EINVAL; 2476177107Sjkoshy return (-1); 2477147191Sjkoshy} 2478145256Sjkoshy 2479147191Sjkoshyint 2480147191Sjkoshypmc_configure_logfile(int fd) 2481147191Sjkoshy{ 2482147191Sjkoshy struct pmc_op_configurelog cla; 2483145256Sjkoshy 2484147191Sjkoshy cla.pm_logfd = fd; 2485147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2486174406Sjkoshy return (-1); 2487174406Sjkoshy return (0); 2488147191Sjkoshy} 2489145256Sjkoshy 2490147191Sjkoshyint 2491147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2492147191Sjkoshy{ 2493147191Sjkoshy if (pmc_syscall == -1) { 2494147191Sjkoshy errno = ENXIO; 2495174406Sjkoshy return (-1); 2496147191Sjkoshy } 2497145256Sjkoshy 2498147219Sjkoshy *pci = &cpu_info; 2499174406Sjkoshy return (0); 2500147191Sjkoshy} 2501145256Sjkoshy 2502147191Sjkoshyint 2503147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2504147191Sjkoshy{ 2505147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2506145256Sjkoshy 2507147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2508147191Sjkoshy pmc_detach_args.pm_pid = pid; 2509174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2510147191Sjkoshy} 2511147191Sjkoshy 2512147191Sjkoshyint 2513147191Sjkoshypmc_disable(int cpu, int pmc) 2514145256Sjkoshy{ 2515147191Sjkoshy struct pmc_op_pmcadmin ssa; 2516145256Sjkoshy 2517147191Sjkoshy ssa.pm_cpu = cpu; 2518147191Sjkoshy ssa.pm_pmc = pmc; 2519147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2520174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2521147191Sjkoshy} 2522145256Sjkoshy 2523147191Sjkoshyint 2524147191Sjkoshypmc_enable(int cpu, int pmc) 2525147191Sjkoshy{ 2526147191Sjkoshy struct pmc_op_pmcadmin ssa; 2527145256Sjkoshy 2528147191Sjkoshy ssa.pm_cpu = cpu; 2529147191Sjkoshy ssa.pm_pmc = pmc; 2530147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2531174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2532147191Sjkoshy} 2533145256Sjkoshy 2534147191Sjkoshy/* 2535147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2536147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2537147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2538147191Sjkoshy * the number of event name pointers returned. 2539147191Sjkoshy * 2540147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2541147191Sjkoshy * is responsible for freeing this space when done. 2542147191Sjkoshy */ 2543147191Sjkoshyint 2544147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2545147191Sjkoshy int *nevents) 2546147191Sjkoshy{ 2547147191Sjkoshy int count; 2548147191Sjkoshy const char **names; 2549147191Sjkoshy const struct pmc_event_descr *ev; 2550147191Sjkoshy 2551147191Sjkoshy switch (cl) 2552147191Sjkoshy { 2553185363Sjkoshy case PMC_CLASS_IAF: 2554185363Sjkoshy ev = iaf_event_table; 2555185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2556185363Sjkoshy break; 2557185363Sjkoshy case PMC_CLASS_IAP: 2558185363Sjkoshy /* 2559185363Sjkoshy * Return the most appropriate set of event name 2560185363Sjkoshy * spellings for the current CPU. 2561185363Sjkoshy */ 2562185363Sjkoshy switch (cpu_info.pm_cputype) { 2563185363Sjkoshy default: 2564185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2565185363Sjkoshy ev = atom_event_table; 2566185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2567185363Sjkoshy break; 2568185363Sjkoshy case PMC_CPU_INTEL_CORE: 2569185363Sjkoshy ev = core_event_table; 2570185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2571185363Sjkoshy break; 2572185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2573185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2574185363Sjkoshy ev = core2_event_table; 2575185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2576185363Sjkoshy break; 2577187761Sjeff case PMC_CPU_INTEL_COREI7: 2578187761Sjeff ev = corei7_event_table; 2579187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2580187761Sjeff break; 2581232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2582232366Sdavide ev = sandybridge_event_table; 2583232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2584232366Sdavide break; 2585206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2586206089Sfabient ev = westmere_event_table; 2587206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2588206089Sfabient break; 2589185363Sjkoshy } 2590185363Sjkoshy break; 2591206089Sfabient case PMC_CLASS_UCF: 2592206089Sfabient ev = ucf_event_table; 2593206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2594206089Sfabient break; 2595206089Sfabient case PMC_CLASS_UCP: 2596206089Sfabient /* 2597206089Sfabient * Return the most appropriate set of event name 2598206089Sfabient * spellings for the current CPU. 2599206089Sfabient */ 2600206089Sfabient switch (cpu_info.pm_cputype) { 2601206089Sfabient default: 2602206089Sfabient case PMC_CPU_INTEL_COREI7: 2603206089Sfabient ev = corei7uc_event_table; 2604206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2605206089Sfabient break; 2606232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2607232366Sdavide ev = sandybridgeuc_event_table; 2608232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2609232366Sdavide break; 2610206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2611206089Sfabient ev = westmereuc_event_table; 2612206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2613206089Sfabient break; 2614206089Sfabient } 2615206089Sfabient break; 2616147191Sjkoshy case PMC_CLASS_TSC: 2617183725Sjkoshy ev = tsc_event_table; 2618183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2619145256Sjkoshy break; 2620147191Sjkoshy case PMC_CLASS_K7: 2621183725Sjkoshy ev = k7_event_table; 2622183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2623145256Sjkoshy break; 2624147191Sjkoshy case PMC_CLASS_K8: 2625183725Sjkoshy ev = k8_event_table; 2626183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2627145256Sjkoshy break; 2628183725Sjkoshy case PMC_CLASS_P4: 2629183725Sjkoshy ev = p4_event_table; 2630183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2631183725Sjkoshy break; 2632147191Sjkoshy case PMC_CLASS_P5: 2633183725Sjkoshy ev = p5_event_table; 2634183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2635145256Sjkoshy break; 2636147191Sjkoshy case PMC_CLASS_P6: 2637183725Sjkoshy ev = p6_event_table; 2638183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2639145256Sjkoshy break; 2640200928Srpaulo case PMC_CLASS_XSCALE: 2641200928Srpaulo ev = xscale_event_table; 2642200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2643200928Srpaulo break; 2644204635Sgnn case PMC_CLASS_MIPS24K: 2645204635Sgnn ev = mips24k_event_table; 2646204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2647204635Sgnn break; 2648228869Sjhibbits case PMC_CLASS_PPC7450: 2649228869Sjhibbits ev = ppc7450_event_table; 2650228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2651228869Sjhibbits break; 2652145256Sjkoshy default: 2653147191Sjkoshy errno = EINVAL; 2654174406Sjkoshy return (-1); 2655145256Sjkoshy } 2656145256Sjkoshy 2657147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2658174406Sjkoshy return (-1); 2659145256Sjkoshy 2660147191Sjkoshy *eventnames = names; 2661147191Sjkoshy *nevents = count; 2662145256Sjkoshy 2663147191Sjkoshy for (;count--; ev++, names++) 2664147191Sjkoshy *names = ev->pm_ev_name; 2665174406Sjkoshy return (0); 2666147191Sjkoshy} 2667145256Sjkoshy 2668147191Sjkoshyint 2669147191Sjkoshypmc_flush_logfile(void) 2670147191Sjkoshy{ 2671174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2672147191Sjkoshy} 2673145256Sjkoshy 2674147191Sjkoshyint 2675226514Sfabientpmc_close_logfile(void) 2676226514Sfabient{ 2677226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2678226514Sfabient} 2679226514Sfabient 2680226514Sfabientint 2681147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2682147191Sjkoshy{ 2683147191Sjkoshy struct pmc_op_getdriverstats gms; 2684145256Sjkoshy 2685147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2686174406Sjkoshy return (-1); 2687145256Sjkoshy 2688147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2689147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2690147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2691147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2692147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2693147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2694147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2695147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2696147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2697174406Sjkoshy return (0); 2698147191Sjkoshy} 2699145256Sjkoshy 2700147191Sjkoshyint 2701147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2702147191Sjkoshy{ 2703147191Sjkoshy struct pmc_op_getmsr gm; 2704147191Sjkoshy 2705147191Sjkoshy gm.pm_pmcid = pmc; 2706147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2707174406Sjkoshy return (-1); 2708147191Sjkoshy *msr = gm.pm_msr; 2709174406Sjkoshy return (0); 2710145256Sjkoshy} 2711145256Sjkoshy 2712145256Sjkoshyint 2713145256Sjkoshypmc_init(void) 2714145256Sjkoshy{ 2715145256Sjkoshy int error, pmc_mod_id; 2716147219Sjkoshy unsigned int n; 2717145256Sjkoshy uint32_t abi_version; 2718145256Sjkoshy struct module_stat pmc_modstat; 2719147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2720198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2721198433Sjkoshy int cpu_has_iaf_counters; 2722198433Sjkoshy unsigned int t; 2723198433Sjkoshy#endif 2724145256Sjkoshy 2725145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2726174406Sjkoshy return (0); 2727145256Sjkoshy 2728145256Sjkoshy /* retrieve the system call number from the KLD */ 2729145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2730174406Sjkoshy return (-1); 2731145256Sjkoshy 2732145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2733145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2734174406Sjkoshy return (-1); 2735145256Sjkoshy 2736145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2737145256Sjkoshy 2738147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2739147191Sjkoshy abi_version = PMC_VERSION; 2740145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2741145256Sjkoshy return (pmc_syscall = -1); 2742145256Sjkoshy 2743147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2744147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2745145256Sjkoshy errno = EPROGMISMATCH; 2746145256Sjkoshy return (pmc_syscall = -1); 2747145256Sjkoshy } 2748145256Sjkoshy 2749147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2750145256Sjkoshy return (pmc_syscall = -1); 2751145256Sjkoshy 2752147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2753147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2754147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2755147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2756147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2757147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2758147219Sjkoshy 2759185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2760185363Sjkoshy sizeof(struct pmc_class_descr *)); 2761185363Sjkoshy 2762185363Sjkoshy if (pmc_class_table == NULL) 2763185363Sjkoshy return (-1); 2764185363Sjkoshy 2765198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2766198433Sjkoshy pmc_class_table[n] = NULL; 2767185363Sjkoshy 2768185363Sjkoshy /* 2769185363Sjkoshy * Fill in the class table. 2770185363Sjkoshy */ 2771185363Sjkoshy n = 0; 2772185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 2773185363Sjkoshy pmc_class_table[n++] = &tsc_class_table_descr; 2774198433Sjkoshy 2775198433Sjkoshy /* 2776198433Sjkoshy * Check if this CPU has fixed function counters. 2777198433Sjkoshy */ 2778198433Sjkoshy cpu_has_iaf_counters = 0; 2779198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 2780212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 2781212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 2782198433Sjkoshy cpu_has_iaf_counters = 1; 2783185363Sjkoshy#endif 2784185363Sjkoshy 2785183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 2786183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 2787183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 2788183725Sjkoshy pmc_mdep_class_list_size = \ 2789183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 2790183725Sjkoshy } while (0) 2791183725Sjkoshy 2792198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 2793198433Sjkoshy PMC_MDEP_INIT(C); \ 2794212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 2795212224Sfabient if (!cpu_has_iaf_counters) \ 2796198433Sjkoshy pmc_mdep_event_aliases = \ 2797198433Sjkoshy C##_aliases_without_iaf; \ 2798198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 2799198433Sjkoshy } while (0) 2800198433Sjkoshy 2801183725Sjkoshy /* Configure the event name parser. */ 2802145256Sjkoshy switch (cpu_info.pm_cputype) { 2803145340Smarcel#if defined(__i386__) 2804145256Sjkoshy case PMC_CPU_AMD_K7: 2805183725Sjkoshy PMC_MDEP_INIT(k7); 2806185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 2807145256Sjkoshy break; 2808145256Sjkoshy case PMC_CPU_INTEL_P5: 2809183725Sjkoshy PMC_MDEP_INIT(p5); 2810185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 2811145256Sjkoshy break; 2812145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 2813145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 2814145256Sjkoshy case PMC_CPU_INTEL_PIII: 2815145256Sjkoshy case PMC_CPU_INTEL_PM: 2816183725Sjkoshy PMC_MDEP_INIT(p6); 2817185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 2818145256Sjkoshy break; 2819147759Sjkoshy#endif 2820147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 2821183725Sjkoshy case PMC_CPU_AMD_K8: 2822183725Sjkoshy PMC_MDEP_INIT(k8); 2823185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 2824183725Sjkoshy break; 2825185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2826198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 2827185363Sjkoshy break; 2828185363Sjkoshy case PMC_CPU_INTEL_CORE: 2829185363Sjkoshy PMC_MDEP_INIT(core); 2830202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 2831185363Sjkoshy break; 2832185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2833185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2834198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 2835185363Sjkoshy break; 2836187761Sjeff case PMC_CPU_INTEL_COREI7: 2837206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2838206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 2839198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 2840187761Sjeff break; 2841232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2842232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 2843232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 2844232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 2845232366Sdavide break; 2846206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2847206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2848206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 2849206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 2850206089Sfabient break; 2851145256Sjkoshy case PMC_CPU_INTEL_PIV: 2852183725Sjkoshy PMC_MDEP_INIT(p4); 2853185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 2854145256Sjkoshy break; 2855145256Sjkoshy#endif 2856200928Srpaulo#if defined(__XSCALE__) 2857200928Srpaulo case PMC_CPU_INTEL_XSCALE: 2858200928Srpaulo PMC_MDEP_INIT(xscale); 2859200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 2860200928Srpaulo break; 2861200928Srpaulo#endif 2862204635Sgnn#if defined(__mips__) 2863204635Sgnn case PMC_CPU_MIPS_24K: 2864204635Sgnn PMC_MDEP_INIT(mips24k); 2865204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 2866204635Sgnn break; 2867204635Sgnn#endif /* __mips__ */ 2868228869Sjhibbits#if defined(__powerpc__) 2869228869Sjhibbits case PMC_CPU_PPC_7450: 2870228869Sjhibbits PMC_MDEP_INIT(ppc7450); 2871228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 2872228869Sjhibbits break; 2873228869Sjhibbits#endif 2874145256Sjkoshy default: 2875145256Sjkoshy /* 2876145256Sjkoshy * Some kind of CPU this version of the library knows nothing 2877145256Sjkoshy * about. This shouldn't happen since the abi version check 2878145256Sjkoshy * should have caught this. 2879145256Sjkoshy */ 2880145256Sjkoshy errno = ENXIO; 2881145256Sjkoshy return (pmc_syscall = -1); 2882145256Sjkoshy } 2883145256Sjkoshy 2884174406Sjkoshy return (0); 2885145256Sjkoshy} 2886145256Sjkoshy 2887147191Sjkoshyconst char * 2888147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 2889145256Sjkoshy{ 2890147191Sjkoshy int i; 2891145256Sjkoshy 2892147191Sjkoshy /* 2893147191Sjkoshy * 'cap' should have a single bit set and should be in 2894147191Sjkoshy * range. 2895147191Sjkoshy */ 2896147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 2897147191Sjkoshy cap > PMC_CAP_LAST) { 2898145256Sjkoshy errno = EINVAL; 2899174406Sjkoshy return (NULL); 2900145256Sjkoshy } 2901145256Sjkoshy 2902147191Sjkoshy i = ffs(cap); 2903174406Sjkoshy return (pmc_capability_names[i - 1]); 2904147191Sjkoshy} 2905145256Sjkoshy 2906147191Sjkoshyconst char * 2907147191Sjkoshypmc_name_of_class(enum pmc_class pc) 2908147191Sjkoshy{ 2909147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 2910147191Sjkoshy pc <= PMC_CLASS_LAST) 2911174406Sjkoshy return (pmc_class_names[pc]); 2912145256Sjkoshy 2913147191Sjkoshy errno = EINVAL; 2914174406Sjkoshy return (NULL); 2915147191Sjkoshy} 2916145256Sjkoshy 2917147191Sjkoshyconst char * 2918147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 2919147191Sjkoshy{ 2920183725Sjkoshy size_t n; 2921183725Sjkoshy 2922183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 2923183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 2924183725Sjkoshy return (pmc_cputype_names[n].pm_name); 2925183725Sjkoshy 2926147191Sjkoshy errno = EINVAL; 2927174406Sjkoshy return (NULL); 2928147191Sjkoshy} 2929145256Sjkoshy 2930147191Sjkoshyconst char * 2931147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 2932147191Sjkoshy{ 2933147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 2934147191Sjkoshy pd <= PMC_DISP_LAST) 2935174406Sjkoshy return (pmc_disposition_names[pd]); 2936145256Sjkoshy 2937147191Sjkoshy errno = EINVAL; 2938174406Sjkoshy return (NULL); 2939147191Sjkoshy} 2940145256Sjkoshy 2941147191Sjkoshyconst char * 2942185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 2943147191Sjkoshy{ 2944183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 2945145256Sjkoshy 2946183725Sjkoshy ev = evfence = NULL; 2947185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 2948185363Sjkoshy ev = iaf_event_table; 2949185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 2950185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 2951185363Sjkoshy switch (cpu) { 2952185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2953185363Sjkoshy ev = atom_event_table; 2954185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 2955185363Sjkoshy break; 2956185363Sjkoshy case PMC_CPU_INTEL_CORE: 2957185363Sjkoshy ev = core_event_table; 2958185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 2959185363Sjkoshy break; 2960185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2961185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2962185363Sjkoshy ev = core2_event_table; 2963185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 2964185363Sjkoshy break; 2965187761Sjeff case PMC_CPU_INTEL_COREI7: 2966187761Sjeff ev = corei7_event_table; 2967187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 2968187761Sjeff break; 2969232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2970232366Sdavide ev = sandybridge_event_table; 2971232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 2972232366Sdavide break; 2973206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2974206089Sfabient ev = westmere_event_table; 2975206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 2976206089Sfabient break; 2977185363Sjkoshy default: /* Unknown CPU type. */ 2978185363Sjkoshy break; 2979185363Sjkoshy } 2980206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 2981206089Sfabient ev = ucf_event_table; 2982206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 2983206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 2984206089Sfabient switch (cpu) { 2985206089Sfabient case PMC_CPU_INTEL_COREI7: 2986206089Sfabient ev = corei7uc_event_table; 2987206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 2988206089Sfabient break; 2989232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2990232366Sdavide ev = sandybridgeuc_event_table; 2991232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2992232366Sdavide break; 2993206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2994206089Sfabient ev = westmereuc_event_table; 2995206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 2996206089Sfabient break; 2997206089Sfabient default: /* Unknown CPU type. */ 2998206089Sfabient break; 2999206089Sfabient } 3000206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3001183725Sjkoshy ev = k7_event_table; 3002183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3003183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3004183725Sjkoshy ev = k8_event_table; 3005183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3006183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3007183725Sjkoshy ev = p4_event_table; 3008183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3009183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3010183725Sjkoshy ev = p5_event_table; 3011183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3012183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3013183725Sjkoshy ev = p6_event_table; 3014183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3015200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3016200928Srpaulo ev = xscale_event_table; 3017200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3018204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3019204635Sgnn ev = mips24k_event_table; 3020204635Sgnn evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k 3021204635Sgnn); 3022228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3023228869Sjhibbits ev = ppc7450_event_table; 3024228869Sjhibbits evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450 3025228869Sjhibbits); 3026183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3027183725Sjkoshy ev = tsc_event_table; 3028183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3029183725Sjkoshy } 3030183725Sjkoshy 3031183725Sjkoshy for (; ev != evfence; ev++) 3032183725Sjkoshy if (pe == ev->pm_ev_code) 3033183725Sjkoshy return (ev->pm_ev_name); 3034183725Sjkoshy 3035185363Sjkoshy return (NULL); 3036185363Sjkoshy} 3037185363Sjkoshy 3038185363Sjkoshyconst char * 3039185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3040185363Sjkoshy{ 3041185363Sjkoshy const char *n; 3042185363Sjkoshy 3043185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3044185363Sjkoshy return (n); 3045185363Sjkoshy 3046147191Sjkoshy errno = EINVAL; 3047174406Sjkoshy return (NULL); 3048147191Sjkoshy} 3049145256Sjkoshy 3050147191Sjkoshyconst char * 3051147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3052147191Sjkoshy{ 3053147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3054147191Sjkoshy pm <= PMC_MODE_LAST) 3055174406Sjkoshy return (pmc_mode_names[pm]); 3056145256Sjkoshy 3057147191Sjkoshy errno = EINVAL; 3058174406Sjkoshy return (NULL); 3059147191Sjkoshy} 3060145256Sjkoshy 3061147191Sjkoshyconst char * 3062147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3063147191Sjkoshy{ 3064147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3065147191Sjkoshy ps <= PMC_STATE_LAST) 3066174406Sjkoshy return (pmc_state_names[ps]); 3067145256Sjkoshy 3068147191Sjkoshy errno = EINVAL; 3069174406Sjkoshy return (NULL); 3070145256Sjkoshy} 3071145256Sjkoshy 3072145256Sjkoshyint 3073147191Sjkoshypmc_ncpu(void) 3074145256Sjkoshy{ 3075147191Sjkoshy if (pmc_syscall == -1) { 3076147191Sjkoshy errno = ENXIO; 3077174406Sjkoshy return (-1); 3078147191Sjkoshy } 3079145256Sjkoshy 3080174406Sjkoshy return (cpu_info.pm_ncpu); 3081145256Sjkoshy} 3082145256Sjkoshy 3083145256Sjkoshyint 3084147191Sjkoshypmc_npmc(int cpu) 3085145256Sjkoshy{ 3086147191Sjkoshy if (pmc_syscall == -1) { 3087147191Sjkoshy errno = ENXIO; 3088174406Sjkoshy return (-1); 3089147191Sjkoshy } 3090145256Sjkoshy 3091147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3092147191Sjkoshy errno = EINVAL; 3093174406Sjkoshy return (-1); 3094147191Sjkoshy } 3095145256Sjkoshy 3096174406Sjkoshy return (cpu_info.pm_npmc); 3097145256Sjkoshy} 3098145256Sjkoshy 3099145256Sjkoshyint 3100147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3101145256Sjkoshy{ 3102147191Sjkoshy int nbytes, npmc; 3103147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3104145256Sjkoshy 3105147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3106174406Sjkoshy return (-1); 3107145256Sjkoshy 3108147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3109147191Sjkoshy npmc * sizeof(struct pmc_info); 3110145256Sjkoshy 3111147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3112174406Sjkoshy return (-1); 3113145256Sjkoshy 3114147191Sjkoshy pmci->pm_cpu = cpu; 3115145256Sjkoshy 3116147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3117147191Sjkoshy free(pmci); 3118174406Sjkoshy return (-1); 3119147191Sjkoshy } 3120145256Sjkoshy 3121147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3122147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3123174406Sjkoshy return (0); 3124145256Sjkoshy} 3125145256Sjkoshy 3126145256Sjkoshyint 3127145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3128145256Sjkoshy{ 3129145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3130145256Sjkoshy 3131145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3132145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3133145256Sjkoshy pmc_read_op.pm_value = -1; 3134145256Sjkoshy 3135145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3136174406Sjkoshy return (-1); 3137145256Sjkoshy 3138145256Sjkoshy *value = pmc_read_op.pm_value; 3139174406Sjkoshy return (0); 3140145256Sjkoshy} 3141145256Sjkoshy 3142145256Sjkoshyint 3143147191Sjkoshypmc_release(pmc_id_t pmc) 3144145256Sjkoshy{ 3145147191Sjkoshy struct pmc_op_simple pmc_release_args; 3146145256Sjkoshy 3147147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3148174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3149145256Sjkoshy} 3150145256Sjkoshy 3151145256Sjkoshyint 3152145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3153145256Sjkoshy{ 3154145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3155145256Sjkoshy 3156145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3157145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3158145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3159145256Sjkoshy 3160145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3161174406Sjkoshy return (-1); 3162145256Sjkoshy 3163145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3164174406Sjkoshy return (0); 3165145256Sjkoshy} 3166145256Sjkoshy 3167145256Sjkoshyint 3168145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3169145256Sjkoshy{ 3170145256Sjkoshy struct pmc_op_pmcsetcount sc; 3171145256Sjkoshy 3172145256Sjkoshy sc.pm_pmcid = pmc; 3173145256Sjkoshy sc.pm_count = value; 3174145256Sjkoshy 3175145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3176174406Sjkoshy return (-1); 3177174406Sjkoshy return (0); 3178145256Sjkoshy} 3179145256Sjkoshy 3180145256Sjkoshyint 3181147191Sjkoshypmc_start(pmc_id_t pmc) 3182145256Sjkoshy{ 3183147191Sjkoshy struct pmc_op_simple pmc_start_args; 3184145256Sjkoshy 3185147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3186174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3187145256Sjkoshy} 3188145256Sjkoshy 3189145256Sjkoshyint 3190147191Sjkoshypmc_stop(pmc_id_t pmc) 3191145256Sjkoshy{ 3192147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3193145256Sjkoshy 3194147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3195174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3196145256Sjkoshy} 3197145256Sjkoshy 3198145256Sjkoshyint 3199145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3200145774Sjkoshy{ 3201145774Sjkoshy unsigned int i; 3202145774Sjkoshy enum pmc_class cl; 3203145774Sjkoshy 3204145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3205145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3206145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3207145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3208174406Sjkoshy return (0); 3209145774Sjkoshy } 3210177107Sjkoshy errno = EINVAL; 3211177107Sjkoshy return (-1); 3212145774Sjkoshy} 3213145774Sjkoshy 3214145774Sjkoshyint 3215147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3216145774Sjkoshy{ 3217147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3218145774Sjkoshy 3219147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3220147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3221147191Sjkoshy pmc_write_op.pm_value = value; 3222174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3223145256Sjkoshy} 3224145256Sjkoshy 3225145256Sjkoshyint 3226147191Sjkoshypmc_writelog(uint32_t userdata) 3227145256Sjkoshy{ 3228147191Sjkoshy struct pmc_op_writelog wl; 3229145256Sjkoshy 3230147191Sjkoshy wl.pm_userdata = userdata; 3231174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3232145256Sjkoshy} 3233