libpmc.c revision 241738
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 241738 2012-10-19 17:01:27Z sbruno $"); 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 80204635Sgnn#if defined(__mips__) 81233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 82204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 83204635Sgnn#endif /* __mips__ */ 84233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 85233628Sfabient struct pmc_op_pmcallocate *_pmc_config); 86204635Sgnn 87228869Sjhibbits#if defined(__powerpc__) 88228869Sjhibbitsstatic int ppc7450_allocate_pmc(enum pmc_event _pe, char* ctrspec, 89228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 90228869Sjhibbits#endif /* __powerpc__ */ 91204635Sgnn 92145256Sjkoshy#define PMC_CALL(cmd, params) \ 93145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 94145256Sjkoshy 95145256Sjkoshy/* 96145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 97145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 98145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 99145256Sjkoshy * lookup table. 100145256Sjkoshy */ 101145256Sjkoshystruct pmc_event_alias { 102145256Sjkoshy const char *pm_alias; 103145256Sjkoshy const char *pm_spec; 104145256Sjkoshy}; 105145256Sjkoshy 106145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 107145256Sjkoshy 108145256Sjkoshy/* 109183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 110145256Sjkoshy * to integer codes used by the PMC KLD. 111145256Sjkoshy */ 112145256Sjkoshystruct pmc_event_descr { 113145256Sjkoshy const char *pm_ev_name; 114145256Sjkoshy enum pmc_event pm_ev_code; 115145256Sjkoshy}; 116145256Sjkoshy 117183725Sjkoshy/* 118183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 119183725Sjkoshy * event names to event tables and other PMC class data. 120183725Sjkoshy */ 121183725Sjkoshystruct pmc_class_descr { 122183725Sjkoshy const char *pm_evc_name; 123183725Sjkoshy size_t pm_evc_name_size; 124183725Sjkoshy enum pmc_class pm_evc_class; 125183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 126183725Sjkoshy size_t pm_evc_event_table_size; 127183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 128183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 129183725Sjkoshy}; 130183725Sjkoshy 131183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 132183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 133183725Sjkoshy 134183725Sjkoshy#undef __PMC_EV 135183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 136183725Sjkoshy 137183725Sjkoshy/* 138185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 139183725Sjkoshy * 140185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 141183725Sjkoshy */ 142185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 143183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 144183725Sjkoshy { \ 145183725Sjkoshy __PMC_EV_##C() \ 146185363Sjkoshy } 147185363Sjkoshy 148185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 149185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 150185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 151185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 152185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 153185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 154200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 155204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 156233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON); 157206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 158228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 159185363Sjkoshy 160233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; 161233628Sfabient 162185363Sjkoshy#undef __PMC_EV_ALIAS 163185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 164185363Sjkoshy 165185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 166185363Sjkoshy{ 167185363Sjkoshy __PMC_EV_ALIAS_ATOM() 168185363Sjkoshy}; 169185363Sjkoshy 170185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 171185363Sjkoshy{ 172185363Sjkoshy __PMC_EV_ALIAS_CORE() 173185363Sjkoshy}; 174185363Sjkoshy 175185363Sjkoshy 176185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 177185363Sjkoshy{ 178185363Sjkoshy __PMC_EV_ALIAS_CORE2() 179185363Sjkoshy}; 180185363Sjkoshy 181187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 182187761Sjeff{ 183187761Sjeff __PMC_EV_ALIAS_COREI7() 184187761Sjeff}; 185187761Sjeff 186240164Sfabientstatic const struct pmc_event_descr ivybridge_event_table[] = 187240164Sfabient{ 188240164Sfabient __PMC_EV_ALIAS_IVYBRIDGE() 189240164Sfabient}; 190240164Sfabient 191232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 192232366Sdavide{ 193232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 194232366Sdavide}; 195232366Sdavide 196241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] = 197241738Ssbruno{ 198241738Ssbruno __PMC_EV_ALIAS_SANDYBRIDGE_XEON() 199241738Ssbruno}; 200241738Ssbruno 201206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 202206089Sfabient{ 203206089Sfabient __PMC_EV_ALIAS_WESTMERE() 204206089Sfabient}; 205206089Sfabient 206206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 207206089Sfabient{ 208206089Sfabient __PMC_EV_ALIAS_COREI7UC() 209206089Sfabient}; 210206089Sfabient 211232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 212232366Sdavide{ 213232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 214232366Sdavide}; 215232366Sdavide 216206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 217206089Sfabient{ 218206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 219206089Sfabient}; 220206089Sfabient 221185363Sjkoshy/* 222185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 223185363Sjkoshy * 224185363Sjkoshy * Map a CPU to the PMC classes it supports. 225185363Sjkoshy */ 226185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 227183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 228183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 229183725Sjkoshy } 230183725Sjkoshy 231233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 232233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 233233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 234233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 235240164SfabientPMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 236233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 237241738SsbrunoPMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 238233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 239233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); 240233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); 241233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); 242233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); 243233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); 244233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); 245233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 246233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 247233628SfabientPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450); 248233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 249183725Sjkoshy 250183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 251145256Sjkoshy{ 252183725Sjkoshy __PMC_EV_TSC() 253145256Sjkoshy}; 254145256Sjkoshy 255183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 256185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 257185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 258185363Sjkoshy { \ 259185363Sjkoshy .pm_evc_name = #CLASS "-", \ 260185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 261185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 262185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 263183725Sjkoshy .pm_evc_event_table_size = \ 264185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 265185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 266183725Sjkoshy } 267183725Sjkoshy 268185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 269185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 270185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 271185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 272185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 273187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 274240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); 275232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 276241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); 277206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 278206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 279206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 280232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 281206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 282185363Sjkoshy#endif 283183725Sjkoshy#if defined(__i386__) 284185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 285183725Sjkoshy#endif 286183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 287185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 288185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 289183725Sjkoshy#endif 290183725Sjkoshy#if defined(__i386__) 291185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 292185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 293183725Sjkoshy#endif 294183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 295185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 296183725Sjkoshy#endif 297200928Srpaulo#if defined(__XSCALE__) 298200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 299200928Srpaulo#endif 300204635Sgnn#if defined(__mips__) 301233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 302233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 303204635Sgnn#endif /* __mips__ */ 304228869Sjhibbits#if defined(__powerpc__) 305228869SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450); 306228869Sjhibbits#endif 307228869Sjhibbits 308233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 309233628Sfabient{ 310233628Sfabient .pm_evc_name = "SOFT-", 311233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 312233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 313233628Sfabient .pm_evc_event_table = NULL, 314233628Sfabient .pm_evc_event_table_size = 0, 315233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 316233628Sfabient}; 317233628Sfabient 318183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 319183725Sjkoshy 320185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 321185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 322185363Sjkoshy 323183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 324183725Sjkoshystatic size_t pmc_mdep_class_list_size; 325183725Sjkoshy 326145256Sjkoshy/* 327145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 328145256Sjkoshy * strings. 329145256Sjkoshy */ 330145256Sjkoshy 331145256Sjkoshystatic const char * pmc_capability_names[] = { 332145256Sjkoshy#undef __PMC_CAP 333145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 334145256Sjkoshy __PMC_CAPS() 335145256Sjkoshy}; 336145256Sjkoshy 337145256Sjkoshystatic const char * pmc_class_names[] = { 338145256Sjkoshy#undef __PMC_CLASS 339145256Sjkoshy#define __PMC_CLASS(C) #C , 340145256Sjkoshy __PMC_CLASSES() 341145256Sjkoshy}; 342145256Sjkoshy 343183725Sjkoshystruct pmc_cputype_map { 344228557Sdim enum pmc_cputype pm_cputype; 345183725Sjkoshy const char *pm_name; 346183725Sjkoshy}; 347183725Sjkoshy 348183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 349145256Sjkoshy#undef __PMC_CPU 350183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 351145256Sjkoshy __PMC_CPUS() 352145256Sjkoshy}; 353145256Sjkoshy 354145256Sjkoshystatic const char * pmc_disposition_names[] = { 355145256Sjkoshy#undef __PMC_DISP 356145256Sjkoshy#define __PMC_DISP(D) #D , 357145256Sjkoshy __PMC_DISPOSITIONS() 358145256Sjkoshy}; 359145256Sjkoshy 360145256Sjkoshystatic const char * pmc_mode_names[] = { 361145256Sjkoshy#undef __PMC_MODE 362145256Sjkoshy#define __PMC_MODE(M,N) #M , 363145256Sjkoshy __PMC_MODES() 364145256Sjkoshy}; 365145256Sjkoshy 366145256Sjkoshystatic const char * pmc_state_names[] = { 367145256Sjkoshy#undef __PMC_STATE 368145256Sjkoshy#define __PMC_STATE(S) #S , 369145256Sjkoshy __PMC_STATES() 370145256Sjkoshy}; 371145256Sjkoshy 372233628Sfabient/* 373233628Sfabient * Filled in by pmc_init(). 374233628Sfabient */ 375233628Sfabientstatic int pmc_syscall = -1; 376233628Sfabientstatic struct pmc_cpuinfo cpu_info; 377233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 378145256Sjkoshy 379145256Sjkoshy/* Event masks for events */ 380145256Sjkoshystruct pmc_masks { 381145256Sjkoshy const char *pm_name; 382240164Sfabient const uint64_t pm_value; 383145256Sjkoshy}; 384145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 385206089Sfabient#define NULLMASK { .pm_name = NULL } 386145256Sjkoshy 387147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 388145256Sjkoshystatic int 389240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) 390145256Sjkoshy{ 391145256Sjkoshy const struct pmc_masks *pm; 392145256Sjkoshy char *q, *r; 393145256Sjkoshy int c; 394145256Sjkoshy 395145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 396174406Sjkoshy return (-1); 397183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 398145256Sjkoshy if (*++q == '\0') /* no more data */ 399174406Sjkoshy return (-1); 400145256Sjkoshy c = 0; /* count of mask keywords seen */ 401145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 402183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 403183725Sjkoshy pm++) 404145256Sjkoshy ; 405145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 406174406Sjkoshy return (-1); 407145256Sjkoshy *evmask |= pm->pm_value; 408145256Sjkoshy c++; 409145256Sjkoshy } 410174406Sjkoshy return (c); 411145256Sjkoshy} 412145340Smarcel#endif 413145256Sjkoshy 414145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 415145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 416145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 417145256Sjkoshy 418145340Smarcel#if defined(__i386__) 419145256Sjkoshy 420145256Sjkoshy/* 421145256Sjkoshy * AMD K7 (Athlon) CPUs. 422145256Sjkoshy */ 423145256Sjkoshy 424145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 425145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 426145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 427145351Sjkoshy EV_ALIAS("cycles", "tsc"), 428183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 429145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 430145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 431145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 432145351Sjkoshy EV_ALIAS(NULL, NULL) 433145256Sjkoshy}; 434145256Sjkoshy 435145256Sjkoshy#define K7_KW_COUNT "count" 436145256Sjkoshy#define K7_KW_EDGE "edge" 437145256Sjkoshy#define K7_KW_INV "inv" 438145256Sjkoshy#define K7_KW_OS "os" 439145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 440145256Sjkoshy#define K7_KW_USR "usr" 441145256Sjkoshy 442145256Sjkoshystatic int 443145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 444145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 445145256Sjkoshy{ 446183107Sjkoshy char *e, *p, *q; 447183107Sjkoshy int c, has_unitmask; 448145256Sjkoshy uint32_t count, unitmask; 449145256Sjkoshy 450147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 451183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 452145256Sjkoshy 453145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 454145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 455145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 456145256Sjkoshy has_unitmask = 1; 457147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 458145256Sjkoshy } else 459145256Sjkoshy unitmask = has_unitmask = 0; 460145256Sjkoshy 461145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 462145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 463145256Sjkoshy q = strchr(p, '='); 464145256Sjkoshy if (*++q == '\0') /* skip '=' */ 465174406Sjkoshy return (-1); 466145256Sjkoshy 467145256Sjkoshy count = strtol(q, &e, 0); 468145256Sjkoshy if (e == q || *e != '\0') 469174406Sjkoshy return (-1); 470145256Sjkoshy 471145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 472147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 473147191Sjkoshy AMD_PMC_TO_COUNTER(count); 474145256Sjkoshy 475145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 476145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 477145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 478145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 479145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 480145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 481145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 482145256Sjkoshy if (has_unitmask == 0) 483174406Sjkoshy return (-1); 484145256Sjkoshy unitmask = 0; 485145256Sjkoshy q = strchr(p, '='); 486145256Sjkoshy if (*++q == '\0') /* skip '=' */ 487174406Sjkoshy return (-1); 488145256Sjkoshy 489145256Sjkoshy while ((c = tolower(*q++)) != 0) 490145256Sjkoshy if (c == 'm') 491147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 492145256Sjkoshy else if (c == 'o') 493147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 494145256Sjkoshy else if (c == 'e') 495147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 496145256Sjkoshy else if (c == 's') 497147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 498145256Sjkoshy else if (c == 'i') 499147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 500145256Sjkoshy else if (c == '+') 501145256Sjkoshy continue; 502145256Sjkoshy else 503174406Sjkoshy return (-1); 504145256Sjkoshy 505145256Sjkoshy if (unitmask == 0) 506174406Sjkoshy return (-1); 507145256Sjkoshy 508145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 509145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 510145256Sjkoshy } else 511174406Sjkoshy return (-1); 512145256Sjkoshy } 513145256Sjkoshy 514145256Sjkoshy if (has_unitmask) { 515145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 516147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 517147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 518145256Sjkoshy } 519145256Sjkoshy 520174406Sjkoshy return (0); 521145256Sjkoshy 522145256Sjkoshy} 523145256Sjkoshy 524147191Sjkoshy#endif 525147191Sjkoshy 526147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 527147191Sjkoshy 528145256Sjkoshy/* 529185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 530185363Sjkoshy */ 531185363Sjkoshy 532185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 533185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 534185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 535185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 536185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 537185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 538185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 539185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 540185363Sjkoshy EV_ALIAS(NULL, NULL) 541185363Sjkoshy}; 542185363Sjkoshy 543185363Sjkoshy/* 544185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 545185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 546198433Sjkoshy * 547198433Sjkoshy * We map aliases to events on the fixed-function counters if these 548198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 549198433Sjkoshy * counters. 550185363Sjkoshy */ 551185363Sjkoshy 552185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 553185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 554185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 555185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 556185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 557185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 558185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 559185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 560185363Sjkoshy EV_ALIAS(NULL, NULL) 561185363Sjkoshy}; 562185363Sjkoshy 563198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 564198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 565198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 566198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 567198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 568198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 569198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 570198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 571198433Sjkoshy EV_ALIAS(NULL, NULL) 572198433Sjkoshy}; 573198433Sjkoshy 574198433Sjkoshy#define atom_aliases core2_aliases 575198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 576198433Sjkoshy#define corei7_aliases core2_aliases 577198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 578240164Sfabient#define ivybridge_aliases core2_aliases 579240164Sfabient#define ivybridge_aliases_without_iaf core2_aliases_without_iaf 580232366Sdavide#define sandybridge_aliases core2_aliases 581232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 582241738Ssbruno#define sandybridge_xeon_aliases core2_aliases 583241738Ssbruno#define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 584206089Sfabient#define westmere_aliases core2_aliases 585206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 586198433Sjkoshy 587185363Sjkoshy#define IAF_KW_OS "os" 588185363Sjkoshy#define IAF_KW_USR "usr" 589185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 590185363Sjkoshy 591185363Sjkoshy/* 592185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 593185363Sjkoshy */ 594185363Sjkoshystatic int 595185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 596185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 597185363Sjkoshy{ 598185363Sjkoshy char *p; 599185363Sjkoshy 600185363Sjkoshy (void) pe; 601185363Sjkoshy 602185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 603185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 604185363Sjkoshy 605185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 606185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 607185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 608185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 609185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 610185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 611185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 612185363Sjkoshy else 613185363Sjkoshy return (-1); 614185363Sjkoshy } 615185363Sjkoshy 616185363Sjkoshy return (0); 617185363Sjkoshy} 618185363Sjkoshy 619185363Sjkoshy/* 620185363Sjkoshy * Core/Core2 support. 621185363Sjkoshy */ 622185363Sjkoshy 623185363Sjkoshy#define IAP_KW_AGENT "agent" 624185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 625185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 626185363Sjkoshy#define IAP_KW_CMASK "cmask" 627185363Sjkoshy#define IAP_KW_CORE "core" 628185363Sjkoshy#define IAP_KW_EDGE "edge" 629185363Sjkoshy#define IAP_KW_INV "inv" 630185363Sjkoshy#define IAP_KW_OS "os" 631185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 632185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 633185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 634185363Sjkoshy#define IAP_KW_TRANSITION "trans" 635185363Sjkoshy#define IAP_KW_USR "usr" 636206089Sfabient#define IAP_KW_RSP "rsp" 637185363Sjkoshy 638185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 639185363Sjkoshy PMCMASK(all, (0x3 << 14)), 640185363Sjkoshy PMCMASK(this, (0x1 << 14)), 641185363Sjkoshy NULLMASK 642185363Sjkoshy}; 643185363Sjkoshy 644185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 645185363Sjkoshy PMCMASK(this, 0), 646185363Sjkoshy PMCMASK(any, (0x1 << 13)), 647185363Sjkoshy NULLMASK 648185363Sjkoshy}; 649185363Sjkoshy 650185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 651185363Sjkoshy PMCMASK(both, (0x3 << 12)), 652185363Sjkoshy PMCMASK(only, (0x1 << 12)), 653185363Sjkoshy PMCMASK(exclude, 0), 654185363Sjkoshy NULLMASK 655185363Sjkoshy}; 656185363Sjkoshy 657185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 658185363Sjkoshy PMCMASK(i, (1 << 8)), 659185363Sjkoshy PMCMASK(s, (1 << 9)), 660185363Sjkoshy PMCMASK(e, (1 << 10)), 661185363Sjkoshy PMCMASK(m, (1 << 11)), 662185363Sjkoshy NULLMASK 663185363Sjkoshy}; 664185363Sjkoshy 665185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 666185363Sjkoshy PMCMASK(clean, (1 << 8)), 667185363Sjkoshy PMCMASK(hit, (1 << 9)), 668185363Sjkoshy PMCMASK(hitm, (1 << 11)), 669185363Sjkoshy NULLMASK 670185363Sjkoshy}; 671185363Sjkoshy 672185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 673185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 674185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 675185363Sjkoshy NULLMASK 676185363Sjkoshy}; 677185363Sjkoshy 678185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 679185363Sjkoshy PMCMASK(any, 0x00), 680185363Sjkoshy PMCMASK(frequency, 0x10), 681185363Sjkoshy NULLMASK 682185363Sjkoshy}; 683185363Sjkoshy 684240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = { 685206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 686206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 687206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 688206089Sfabient PMCMASK(WB, (1 << 3)), 689206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 690206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 691206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 692206089Sfabient PMCMASK(OTHER, (1 << 7)), 693206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 694206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 695206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 696206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 697206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 698206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 699206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 700206089Sfabient NULLMASK 701206089Sfabient}; 702206089Sfabient 703241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { 704240164Sfabient PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 705240164Sfabient PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 706240164Sfabient PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 707240164Sfabient PMCMASK(REQ_WB, (1ULL << 3)), 708240164Sfabient PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 709240164Sfabient PMCMASK(REQ_PF_RFO, (1ULL << 5)), 710240164Sfabient PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 711240164Sfabient PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), 712240164Sfabient PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), 713240164Sfabient PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), 714240164Sfabient PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), 715240164Sfabient PMCMASK(REQ_STRM_ST, (1ULL << 11)), 716240164Sfabient PMCMASK(REQ_OTHER, (1ULL << 15)), 717240164Sfabient PMCMASK(RES_ANY, (1ULL << 16)), 718240164Sfabient PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 719240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 720240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 721240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 722240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 723240164Sfabient PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 724240164Sfabient PMCMASK(RES_SNOOP_SNPI_NONE, (1ULL << 31)), 725240164Sfabient PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 726240164Sfabient PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 727240164Sfabient PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 728240164Sfabient PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 729240164Sfabient PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 730240164Sfabient PMCMASK(RES_NON_DRAM, (1ULL << 37)), 731240164Sfabient NULLMASK 732240164Sfabient}; 733240164Sfabient 734185363Sjkoshystatic int 735185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 736185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 737185363Sjkoshy{ 738185363Sjkoshy char *e, *p, *q; 739240164Sfabient uint64_t cachestate, evmask, rsp; 740185363Sjkoshy int count, n; 741185363Sjkoshy 742185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 743185363Sjkoshy PMC_CAP_QUALIFIER); 744185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 745185363Sjkoshy 746206089Sfabient cachestate = evmask = rsp = 0; 747185363Sjkoshy 748185363Sjkoshy /* Parse additional modifiers if present */ 749185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 750185363Sjkoshy 751185363Sjkoshy n = 0; 752185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 753185363Sjkoshy q = strchr(p, '='); 754185363Sjkoshy if (*++q == '\0') /* skip '=' */ 755185363Sjkoshy return (-1); 756185363Sjkoshy count = strtol(q, &e, 0); 757185363Sjkoshy if (e == q || *e != '\0') 758185363Sjkoshy return (-1); 759185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 760185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 761185363Sjkoshy IAP_CMASK(count); 762185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 763185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 764185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 765185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 766185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 767185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 768185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 769185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 770185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 771185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 772193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 773185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 774185363Sjkoshy if (n != 1) 775185363Sjkoshy return (-1); 776193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 777185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 778185363Sjkoshy if (n != 1) 779185363Sjkoshy return (-1); 780193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 781185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 782185363Sjkoshy if (n != 1) 783185363Sjkoshy return (-1); 784193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 785185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 786185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 787193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 788185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 789185363Sjkoshy if (n != 1) 790185363Sjkoshy return (-1); 791185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 792185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 793206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 794193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 795185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 796185363Sjkoshy &evmask); 797193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 798185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 799185363Sjkoshy &evmask); 800185363Sjkoshy } else 801185363Sjkoshy return (-1); 802206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 803206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) { 804206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 805240164Sfabient n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); 806206089Sfabient } else 807206089Sfabient return (-1); 808240164Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || 809241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || 810241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE) { 811240164Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 812241738Ssbruno n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); 813240164Sfabient } else 814240164Sfabient return (-1); 815185363Sjkoshy } else 816185363Sjkoshy return (-1); 817185363Sjkoshy 818185363Sjkoshy if (n < 0) /* Parsing failed. */ 819185363Sjkoshy return (-1); 820185363Sjkoshy } 821185363Sjkoshy 822185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 823185363Sjkoshy 824185363Sjkoshy /* 825185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 826185363Sjkoshy * specified by the user, use a sensible default. 827185363Sjkoshy */ 828185363Sjkoshy switch (pe) { 829185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 830185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 831185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 832185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 833185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 834185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 835185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 836185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 837185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 838185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 839185363Sjkoshy if (cachestate == 0) 840185363Sjkoshy cachestate = (0xF << 8); 841207482Srstone break; 842207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 843207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 844207482Srstone * Atom processor 845207482Srstone */ 846207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 847207482Srstone cachestate = (0xF << 8); 848207482Srstone break; 849185363Sjkoshy default: 850185363Sjkoshy break; 851185363Sjkoshy } 852185363Sjkoshy 853185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 854206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 855185363Sjkoshy 856185363Sjkoshy return (0); 857185363Sjkoshy} 858185363Sjkoshy 859185363Sjkoshy/* 860206089Sfabient * Intel Uncore. 861206089Sfabient */ 862206089Sfabient 863206089Sfabientstatic int 864206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 865206089Sfabient struct pmc_op_pmcallocate *pmc_config) 866206089Sfabient{ 867206089Sfabient (void) pe; 868206089Sfabient (void) ctrspec; 869206089Sfabient 870206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 871206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 872206089Sfabient 873206089Sfabient return (0); 874206089Sfabient} 875206089Sfabient 876206089Sfabient#define UCP_KW_CMASK "cmask" 877206089Sfabient#define UCP_KW_EDGE "edge" 878206089Sfabient#define UCP_KW_INV "inv" 879206089Sfabient 880206089Sfabientstatic int 881206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 882206089Sfabient struct pmc_op_pmcallocate *pmc_config) 883206089Sfabient{ 884206089Sfabient char *e, *p, *q; 885206089Sfabient int count, n; 886206089Sfabient 887206089Sfabient (void) pe; 888206089Sfabient 889206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 890206089Sfabient PMC_CAP_QUALIFIER); 891206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 892206089Sfabient 893206089Sfabient /* Parse additional modifiers if present */ 894206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 895206089Sfabient 896206089Sfabient n = 0; 897206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 898206089Sfabient q = strchr(p, '='); 899206089Sfabient if (*++q == '\0') /* skip '=' */ 900206089Sfabient return (-1); 901206089Sfabient count = strtol(q, &e, 0); 902206089Sfabient if (e == q || *e != '\0') 903206089Sfabient return (-1); 904206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 905206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 906206089Sfabient UCP_CMASK(count); 907206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 908206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 909206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 910206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 911206089Sfabient } else 912206089Sfabient return (-1); 913206089Sfabient 914206089Sfabient if (n < 0) /* Parsing failed. */ 915206089Sfabient return (-1); 916206089Sfabient } 917206089Sfabient 918206089Sfabient return (0); 919206089Sfabient} 920206089Sfabient 921206089Sfabient/* 922147191Sjkoshy * AMD K8 PMCs. 923147191Sjkoshy * 924147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 925147191Sjkoshy * events. 926147191Sjkoshy */ 927147191Sjkoshy 928147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 929147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 930147191Sjkoshy EV_ALIAS("branch-mispredicts", 931147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 932147191Sjkoshy EV_ALIAS("cycles", "tsc"), 933147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 934147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 935183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 936147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 937155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 938147191Sjkoshy EV_ALIAS(NULL, NULL) 939147191Sjkoshy}; 940147191Sjkoshy 941147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 942147191Sjkoshy 943147191Sjkoshy/* 944147191Sjkoshy * Parsing tables 945147191Sjkoshy */ 946147191Sjkoshy 947147191Sjkoshy/* fp dispatched fpu ops */ 948147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 949147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 950147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 951147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 952147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 953147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 954147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 955147191Sjkoshy NULLMASK 956147191Sjkoshy}; 957147191Sjkoshy 958147191Sjkoshy/* ls segment register loads */ 959147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 960147191Sjkoshy __K8MASK(es, 0), 961147191Sjkoshy __K8MASK(cs, 1), 962147191Sjkoshy __K8MASK(ss, 2), 963147191Sjkoshy __K8MASK(ds, 3), 964147191Sjkoshy __K8MASK(fs, 4), 965147191Sjkoshy __K8MASK(gs, 5), 966147191Sjkoshy __K8MASK(hs, 6), 967147191Sjkoshy NULLMASK 968147191Sjkoshy}; 969147191Sjkoshy 970147191Sjkoshy/* ls locked operation */ 971147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 972147191Sjkoshy __K8MASK(locked-instructions, 0), 973147191Sjkoshy __K8MASK(cycles-in-request, 1), 974147191Sjkoshy __K8MASK(cycles-to-complete, 2), 975147191Sjkoshy NULLMASK 976147191Sjkoshy}; 977147191Sjkoshy 978147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 979147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 980147191Sjkoshy __K8MASK(invalid, 0), 981147191Sjkoshy __K8MASK(shared, 1), 982147191Sjkoshy __K8MASK(exclusive, 2), 983147191Sjkoshy __K8MASK(owner, 3), 984147191Sjkoshy __K8MASK(modified, 4), 985147191Sjkoshy NULLMASK 986147191Sjkoshy}; 987147191Sjkoshy 988147191Sjkoshy/* dc one bit ecc error */ 989147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 990147191Sjkoshy __K8MASK(scrubber, 0), 991147191Sjkoshy __K8MASK(piggyback, 1), 992147191Sjkoshy NULLMASK 993147191Sjkoshy}; 994147191Sjkoshy 995147191Sjkoshy/* dc dispatched prefetch instructions */ 996147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 997147191Sjkoshy __K8MASK(load, 0), 998147191Sjkoshy __K8MASK(store, 1), 999147191Sjkoshy __K8MASK(nta, 2), 1000147191Sjkoshy NULLMASK 1001147191Sjkoshy}; 1002147191Sjkoshy 1003147191Sjkoshy/* dc dcache accesses by locks */ 1004147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1005147191Sjkoshy __K8MASK(accesses, 0), 1006147191Sjkoshy __K8MASK(misses, 1), 1007147191Sjkoshy NULLMASK 1008147191Sjkoshy}; 1009147191Sjkoshy 1010147191Sjkoshy/* bu internal l2 request */ 1011147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1012147191Sjkoshy __K8MASK(ic-fill, 0), 1013147191Sjkoshy __K8MASK(dc-fill, 1), 1014147191Sjkoshy __K8MASK(tlb-reload, 2), 1015147191Sjkoshy __K8MASK(tag-snoop, 3), 1016147191Sjkoshy __K8MASK(cancelled, 4), 1017147191Sjkoshy NULLMASK 1018147191Sjkoshy}; 1019147191Sjkoshy 1020147191Sjkoshy/* bu fill request l2 miss */ 1021147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1022147191Sjkoshy __K8MASK(ic-fill, 0), 1023147191Sjkoshy __K8MASK(dc-fill, 1), 1024147191Sjkoshy __K8MASK(tlb-reload, 2), 1025147191Sjkoshy NULLMASK 1026147191Sjkoshy}; 1027147191Sjkoshy 1028147191Sjkoshy/* bu fill into l2 */ 1029147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1030147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 1031147191Sjkoshy __K8MASK(victim-from-l2, 1), 1032147191Sjkoshy NULLMASK 1033147191Sjkoshy}; 1034147191Sjkoshy 1035147191Sjkoshy/* fr retired fpu instructions */ 1036147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1037147191Sjkoshy __K8MASK(x87, 0), 1038147191Sjkoshy __K8MASK(mmx-3dnow, 1), 1039147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 1040147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1041147191Sjkoshy NULLMASK 1042147191Sjkoshy}; 1043147191Sjkoshy 1044147191Sjkoshy/* fr retired fastpath double op instructions */ 1045147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1046147191Sjkoshy __K8MASK(low-op-pos-0, 0), 1047147191Sjkoshy __K8MASK(low-op-pos-1, 1), 1048147191Sjkoshy __K8MASK(low-op-pos-2, 2), 1049147191Sjkoshy NULLMASK 1050147191Sjkoshy}; 1051147191Sjkoshy 1052147191Sjkoshy/* fr fpu exceptions */ 1053147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1054147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1055147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1056147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1057147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1058147191Sjkoshy NULLMASK 1059147191Sjkoshy}; 1060147191Sjkoshy 1061147191Sjkoshy/* nb memory controller page access event */ 1062147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1063147191Sjkoshy __K8MASK(page-hit, 0), 1064147191Sjkoshy __K8MASK(page-miss, 1), 1065147191Sjkoshy __K8MASK(page-conflict, 2), 1066147191Sjkoshy NULLMASK 1067147191Sjkoshy}; 1068147191Sjkoshy 1069147191Sjkoshy/* nb memory controller turnaround */ 1070147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1071147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1072147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1073147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1074147191Sjkoshy NULLMASK 1075147191Sjkoshy}; 1076147191Sjkoshy 1077147191Sjkoshy/* nb memory controller bypass saturation */ 1078147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1079147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1080147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1081147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1082147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1083147191Sjkoshy NULLMASK 1084147191Sjkoshy}; 1085147191Sjkoshy 1086147191Sjkoshy/* nb sized commands */ 1087147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1088147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1089147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1090147191Sjkoshy __K8MASK(postwrszbyte, 2), 1091147191Sjkoshy __K8MASK(postwrszdword, 3), 1092147191Sjkoshy __K8MASK(rdszbyte, 4), 1093147191Sjkoshy __K8MASK(rdszdword, 5), 1094147191Sjkoshy __K8MASK(rdmodwr, 6), 1095147191Sjkoshy NULLMASK 1096147191Sjkoshy}; 1097147191Sjkoshy 1098147191Sjkoshy/* nb probe result */ 1099147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1100147191Sjkoshy __K8MASK(probe-miss, 0), 1101147191Sjkoshy __K8MASK(probe-hit, 1), 1102147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1103147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1104147191Sjkoshy NULLMASK 1105147191Sjkoshy}; 1106147191Sjkoshy 1107147191Sjkoshy/* nb hypertransport bus bandwidth */ 1108147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1109147191Sjkoshy __K8MASK(command, 0), 1110183107Sjkoshy __K8MASK(data, 1), 1111147191Sjkoshy __K8MASK(buffer-release, 2), 1112147191Sjkoshy __K8MASK(nop, 3), 1113147191Sjkoshy NULLMASK 1114147191Sjkoshy}; 1115147191Sjkoshy 1116147191Sjkoshy#undef __K8MASK 1117147191Sjkoshy 1118147191Sjkoshy#define K8_KW_COUNT "count" 1119147191Sjkoshy#define K8_KW_EDGE "edge" 1120147191Sjkoshy#define K8_KW_INV "inv" 1121147191Sjkoshy#define K8_KW_MASK "mask" 1122147191Sjkoshy#define K8_KW_OS "os" 1123147191Sjkoshy#define K8_KW_USR "usr" 1124147191Sjkoshy 1125147191Sjkoshystatic int 1126147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1127147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1128147191Sjkoshy{ 1129183107Sjkoshy char *e, *p, *q; 1130183107Sjkoshy int n; 1131240164Sfabient uint32_t count; 1132240164Sfabient uint64_t evmask; 1133147191Sjkoshy const struct pmc_masks *pm, *pmask; 1134147191Sjkoshy 1135183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1136147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1137147191Sjkoshy 1138147191Sjkoshy pmask = NULL; 1139147191Sjkoshy evmask = 0; 1140147191Sjkoshy 1141147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1142147191Sjkoshy 1143147191Sjkoshy /* setup parsing tables */ 1144147191Sjkoshy switch (pe) { 1145147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1146147191Sjkoshy __K8SETMASK(fdfo); 1147147191Sjkoshy break; 1148147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1149147191Sjkoshy __K8SETMASK(lsrl); 1150147191Sjkoshy break; 1151147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1152147191Sjkoshy __K8SETMASK(llo); 1153147191Sjkoshy break; 1154147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1155147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1156147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1157147191Sjkoshy __K8SETMASK(dc); 1158147191Sjkoshy break; 1159147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1160147191Sjkoshy __K8SETMASK(dobee); 1161147191Sjkoshy break; 1162147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1163147191Sjkoshy __K8SETMASK(ddpi); 1164147191Sjkoshy break; 1165147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1166147191Sjkoshy __K8SETMASK(dabl); 1167147191Sjkoshy break; 1168147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1169147191Sjkoshy __K8SETMASK(bilr); 1170147191Sjkoshy break; 1171147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1172147191Sjkoshy __K8SETMASK(bfrlm); 1173147191Sjkoshy break; 1174147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1175147191Sjkoshy __K8SETMASK(bfil); 1176147191Sjkoshy break; 1177147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1178147191Sjkoshy __K8SETMASK(frfi); 1179147191Sjkoshy break; 1180147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1181147191Sjkoshy __K8SETMASK(frfdoi); 1182147191Sjkoshy break; 1183147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1184147191Sjkoshy __K8SETMASK(ffe); 1185147191Sjkoshy break; 1186147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1187147191Sjkoshy __K8SETMASK(nmcpae); 1188147191Sjkoshy break; 1189147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1190147191Sjkoshy __K8SETMASK(nmct); 1191147191Sjkoshy break; 1192147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1193147191Sjkoshy __K8SETMASK(nmcbs); 1194147191Sjkoshy break; 1195147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1196147191Sjkoshy __K8SETMASK(nsc); 1197147191Sjkoshy break; 1198147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1199147191Sjkoshy __K8SETMASK(npr); 1200147191Sjkoshy break; 1201147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1202147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1203147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1204147191Sjkoshy __K8SETMASK(nhbb); 1205147191Sjkoshy break; 1206147191Sjkoshy 1207147191Sjkoshy default: 1208147191Sjkoshy break; /* no options defined */ 1209147191Sjkoshy } 1210147191Sjkoshy 1211147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1212147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1213147191Sjkoshy q = strchr(p, '='); 1214147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1215174406Sjkoshy return (-1); 1216147191Sjkoshy 1217147191Sjkoshy count = strtol(q, &e, 0); 1218147191Sjkoshy if (e == q || *e != '\0') 1219174406Sjkoshy return (-1); 1220147191Sjkoshy 1221147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1222147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1223147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1224147191Sjkoshy 1225147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1226147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1227147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1228147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1229147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1230147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1231174406Sjkoshy return (-1); 1232147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1233147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1234147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1235147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1236147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1237147191Sjkoshy } else 1238174406Sjkoshy return (-1); 1239147191Sjkoshy } 1240147191Sjkoshy 1241147191Sjkoshy /* other post processing */ 1242147191Sjkoshy switch (pe) { 1243147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1244147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1245147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1246147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1247147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1248147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1249147191Sjkoshy /* XXX only available in rev B and later */ 1250147191Sjkoshy break; 1251147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1252147191Sjkoshy /* XXX only available in rev C and later */ 1253147191Sjkoshy break; 1254147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1255147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1256147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1257174406Sjkoshy return (-1); 1258147191Sjkoshy if (evmask == 0) { 1259147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1260147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1261147191Sjkoshy } 1262147191Sjkoshy break; 1263147191Sjkoshy default: 1264147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1265147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1266147191Sjkoshy evmask |= pm->pm_value; 1267147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1268147191Sjkoshy } 1269147191Sjkoshy } 1270147191Sjkoshy 1271147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1272147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1273147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1274147191Sjkoshy 1275174406Sjkoshy return (0); 1276147191Sjkoshy} 1277147191Sjkoshy 1278147191Sjkoshy#endif 1279147191Sjkoshy 1280147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1281147191Sjkoshy 1282147191Sjkoshy/* 1283145256Sjkoshy * Intel P4 PMCs 1284145256Sjkoshy */ 1285145256Sjkoshy 1286145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1287145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1288145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1289145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1290145351Sjkoshy EV_ALIAS("instructions", 1291145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1292155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1293145256Sjkoshy EV_ALIAS(NULL, NULL) 1294145256Sjkoshy}; 1295145256Sjkoshy 1296145256Sjkoshy#define P4_KW_ACTIVE "active" 1297145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1298145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1299145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1300145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1301145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1302145256Sjkoshy#define P4_KW_CASCADE "cascade" 1303145256Sjkoshy#define P4_KW_EDGE "edge" 1304145256Sjkoshy#define P4_KW_INV "complement" 1305145256Sjkoshy#define P4_KW_OS "os" 1306145256Sjkoshy#define P4_KW_MASK "mask" 1307145256Sjkoshy#define P4_KW_PRECISE "precise" 1308145256Sjkoshy#define P4_KW_TAG "tag" 1309145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1310145256Sjkoshy#define P4_KW_USR "usr" 1311145256Sjkoshy 1312145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1313145256Sjkoshy 1314145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1315145256Sjkoshy __P4MASK(dd, 0), 1316145256Sjkoshy __P4MASK(db, 1), 1317145256Sjkoshy __P4MASK(di, 2), 1318145256Sjkoshy __P4MASK(bd, 3), 1319145256Sjkoshy __P4MASK(bb, 4), 1320145256Sjkoshy __P4MASK(bi, 5), 1321145256Sjkoshy __P4MASK(id, 6), 1322145256Sjkoshy __P4MASK(ib, 7), 1323145256Sjkoshy NULLMASK 1324145256Sjkoshy}; 1325145256Sjkoshy 1326145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1327145256Sjkoshy __P4MASK(tcmiss, 0), 1328145256Sjkoshy NULLMASK, 1329145256Sjkoshy}; 1330145256Sjkoshy 1331145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1332145256Sjkoshy __P4MASK(hit, 0), 1333145256Sjkoshy __P4MASK(miss, 1), 1334145256Sjkoshy __P4MASK(hit-uc, 2), 1335145256Sjkoshy NULLMASK 1336145256Sjkoshy}; 1337145256Sjkoshy 1338145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1339145256Sjkoshy __P4MASK(st-rb-full, 2), 1340145256Sjkoshy __P4MASK(64k-conf, 3), 1341145256Sjkoshy NULLMASK 1342145256Sjkoshy}; 1343145256Sjkoshy 1344145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1345145256Sjkoshy __P4MASK(lsc, 0), 1346145256Sjkoshy __P4MASK(ssc, 1), 1347145256Sjkoshy NULLMASK 1348145256Sjkoshy}; 1349145256Sjkoshy 1350145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1351145256Sjkoshy __P4MASK(split-ld, 1), 1352145256Sjkoshy NULLMASK 1353145256Sjkoshy}; 1354145256Sjkoshy 1355145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1356145256Sjkoshy __P4MASK(split-st, 1), 1357145256Sjkoshy NULLMASK 1358145256Sjkoshy}; 1359145256Sjkoshy 1360145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1361145256Sjkoshy __P4MASK(no-sta, 1), 1362145256Sjkoshy __P4MASK(no-std, 3), 1363145256Sjkoshy __P4MASK(partial-data, 4), 1364145256Sjkoshy __P4MASK(unalgn-addr, 5), 1365145256Sjkoshy NULLMASK 1366145256Sjkoshy}; 1367145256Sjkoshy 1368145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1369145256Sjkoshy __P4MASK(dtmiss, 0), 1370145256Sjkoshy __P4MASK(itmiss, 1), 1371145256Sjkoshy NULLMASK 1372145256Sjkoshy}; 1373145256Sjkoshy 1374145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1375145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1376145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1377145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1378145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1379145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1380145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1381145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1382145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1383145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1384145256Sjkoshy NULLMASK 1385145256Sjkoshy}; 1386145256Sjkoshy 1387145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1388145256Sjkoshy __P4MASK(all-read, 5), 1389145256Sjkoshy __P4MASK(all-write, 6), 1390145256Sjkoshy __P4MASK(mem-uc, 7), 1391145256Sjkoshy __P4MASK(mem-wc, 8), 1392145256Sjkoshy __P4MASK(mem-wt, 9), 1393145256Sjkoshy __P4MASK(mem-wp, 10), 1394145256Sjkoshy __P4MASK(mem-wb, 11), 1395145256Sjkoshy __P4MASK(own, 13), 1396145256Sjkoshy __P4MASK(other, 14), 1397145256Sjkoshy __P4MASK(prefetch, 15), 1398145256Sjkoshy NULLMASK 1399145256Sjkoshy}; 1400145256Sjkoshy 1401145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1402145256Sjkoshy __P4MASK(all-read, 5), 1403145256Sjkoshy __P4MASK(all-write, 6), 1404145256Sjkoshy __P4MASK(mem-uc, 7), 1405145256Sjkoshy __P4MASK(mem-wc, 8), 1406145256Sjkoshy __P4MASK(mem-wt, 9), 1407145256Sjkoshy __P4MASK(mem-wp, 10), 1408145256Sjkoshy __P4MASK(mem-wb, 11), 1409145256Sjkoshy __P4MASK(own, 13), 1410145256Sjkoshy __P4MASK(other, 14), 1411145256Sjkoshy __P4MASK(prefetch, 15), 1412145256Sjkoshy NULLMASK 1413145256Sjkoshy}; 1414145256Sjkoshy 1415145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1416145256Sjkoshy __P4MASK(drdy-drv, 0), 1417145256Sjkoshy __P4MASK(drdy-own, 1), 1418145256Sjkoshy __P4MASK(drdy-other, 2), 1419145256Sjkoshy __P4MASK(dbsy-drv, 3), 1420145256Sjkoshy __P4MASK(dbsy-own, 4), 1421145256Sjkoshy __P4MASK(dbsy-other, 5), 1422145256Sjkoshy NULLMASK 1423145256Sjkoshy}; 1424145256Sjkoshy 1425145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1426145256Sjkoshy __P4MASK(req-type0, 0), 1427145256Sjkoshy __P4MASK(req-type1, 1), 1428145256Sjkoshy __P4MASK(req-len0, 2), 1429145256Sjkoshy __P4MASK(req-len1, 3), 1430145256Sjkoshy __P4MASK(req-io-type, 5), 1431145256Sjkoshy __P4MASK(req-lock-type, 6), 1432145256Sjkoshy __P4MASK(req-cache-type, 7), 1433145256Sjkoshy __P4MASK(req-split-type, 8), 1434145256Sjkoshy __P4MASK(req-dem-type, 9), 1435145256Sjkoshy __P4MASK(req-ord-type, 10), 1436145256Sjkoshy __P4MASK(mem-type0, 11), 1437145256Sjkoshy __P4MASK(mem-type1, 12), 1438145256Sjkoshy __P4MASK(mem-type2, 13), 1439145256Sjkoshy NULLMASK 1440145256Sjkoshy}; 1441145256Sjkoshy 1442145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1443145256Sjkoshy __P4MASK(all, 15), 1444145256Sjkoshy NULLMASK 1445145256Sjkoshy}; 1446145256Sjkoshy 1447145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1448145256Sjkoshy __P4MASK(all, 15), 1449145256Sjkoshy NULLMASK 1450145256Sjkoshy}; 1451145256Sjkoshy 1452145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1453145256Sjkoshy __P4MASK(all, 15), 1454145256Sjkoshy NULLMASK 1455145256Sjkoshy}; 1456145256Sjkoshy 1457145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1458145256Sjkoshy __P4MASK(all, 15), 1459145256Sjkoshy NULLMASK 1460145256Sjkoshy}; 1461145256Sjkoshy 1462145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1463145256Sjkoshy __P4MASK(all, 15), 1464145256Sjkoshy NULLMASK 1465145256Sjkoshy}; 1466145256Sjkoshy 1467145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1468145256Sjkoshy __P4MASK(all, 15), 1469145256Sjkoshy NULLMASK 1470145256Sjkoshy}; 1471145256Sjkoshy 1472145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1473145256Sjkoshy __P4MASK(all, 15), 1474145256Sjkoshy NULLMASK 1475145256Sjkoshy}; 1476145256Sjkoshy 1477145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1478145256Sjkoshy __P4MASK(all, 15), 1479145256Sjkoshy NULLMASK 1480145256Sjkoshy}; 1481145256Sjkoshy 1482145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1483145256Sjkoshy __P4MASK(allp0, 3), 1484145256Sjkoshy __P4MASK(allp2, 4), 1485145256Sjkoshy NULLMASK 1486145256Sjkoshy}; 1487145256Sjkoshy 1488145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1489145256Sjkoshy __P4MASK(running, 0), 1490145256Sjkoshy NULLMASK 1491145256Sjkoshy}; 1492145256Sjkoshy 1493145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1494145256Sjkoshy __P4MASK(cisc, 0), 1495145256Sjkoshy NULLMASK 1496145256Sjkoshy}; 1497145256Sjkoshy 1498145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1499145256Sjkoshy __P4MASK(from-tc-build, 0), 1500145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1501145256Sjkoshy __P4MASK(from-rom, 2), 1502145256Sjkoshy NULLMASK 1503145256Sjkoshy}; 1504145256Sjkoshy 1505145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1506145351Sjkoshy /* retired mispred branch type */ 1507145256Sjkoshy __P4MASK(conditional, 1), 1508145256Sjkoshy __P4MASK(call, 2), 1509145256Sjkoshy __P4MASK(return, 3), 1510145256Sjkoshy __P4MASK(indirect, 4), 1511145256Sjkoshy NULLMASK 1512145256Sjkoshy}; 1513145256Sjkoshy 1514145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1515145256Sjkoshy __P4MASK(conditional, 1), 1516145256Sjkoshy __P4MASK(call, 2), 1517145256Sjkoshy __P4MASK(retired, 3), 1518145256Sjkoshy __P4MASK(indirect, 4), 1519145256Sjkoshy NULLMASK 1520145256Sjkoshy}; 1521145256Sjkoshy 1522145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1523145256Sjkoshy __P4MASK(sbfull, 5), 1524145256Sjkoshy NULLMASK 1525145256Sjkoshy}; 1526145256Sjkoshy 1527145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1528145256Sjkoshy __P4MASK(wcb-evicts, 0), 1529145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1530145256Sjkoshy NULLMASK 1531145256Sjkoshy}; 1532145256Sjkoshy 1533145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1534145256Sjkoshy __P4MASK(nbogus, 0), 1535145256Sjkoshy __P4MASK(bogus, 1), 1536145256Sjkoshy NULLMASK 1537145256Sjkoshy}; 1538145256Sjkoshy 1539145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1540145256Sjkoshy __P4MASK(nbogus0, 0), 1541145256Sjkoshy __P4MASK(nbogus1, 1), 1542145256Sjkoshy __P4MASK(nbogus2, 2), 1543145256Sjkoshy __P4MASK(nbogus3, 3), 1544145256Sjkoshy __P4MASK(bogus0, 4), 1545145256Sjkoshy __P4MASK(bogus1, 5), 1546145256Sjkoshy __P4MASK(bogus2, 6), 1547145256Sjkoshy __P4MASK(bogus3, 7), 1548145256Sjkoshy NULLMASK 1549145256Sjkoshy}; 1550145256Sjkoshy 1551145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1552145256Sjkoshy __P4MASK(nbogus, 0), 1553145256Sjkoshy __P4MASK(bogus, 1), 1554145256Sjkoshy NULLMASK 1555145256Sjkoshy}; 1556145256Sjkoshy 1557145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1558145256Sjkoshy __P4MASK(nbogusntag, 0), 1559145256Sjkoshy __P4MASK(nbogustag, 1), 1560145256Sjkoshy __P4MASK(bogusntag, 2), 1561145256Sjkoshy __P4MASK(bogustag, 3), 1562145256Sjkoshy NULLMASK 1563145256Sjkoshy}; 1564145256Sjkoshy 1565145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1566145256Sjkoshy __P4MASK(nbogus, 0), 1567145256Sjkoshy __P4MASK(bogus, 1), 1568145256Sjkoshy NULLMASK 1569145256Sjkoshy}; 1570145256Sjkoshy 1571145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1572145256Sjkoshy __P4MASK(tagloads, 1), 1573145256Sjkoshy __P4MASK(tagstores, 2), 1574145256Sjkoshy NULLMASK 1575145256Sjkoshy}; 1576145256Sjkoshy 1577145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1578145256Sjkoshy __P4MASK(mmnp, 0), 1579145256Sjkoshy __P4MASK(mmnm, 1), 1580145256Sjkoshy __P4MASK(mmtp, 2), 1581145256Sjkoshy __P4MASK(mmtm, 3), 1582145256Sjkoshy NULLMASK 1583145256Sjkoshy}; 1584145256Sjkoshy 1585145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1586145256Sjkoshy __P4MASK(nbogus, 0), 1587145256Sjkoshy NULLMASK 1588145256Sjkoshy}; 1589145256Sjkoshy 1590145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1591145256Sjkoshy __P4MASK(fpsu, 0), 1592145256Sjkoshy __P4MASK(fpso, 1), 1593145256Sjkoshy __P4MASK(poao, 2), 1594145256Sjkoshy __P4MASK(poau, 3), 1595145256Sjkoshy __P4MASK(prea, 4), 1596145256Sjkoshy NULLMASK 1597145256Sjkoshy}; 1598145256Sjkoshy 1599145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1600145256Sjkoshy __P4MASK(clear, 0), 1601145256Sjkoshy __P4MASK(moclear, 2), 1602145256Sjkoshy __P4MASK(smclear, 3), 1603145256Sjkoshy NULLMASK 1604145256Sjkoshy}; 1605145256Sjkoshy 1606145256Sjkoshy/* P4 event parser */ 1607145256Sjkoshystatic int 1608145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1609145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1610145256Sjkoshy{ 1611145256Sjkoshy 1612145256Sjkoshy char *e, *p, *q; 1613145256Sjkoshy int count, has_tag, has_busreqtype, n; 1614240164Sfabient uint32_t cccractivemask; 1615240164Sfabient uint64_t evmask; 1616145256Sjkoshy const struct pmc_masks *pm, *pmask; 1617145256Sjkoshy 1618183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1619147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1620147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1621145256Sjkoshy 1622145256Sjkoshy pmask = NULL; 1623145256Sjkoshy evmask = 0; 1624145256Sjkoshy cccractivemask = 0x3; 1625145256Sjkoshy has_tag = has_busreqtype = 0; 1626145256Sjkoshy 1627145256Sjkoshy#define __P4SETMASK(M) do { \ 1628183107Sjkoshy pmask = p4_mask_##M; \ 1629145256Sjkoshy} while (0) 1630145256Sjkoshy 1631145256Sjkoshy switch (pe) { 1632145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1633145256Sjkoshy __P4SETMASK(tcdm); 1634145256Sjkoshy break; 1635145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1636145256Sjkoshy __P4SETMASK(bfr); 1637145256Sjkoshy break; 1638145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1639145256Sjkoshy __P4SETMASK(ir); 1640145256Sjkoshy break; 1641145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1642145256Sjkoshy __P4SETMASK(memcan); 1643145256Sjkoshy break; 1644145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1645145256Sjkoshy __P4SETMASK(memcomp); 1646145256Sjkoshy break; 1647145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1648145256Sjkoshy __P4SETMASK(lpr); 1649145256Sjkoshy break; 1650145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1651145256Sjkoshy __P4SETMASK(spr); 1652145256Sjkoshy break; 1653145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1654145256Sjkoshy __P4SETMASK(mlr); 1655145256Sjkoshy break; 1656145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1657145256Sjkoshy __P4SETMASK(pwt); 1658145256Sjkoshy break; 1659145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1660145256Sjkoshy __P4SETMASK(bcr); 1661145256Sjkoshy break; 1662145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1663145256Sjkoshy __P4SETMASK(ia); 1664145256Sjkoshy has_busreqtype = 1; 1665145256Sjkoshy break; 1666145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1667145256Sjkoshy __P4SETMASK(iae); 1668145256Sjkoshy has_busreqtype = 1; 1669145256Sjkoshy break; 1670145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1671145256Sjkoshy __P4SETMASK(fda); 1672145256Sjkoshy break; 1673145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1674145256Sjkoshy __P4SETMASK(ba); 1675145256Sjkoshy break; 1676145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1677145256Sjkoshy __P4SETMASK(sia); 1678145256Sjkoshy break; 1679145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1680145256Sjkoshy __P4SETMASK(psu); 1681145256Sjkoshy break; 1682145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1683145256Sjkoshy __P4SETMASK(pdu); 1684145256Sjkoshy break; 1685145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1686145256Sjkoshy __P4SETMASK(ssu); 1687145256Sjkoshy break; 1688145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1689145256Sjkoshy __P4SETMASK(sdu); 1690145256Sjkoshy break; 1691145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1692145256Sjkoshy __P4SETMASK(64bmu); 1693145256Sjkoshy break; 1694145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1695145256Sjkoshy __P4SETMASK(128bmu); 1696145256Sjkoshy break; 1697145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1698145256Sjkoshy __P4SETMASK(xfu); 1699145256Sjkoshy break; 1700145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1701145256Sjkoshy __P4SETMASK(xsmu); 1702145256Sjkoshy break; 1703145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1704145256Sjkoshy __P4SETMASK(gpe); 1705145256Sjkoshy break; 1706145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1707145256Sjkoshy __P4SETMASK(tmx); 1708145256Sjkoshy break; 1709145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1710145256Sjkoshy __P4SETMASK(uqw); 1711145256Sjkoshy break; 1712145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1713145256Sjkoshy __P4SETMASK(rmbt); 1714145256Sjkoshy break; 1715145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1716145256Sjkoshy __P4SETMASK(rbt); 1717145256Sjkoshy break; 1718145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1719145256Sjkoshy __P4SETMASK(rs); 1720145256Sjkoshy break; 1721145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1722145256Sjkoshy __P4SETMASK(wb); 1723145256Sjkoshy break; 1724145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1725145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1726145256Sjkoshy case PMC_EV_P4_BNR: 1727145256Sjkoshy case PMC_EV_P4_SNOOP: 1728145256Sjkoshy case PMC_EV_P4_RESPONSE: 1729145256Sjkoshy break; 1730145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1731145256Sjkoshy __P4SETMASK(fee); 1732145256Sjkoshy break; 1733145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1734145256Sjkoshy __P4SETMASK(ee); 1735145256Sjkoshy break; 1736145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1737145256Sjkoshy __P4SETMASK(re); 1738145256Sjkoshy break; 1739145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1740145256Sjkoshy __P4SETMASK(insret); 1741145256Sjkoshy break; 1742145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1743145256Sjkoshy __P4SETMASK(ur); 1744145256Sjkoshy break; 1745145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1746145256Sjkoshy __P4SETMASK(ut); 1747145256Sjkoshy break; 1748145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1749145256Sjkoshy __P4SETMASK(br); 1750145256Sjkoshy break; 1751145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1752145256Sjkoshy __P4SETMASK(mbr); 1753145256Sjkoshy break; 1754145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1755145256Sjkoshy __P4SETMASK(xa); 1756145256Sjkoshy break; 1757145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1758145256Sjkoshy __P4SETMASK(machclr); 1759145256Sjkoshy break; 1760145256Sjkoshy default: 1761174406Sjkoshy return (-1); 1762145256Sjkoshy } 1763145256Sjkoshy 1764145256Sjkoshy /* process additional flags */ 1765145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1766145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1767145256Sjkoshy q = strchr(p, '='); 1768145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1769174406Sjkoshy return (-1); 1770145256Sjkoshy 1771183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1772145256Sjkoshy cccractivemask = 0x0; 1773183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1774145256Sjkoshy cccractivemask = 0x1; 1775183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1776145256Sjkoshy cccractivemask = 0x2; 1777183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1778145256Sjkoshy cccractivemask = 0x3; 1779145256Sjkoshy else 1780174406Sjkoshy return (-1); 1781145256Sjkoshy 1782145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1783145256Sjkoshy if (has_busreqtype == 0) 1784174406Sjkoshy return (-1); 1785145256Sjkoshy 1786145256Sjkoshy q = strchr(p, '='); 1787145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1788174406Sjkoshy return (-1); 1789145256Sjkoshy 1790145256Sjkoshy count = strtol(q, &e, 0); 1791145256Sjkoshy if (e == q || *e != '\0') 1792174406Sjkoshy return (-1); 1793145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1794145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1795145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1796145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1797145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1798145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1799145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1800145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1801145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1802174406Sjkoshy return (-1); 1803145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1804145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1805145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1806145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1807145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1808145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1809145256Sjkoshy if (has_tag == 0) 1810174406Sjkoshy return (-1); 1811145256Sjkoshy 1812145256Sjkoshy q = strchr(p, '='); 1813145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1814174406Sjkoshy return (-1); 1815145256Sjkoshy 1816145256Sjkoshy count = strtol(q, &e, 0); 1817145256Sjkoshy if (e == q || *e != '\0') 1818174406Sjkoshy return (-1); 1819145256Sjkoshy 1820145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1821147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1822145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1823145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1824145256Sjkoshy q = strchr(p, '='); 1825145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1826174406Sjkoshy return (-1); 1827145256Sjkoshy 1828145256Sjkoshy count = strtol(q, &e, 0); 1829145256Sjkoshy if (e == q || *e != '\0') 1830174406Sjkoshy return (-1); 1831145256Sjkoshy 1832145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1833147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1834147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1835147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1836147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1837145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1838145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1839145256Sjkoshy else 1840174406Sjkoshy return (-1); 1841145256Sjkoshy } 1842145256Sjkoshy 1843145256Sjkoshy /* other post processing */ 1844145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1845145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1846145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1847145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1848145256Sjkoshy 1849145256Sjkoshy /* fill in thread activity mask */ 1850147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1851145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1852145256Sjkoshy 1853145256Sjkoshy if (evmask) 1854145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1855145256Sjkoshy 1856145256Sjkoshy switch (pe) { 1857145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1858145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1859145256Sjkoshy (evmask & 0x18) == 0x18) 1860174406Sjkoshy return (-1); /* can't have own+other bits together */ 1861145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1862145256Sjkoshy evmask = 0x1D; 1863145256Sjkoshy break; 1864145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1865145256Sjkoshy /* only one bit is allowed to be set */ 1866145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1867174406Sjkoshy return (-1); 1868145256Sjkoshy if (evmask == 0) { 1869183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1870145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1871145256Sjkoshy } 1872145256Sjkoshy break; 1873145256Sjkoshy default: 1874145256Sjkoshy if (evmask == 0 && pmask) { 1875145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1876145256Sjkoshy evmask |= pm->pm_value; 1877145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1878145256Sjkoshy } 1879145256Sjkoshy } 1880145256Sjkoshy 1881147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1882147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1883145256Sjkoshy 1884174406Sjkoshy return (0); 1885145256Sjkoshy} 1886145256Sjkoshy 1887147759Sjkoshy#endif 1888147759Sjkoshy 1889147759Sjkoshy#if defined(__i386__) 1890147759Sjkoshy 1891145256Sjkoshy/* 1892147191Sjkoshy * Pentium style PMCs 1893147191Sjkoshy */ 1894147191Sjkoshy 1895147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1896183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1897183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1898183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1899183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1900183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1901183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1902183105Sjkoshy EV_ALIAS("unhalted-cycles", 1903183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1904147191Sjkoshy EV_ALIAS(NULL, NULL) 1905147191Sjkoshy}; 1906147191Sjkoshy 1907147191Sjkoshystatic int 1908147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1909147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1910147191Sjkoshy{ 1911174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1912147191Sjkoshy} 1913147191Sjkoshy 1914147191Sjkoshy/* 1915145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1916145256Sjkoshy * and Pentium M CPUs. 1917145256Sjkoshy */ 1918145256Sjkoshy 1919145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1920145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1921145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1922145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1923145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1924168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1925145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1926145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1927155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1928145351Sjkoshy EV_ALIAS(NULL, NULL) 1929145256Sjkoshy}; 1930145256Sjkoshy 1931145256Sjkoshy#define P6_KW_CMASK "cmask" 1932145256Sjkoshy#define P6_KW_EDGE "edge" 1933145256Sjkoshy#define P6_KW_INV "inv" 1934145256Sjkoshy#define P6_KW_OS "os" 1935145256Sjkoshy#define P6_KW_UMASK "umask" 1936145256Sjkoshy#define P6_KW_USR "usr" 1937145256Sjkoshy 1938145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1939145256Sjkoshy PMCMASK(m, 0x01), 1940145256Sjkoshy PMCMASK(e, 0x02), 1941145256Sjkoshy PMCMASK(s, 0x04), 1942145256Sjkoshy PMCMASK(i, 0x08), 1943145256Sjkoshy NULLMASK 1944145256Sjkoshy}; 1945145256Sjkoshy 1946145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1947145256Sjkoshy PMCMASK(m, 0x01), 1948145256Sjkoshy PMCMASK(e, 0x02), 1949145256Sjkoshy PMCMASK(s, 0x04), 1950145256Sjkoshy PMCMASK(i, 0x08), 1951145256Sjkoshy PMCMASK(nonhw, 0x00), 1952145256Sjkoshy PMCMASK(hw, 0x10), 1953145256Sjkoshy PMCMASK(both, 0x30), 1954145256Sjkoshy NULLMASK 1955145256Sjkoshy}; 1956145256Sjkoshy 1957145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1958145256Sjkoshy PMCMASK(nonhw, 0x00), 1959145256Sjkoshy PMCMASK(hw, 0x10), 1960145256Sjkoshy PMCMASK(both, 0x30), 1961145256Sjkoshy NULLMASK 1962145256Sjkoshy}; 1963145256Sjkoshy 1964145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1965145256Sjkoshy PMCMASK(self, 0x00), 1966145256Sjkoshy PMCMASK(any, 0x20), 1967145256Sjkoshy NULLMASK 1968145256Sjkoshy}; 1969145256Sjkoshy 1970145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1971145256Sjkoshy PMCMASK(nta, 0x00), 1972145256Sjkoshy PMCMASK(t1, 0x01), 1973145256Sjkoshy PMCMASK(t2, 0x02), 1974145256Sjkoshy PMCMASK(wos, 0x03), 1975145256Sjkoshy NULLMASK 1976145256Sjkoshy}; 1977145256Sjkoshy 1978145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1979145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1980145256Sjkoshy PMCMASK(scalar, 0x01), 1981145256Sjkoshy NULLMASK 1982145256Sjkoshy}; 1983145256Sjkoshy 1984145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1985145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1986145256Sjkoshy PMCMASK(packed-shift, 0x02), 1987145256Sjkoshy PMCMASK(pack, 0x04), 1988145256Sjkoshy PMCMASK(unpack, 0x08), 1989145256Sjkoshy PMCMASK(packed-logical, 0x10), 1990145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1991145256Sjkoshy NULLMASK 1992145256Sjkoshy}; 1993145256Sjkoshy 1994145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1995145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1996145256Sjkoshy PMCMASK(fptommx, 0x01), 1997145256Sjkoshy NULLMASK 1998145256Sjkoshy}; 1999145256Sjkoshy 2000145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 2001145256Sjkoshy PMCMASK(es, 0x01), 2002145256Sjkoshy PMCMASK(ds, 0x02), 2003145256Sjkoshy PMCMASK(fs, 0x04), 2004145256Sjkoshy PMCMASK(gs, 0x08), 2005145256Sjkoshy NULLMASK 2006145256Sjkoshy}; 2007145256Sjkoshy 2008145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 2009145256Sjkoshy PMCMASK(all, 0x00), 2010145256Sjkoshy PMCMASK(freq, 0x02), 2011145256Sjkoshy NULLMASK 2012145256Sjkoshy}; 2013145256Sjkoshy 2014145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 2015145256Sjkoshy PMCMASK(all, 0x00), 2016145256Sjkoshy PMCMASK(loadop, 0x01), 2017145256Sjkoshy PMCMASK(stdsta, 0x02), 2018145256Sjkoshy NULLMASK 2019145256Sjkoshy}; 2020145256Sjkoshy 2021145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 2022145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2023145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 2024145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2025145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2026145256Sjkoshy NULLMASK 2027145256Sjkoshy}; 2028145256Sjkoshy 2029145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 2030145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2031145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 2032145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2033145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2034145256Sjkoshy NULLMASK 2035145256Sjkoshy}; 2036145256Sjkoshy 2037145256Sjkoshy/* P6 event parser */ 2038145256Sjkoshystatic int 2039145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 2040145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2041145256Sjkoshy{ 2042145256Sjkoshy char *e, *p, *q; 2043240164Sfabient uint64_t evmask; 2044145256Sjkoshy int count, n; 2045145256Sjkoshy const struct pmc_masks *pm, *pmask; 2046145256Sjkoshy 2047183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2048147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 2049145256Sjkoshy 2050145256Sjkoshy evmask = 0; 2051145256Sjkoshy 2052145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 2053145256Sjkoshy 2054145256Sjkoshy switch(pe) { 2055183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 2056145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 2057145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2058145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2059145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2060145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2061145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2062145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2063145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2064145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2065145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2066145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2067145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2068145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2069145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2070145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2071145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2072145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2073145256Sjkoshy P6MASKSET(any); break; 2074145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2075145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2076145256Sjkoshy P6MASKSET(ekp); break; 2077145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2078145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2079145256Sjkoshy P6MASKSET(pps); break; 2080145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2081145256Sjkoshy P6MASKSET(mite); break; 2082145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2083145256Sjkoshy P6MASKSET(fmt); break; 2084145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2085145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2086145256Sjkoshy P6MASKSET(sr); break; 2087145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2088145256Sjkoshy P6MASKSET(eet); break; 2089145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2090145256Sjkoshy P6MASKSET(efur); break; 2091145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2092145256Sjkoshy P6MASKSET(essir); break; 2093145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2094145256Sjkoshy P6MASKSET(esscir); break; 2095145256Sjkoshy default: 2096145256Sjkoshy pmask = NULL; 2097145256Sjkoshy break; 2098145256Sjkoshy } 2099145256Sjkoshy 2100145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2101145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2102145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2103145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2104145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2105145256Sjkoshy P6MASKSET(mesihw); 2106145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2107145256Sjkoshy P6MASKSET(hw); 2108145256Sjkoshy } 2109145256Sjkoshy 2110145256Sjkoshy /* Parse additional modifiers if present */ 2111145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2112145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2113145256Sjkoshy q = strchr(p, '='); 2114145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2115174406Sjkoshy return (-1); 2116145256Sjkoshy count = strtol(q, &e, 0); 2117145256Sjkoshy if (e == q || *e != '\0') 2118174406Sjkoshy return (-1); 2119145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2120147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2121147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2122145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2123145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2124145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2125145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2126145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2127145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2128145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2129145256Sjkoshy evmask = 0; 2130145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2131174406Sjkoshy return (-1); 2132145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2133145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2134145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2135145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2136145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2137145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2138145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2139145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2140145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2141145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2142145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2143145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2144145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2145145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2146145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2147145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2148145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2149145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2150145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2151145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2152145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2153145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2154145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2155174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2156174406Sjkoshy return (-1); 2157145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2158145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2159145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2160145256Sjkoshy } else 2161174406Sjkoshy return (-1); 2162145256Sjkoshy } 2163145256Sjkoshy 2164145256Sjkoshy /* post processing */ 2165145256Sjkoshy switch (pe) { 2166145256Sjkoshy 2167145256Sjkoshy /* 2168145256Sjkoshy * The following events default to an evmask of 0 2169145256Sjkoshy */ 2170145256Sjkoshy 2171145256Sjkoshy /* default => 'self' */ 2172145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2173145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2174145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2175145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2176145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2177145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2178145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2179145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2180145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2181145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2182145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2183145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2184145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2185145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2186145256Sjkoshy 2187145256Sjkoshy /* default => 'nta' */ 2188145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2189145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2190145256Sjkoshy 2191145256Sjkoshy /* default => 'packed and scalar' */ 2192145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2193145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2194145256Sjkoshy 2195145256Sjkoshy /* default => 'mmx to fp transitions' */ 2196145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2197145256Sjkoshy 2198145256Sjkoshy /* default => 'SSE Packed Single' */ 2199145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2200145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2201145256Sjkoshy 2202145256Sjkoshy /* default => 'all fused micro-ops' */ 2203145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2204145256Sjkoshy 2205145256Sjkoshy /* default => 'all transitions' */ 2206145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2207145256Sjkoshy break; 2208145256Sjkoshy 2209145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2210145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2211145256Sjkoshy break; 2212145256Sjkoshy 2213145256Sjkoshy default: 2214145256Sjkoshy /* 2215145256Sjkoshy * For all other events, set the default event mask 2216145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2217145256Sjkoshy */ 2218145256Sjkoshy if (evmask == 0 && pmask) { 2219145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2220145256Sjkoshy evmask |= pm->pm_value; 2221145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2222145256Sjkoshy } 2223145256Sjkoshy 2224145256Sjkoshy break; 2225145256Sjkoshy } 2226145256Sjkoshy 2227145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2228147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2229147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2230145256Sjkoshy 2231174406Sjkoshy return (0); 2232145256Sjkoshy} 2233145256Sjkoshy 2234147191Sjkoshy#endif 2235147191Sjkoshy 2236183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2237183725Sjkoshystatic int 2238183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2239183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2240183725Sjkoshy{ 2241183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2242183725Sjkoshy return (-1); 2243183725Sjkoshy 2244183725Sjkoshy /* TSC events must be unqualified. */ 2245183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2246183725Sjkoshy return (-1); 2247183725Sjkoshy 2248183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2249183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2250183725Sjkoshy 2251183725Sjkoshy return (0); 2252183725Sjkoshy} 2253183725Sjkoshy#endif 2254183725Sjkoshy 2255233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2256233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2257233628Sfabient EV_ALIAS(NULL, NULL) 2258233628Sfabient}; 2259233628Sfabient 2260233628Sfabientstatic int 2261233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2262233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2263233628Sfabient{ 2264233628Sfabient (void)ctrspec; 2265233628Sfabient (void)pmc_config; 2266233628Sfabient 2267233628Sfabient if (pe < PMC_EV_SOFT_FIRST || pe > PMC_EV_SOFT_LAST) 2268233628Sfabient return (-1); 2269233628Sfabient 2270233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2271233628Sfabient return (0); 2272233628Sfabient} 2273233628Sfabient 2274200928Srpaulo#if defined(__XSCALE__) 2275200928Srpaulo 2276200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2277200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2278200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2279200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2280200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2281200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2282200928Srpaulo EV_ALIAS(NULL, NULL) 2283200928Srpaulo}; 2284200928Srpaulostatic int 2285200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2286200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2287200928Srpaulo{ 2288200928Srpaulo switch (pe) { 2289200928Srpaulo default: 2290200928Srpaulo break; 2291200928Srpaulo } 2292200928Srpaulo 2293200928Srpaulo return (0); 2294200928Srpaulo} 2295200928Srpaulo#endif 2296200928Srpaulo 2297204635Sgnn#if defined(__mips__) 2298204635Sgnn 2299204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2300204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2301204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2302204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2303204635Sgnn EV_ALIAS(NULL, NULL) 2304204635Sgnn}; 2305204635Sgnn 2306233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2307233335Sgonzo EV_ALIAS("instructions", "RET"), 2308233335Sgonzo EV_ALIAS("branches", "BR"), 2309233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2310233335Sgonzo EV_ALIAS(NULL, NULL) 2311233335Sgonzo}; 2312233335Sgonzo 2313233320Sgonzo#define MIPS_KW_OS "os" 2314233320Sgonzo#define MIPS_KW_USR "usr" 2315233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2316204635Sgnn 2317204635Sgnnstatic int 2318233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2319204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2320204635Sgnn{ 2321204635Sgnn char *p; 2322204635Sgnn 2323204635Sgnn (void) pe; 2324204635Sgnn 2325204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2326204635Sgnn 2327204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2328233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2329204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2330233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2331204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2332233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2333204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2334204635Sgnn else 2335204635Sgnn return (-1); 2336204635Sgnn } 2337204635Sgnn 2338204635Sgnn return (0); 2339204635Sgnn} 2340233320Sgonzo 2341204635Sgnn#endif /* __mips__ */ 2342204635Sgnn 2343228869Sjhibbits#if defined(__powerpc__) 2344204635Sgnn 2345228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2346228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2347228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2348228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2349228869Sjhibbits EV_ALIAS(NULL, NULL) 2350228869Sjhibbits}; 2351228869Sjhibbits 2352228869Sjhibbits#define PPC7450_KW_OS "os" 2353228869Sjhibbits#define PPC7450_KW_USR "usr" 2354228869Sjhibbits#define PPC7450_KW_ANYTHREAD "anythread" 2355228869Sjhibbits 2356228869Sjhibbitsstatic int 2357228869Sjhibbitsppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2358228869Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2359228869Sjhibbits{ 2360228869Sjhibbits char *p; 2361228869Sjhibbits 2362228869Sjhibbits (void) pe; 2363228869Sjhibbits 2364228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2365228869Sjhibbits 2366228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2367228869Sjhibbits if (KWMATCH(p, PPC7450_KW_OS)) 2368228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2369228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_USR)) 2370228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2371228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_ANYTHREAD)) 2372228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2373228869Sjhibbits else 2374228869Sjhibbits return (-1); 2375228869Sjhibbits } 2376228869Sjhibbits 2377228869Sjhibbits return (0); 2378228869Sjhibbits} 2379228869Sjhibbits#endif /* __powerpc__ */ 2380228869Sjhibbits 2381228869Sjhibbits 2382145256Sjkoshy/* 2383183725Sjkoshy * Match an event name `name' with its canonical form. 2384183725Sjkoshy * 2385185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2386185363Sjkoshy * hyphen characters are considered to match each other. 2387185363Sjkoshy * 2388183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2389183725Sjkoshy */ 2390183725Sjkoshy 2391183725Sjkoshystatic int 2392183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2393183725Sjkoshy{ 2394183725Sjkoshy int cc, nc; 2395183725Sjkoshy const unsigned char *c, *n; 2396183725Sjkoshy 2397183725Sjkoshy c = (const unsigned char *) canonicalname; 2398183725Sjkoshy n = (const unsigned char *) name; 2399183725Sjkoshy 2400183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2401183725Sjkoshy 2402185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2403185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2404183725Sjkoshy continue; 2405183725Sjkoshy 2406185363Sjkoshy if (toupper(nc) == toupper(cc)) 2407183725Sjkoshy continue; 2408183725Sjkoshy 2409185363Sjkoshy 2410183725Sjkoshy return (0); 2411183725Sjkoshy } 2412183725Sjkoshy 2413183725Sjkoshy if (*n == '\0' && *c == '\0') 2414183725Sjkoshy return (1); 2415183725Sjkoshy 2416183725Sjkoshy return (0); 2417183725Sjkoshy} 2418183725Sjkoshy 2419183725Sjkoshy/* 2420183725Sjkoshy * Match an event name against all the event named supported by a 2421183725Sjkoshy * PMC class. 2422183725Sjkoshy * 2423183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2424183725Sjkoshy */ 2425183725Sjkoshystatic const struct pmc_event_descr * 2426183725Sjkoshypmc_match_event_class(const char *name, 2427183725Sjkoshy const struct pmc_class_descr *pcd) 2428183725Sjkoshy{ 2429183725Sjkoshy size_t n; 2430183725Sjkoshy const struct pmc_event_descr *ev; 2431185363Sjkoshy 2432183725Sjkoshy ev = pcd->pm_evc_event_table; 2433183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2434183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2435183725Sjkoshy return (ev); 2436183725Sjkoshy 2437183725Sjkoshy return (NULL); 2438183725Sjkoshy} 2439183725Sjkoshy 2440183725Sjkoshystatic int 2441183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2442183725Sjkoshy{ 2443183725Sjkoshy size_t n; 2444183725Sjkoshy 2445183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2446183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2447183725Sjkoshy return (1); 2448183725Sjkoshy return (0); 2449183725Sjkoshy} 2450183725Sjkoshy 2451183725Sjkoshy/* 2452147191Sjkoshy * API entry points 2453145256Sjkoshy */ 2454145256Sjkoshy 2455147191Sjkoshyint 2456147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2457147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2458145256Sjkoshy{ 2459183725Sjkoshy size_t n; 2460147191Sjkoshy int retval; 2461147191Sjkoshy char *r, *spec_copy; 2462147191Sjkoshy const char *ctrname; 2463183725Sjkoshy const struct pmc_event_descr *ev; 2464183725Sjkoshy const struct pmc_event_alias *alias; 2465147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2466183725Sjkoshy const struct pmc_class_descr *pcd; 2467145256Sjkoshy 2468147191Sjkoshy spec_copy = NULL; 2469147191Sjkoshy retval = -1; 2470145256Sjkoshy 2471147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2472147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2473147191Sjkoshy errno = EINVAL; 2474147191Sjkoshy goto out; 2475147191Sjkoshy } 2476145256Sjkoshy 2477147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2478147191Sjkoshy if (pmc_mdep_event_aliases) 2479183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2480183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2481183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2482147191Sjkoshy break; 2483147191Sjkoshy } 2484145256Sjkoshy 2485147191Sjkoshy if (spec_copy == NULL) 2486147191Sjkoshy spec_copy = strdup(ctrspec); 2487145256Sjkoshy 2488147191Sjkoshy r = spec_copy; 2489147191Sjkoshy ctrname = strsep(&r, ","); 2490145256Sjkoshy 2491183725Sjkoshy /* 2492183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2493183725Sjkoshy * search for the event to the specified PMC class. 2494183725Sjkoshy */ 2495183725Sjkoshy ev = NULL; 2496185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2497185363Sjkoshy pcd = pmc_class_table[n]; 2498183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2499183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2500183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2501183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2502183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2503183725Sjkoshy errno = EINVAL; 2504183725Sjkoshy goto out; 2505183725Sjkoshy } 2506147191Sjkoshy break; 2507183725Sjkoshy } 2508183725Sjkoshy } 2509145256Sjkoshy 2510183725Sjkoshy /* 2511183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2512183725Sjkoshy * classes. 2513183725Sjkoshy */ 2514185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2515185363Sjkoshy pcd = pmc_class_table[n]; 2516183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2517183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2518183725Sjkoshy } 2519183725Sjkoshy 2520183725Sjkoshy if (ev == NULL) { 2521147191Sjkoshy errno = EINVAL; 2522147191Sjkoshy goto out; 2523147191Sjkoshy } 2524145256Sjkoshy 2525147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2526183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2527183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2528147191Sjkoshy pmc_config.pm_cpu = cpu; 2529147191Sjkoshy pmc_config.pm_mode = mode; 2530147191Sjkoshy pmc_config.pm_flags = flags; 2531145256Sjkoshy 2532147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2533147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2534145256Sjkoshy 2535183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2536147191Sjkoshy errno = EINVAL; 2537147191Sjkoshy goto out; 2538147191Sjkoshy } 2539145256Sjkoshy 2540147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2541147191Sjkoshy goto out; 2542145256Sjkoshy 2543147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2544145256Sjkoshy 2545147191Sjkoshy retval = 0; 2546145256Sjkoshy 2547147191Sjkoshy out: 2548147191Sjkoshy if (spec_copy) 2549147191Sjkoshy free(spec_copy); 2550145256Sjkoshy 2551174406Sjkoshy return (retval); 2552147191Sjkoshy} 2553145256Sjkoshy 2554147191Sjkoshyint 2555147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2556147191Sjkoshy{ 2557147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2558145256Sjkoshy 2559147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2560147191Sjkoshy pmc_attach_args.pm_pid = pid; 2561145256Sjkoshy 2562174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2563147191Sjkoshy} 2564145256Sjkoshy 2565147191Sjkoshyint 2566147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2567147191Sjkoshy{ 2568147191Sjkoshy unsigned int i; 2569147191Sjkoshy enum pmc_class cl; 2570145256Sjkoshy 2571147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2572147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2573147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2574147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2575174406Sjkoshy return (0); 2576147191Sjkoshy } 2577177107Sjkoshy errno = EINVAL; 2578177107Sjkoshy return (-1); 2579147191Sjkoshy} 2580145256Sjkoshy 2581147191Sjkoshyint 2582147191Sjkoshypmc_configure_logfile(int fd) 2583147191Sjkoshy{ 2584147191Sjkoshy struct pmc_op_configurelog cla; 2585145256Sjkoshy 2586147191Sjkoshy cla.pm_logfd = fd; 2587147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2588174406Sjkoshy return (-1); 2589174406Sjkoshy return (0); 2590147191Sjkoshy} 2591145256Sjkoshy 2592147191Sjkoshyint 2593147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2594147191Sjkoshy{ 2595147191Sjkoshy if (pmc_syscall == -1) { 2596147191Sjkoshy errno = ENXIO; 2597174406Sjkoshy return (-1); 2598147191Sjkoshy } 2599145256Sjkoshy 2600147219Sjkoshy *pci = &cpu_info; 2601174406Sjkoshy return (0); 2602147191Sjkoshy} 2603145256Sjkoshy 2604147191Sjkoshyint 2605147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2606147191Sjkoshy{ 2607147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2608145256Sjkoshy 2609147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2610147191Sjkoshy pmc_detach_args.pm_pid = pid; 2611174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2612147191Sjkoshy} 2613147191Sjkoshy 2614147191Sjkoshyint 2615147191Sjkoshypmc_disable(int cpu, int pmc) 2616145256Sjkoshy{ 2617147191Sjkoshy struct pmc_op_pmcadmin ssa; 2618145256Sjkoshy 2619147191Sjkoshy ssa.pm_cpu = cpu; 2620147191Sjkoshy ssa.pm_pmc = pmc; 2621147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2622174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2623147191Sjkoshy} 2624145256Sjkoshy 2625147191Sjkoshyint 2626147191Sjkoshypmc_enable(int cpu, int pmc) 2627147191Sjkoshy{ 2628147191Sjkoshy struct pmc_op_pmcadmin ssa; 2629145256Sjkoshy 2630147191Sjkoshy ssa.pm_cpu = cpu; 2631147191Sjkoshy ssa.pm_pmc = pmc; 2632147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2633174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2634147191Sjkoshy} 2635145256Sjkoshy 2636147191Sjkoshy/* 2637147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2638147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2639147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2640147191Sjkoshy * the number of event name pointers returned. 2641147191Sjkoshy * 2642147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2643147191Sjkoshy * is responsible for freeing this space when done. 2644147191Sjkoshy */ 2645147191Sjkoshyint 2646147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2647147191Sjkoshy int *nevents) 2648147191Sjkoshy{ 2649147191Sjkoshy int count; 2650147191Sjkoshy const char **names; 2651147191Sjkoshy const struct pmc_event_descr *ev; 2652147191Sjkoshy 2653147191Sjkoshy switch (cl) 2654147191Sjkoshy { 2655185363Sjkoshy case PMC_CLASS_IAF: 2656185363Sjkoshy ev = iaf_event_table; 2657185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2658185363Sjkoshy break; 2659185363Sjkoshy case PMC_CLASS_IAP: 2660185363Sjkoshy /* 2661185363Sjkoshy * Return the most appropriate set of event name 2662185363Sjkoshy * spellings for the current CPU. 2663185363Sjkoshy */ 2664185363Sjkoshy switch (cpu_info.pm_cputype) { 2665185363Sjkoshy default: 2666185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2667185363Sjkoshy ev = atom_event_table; 2668185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2669185363Sjkoshy break; 2670185363Sjkoshy case PMC_CPU_INTEL_CORE: 2671185363Sjkoshy ev = core_event_table; 2672185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2673185363Sjkoshy break; 2674185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2675185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2676185363Sjkoshy ev = core2_event_table; 2677185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2678185363Sjkoshy break; 2679187761Sjeff case PMC_CPU_INTEL_COREI7: 2680187761Sjeff ev = corei7_event_table; 2681187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2682187761Sjeff break; 2683240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2684240164Sfabient ev = ivybridge_event_table; 2685240164Sfabient count = PMC_EVENT_TABLE_SIZE(ivybridge); 2686240164Sfabient break; 2687232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2688232366Sdavide ev = sandybridge_event_table; 2689232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2690232366Sdavide break; 2691241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2692241738Ssbruno ev = sandybridge_xeon_event_table; 2693241738Ssbruno count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 2694241738Ssbruno break; 2695206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2696206089Sfabient ev = westmere_event_table; 2697206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2698206089Sfabient break; 2699185363Sjkoshy } 2700185363Sjkoshy break; 2701206089Sfabient case PMC_CLASS_UCF: 2702206089Sfabient ev = ucf_event_table; 2703206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2704206089Sfabient break; 2705206089Sfabient case PMC_CLASS_UCP: 2706206089Sfabient /* 2707206089Sfabient * Return the most appropriate set of event name 2708206089Sfabient * spellings for the current CPU. 2709206089Sfabient */ 2710206089Sfabient switch (cpu_info.pm_cputype) { 2711206089Sfabient default: 2712206089Sfabient case PMC_CPU_INTEL_COREI7: 2713206089Sfabient ev = corei7uc_event_table; 2714206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2715206089Sfabient break; 2716232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2717232366Sdavide ev = sandybridgeuc_event_table; 2718232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2719232366Sdavide break; 2720206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2721206089Sfabient ev = westmereuc_event_table; 2722206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2723206089Sfabient break; 2724206089Sfabient } 2725206089Sfabient break; 2726147191Sjkoshy case PMC_CLASS_TSC: 2727183725Sjkoshy ev = tsc_event_table; 2728183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2729145256Sjkoshy break; 2730147191Sjkoshy case PMC_CLASS_K7: 2731183725Sjkoshy ev = k7_event_table; 2732183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2733145256Sjkoshy break; 2734147191Sjkoshy case PMC_CLASS_K8: 2735183725Sjkoshy ev = k8_event_table; 2736183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2737145256Sjkoshy break; 2738183725Sjkoshy case PMC_CLASS_P4: 2739183725Sjkoshy ev = p4_event_table; 2740183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2741183725Sjkoshy break; 2742147191Sjkoshy case PMC_CLASS_P5: 2743183725Sjkoshy ev = p5_event_table; 2744183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2745145256Sjkoshy break; 2746147191Sjkoshy case PMC_CLASS_P6: 2747183725Sjkoshy ev = p6_event_table; 2748183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2749145256Sjkoshy break; 2750200928Srpaulo case PMC_CLASS_XSCALE: 2751200928Srpaulo ev = xscale_event_table; 2752200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2753200928Srpaulo break; 2754204635Sgnn case PMC_CLASS_MIPS24K: 2755204635Sgnn ev = mips24k_event_table; 2756204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2757204635Sgnn break; 2758233335Sgonzo case PMC_CLASS_OCTEON: 2759233335Sgonzo ev = octeon_event_table; 2760233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 2761233335Sgonzo break; 2762228869Sjhibbits case PMC_CLASS_PPC7450: 2763228869Sjhibbits ev = ppc7450_event_table; 2764228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2765228869Sjhibbits break; 2766233628Sfabient case PMC_CLASS_SOFT: 2767233628Sfabient ev = soft_event_table; 2768233628Sfabient count = soft_event_info.pm_nevent; 2769233628Sfabient break; 2770145256Sjkoshy default: 2771147191Sjkoshy errno = EINVAL; 2772174406Sjkoshy return (-1); 2773145256Sjkoshy } 2774145256Sjkoshy 2775147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2776174406Sjkoshy return (-1); 2777145256Sjkoshy 2778147191Sjkoshy *eventnames = names; 2779147191Sjkoshy *nevents = count; 2780145256Sjkoshy 2781147191Sjkoshy for (;count--; ev++, names++) 2782147191Sjkoshy *names = ev->pm_ev_name; 2783233628Sfabient 2784174406Sjkoshy return (0); 2785147191Sjkoshy} 2786145256Sjkoshy 2787147191Sjkoshyint 2788147191Sjkoshypmc_flush_logfile(void) 2789147191Sjkoshy{ 2790174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2791147191Sjkoshy} 2792145256Sjkoshy 2793147191Sjkoshyint 2794226514Sfabientpmc_close_logfile(void) 2795226514Sfabient{ 2796226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2797226514Sfabient} 2798226514Sfabient 2799226514Sfabientint 2800147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2801147191Sjkoshy{ 2802147191Sjkoshy struct pmc_op_getdriverstats gms; 2803145256Sjkoshy 2804147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2805174406Sjkoshy return (-1); 2806145256Sjkoshy 2807147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2808147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2809147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2810147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2811147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2812147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2813147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2814147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2815147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2816174406Sjkoshy return (0); 2817147191Sjkoshy} 2818145256Sjkoshy 2819147191Sjkoshyint 2820147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2821147191Sjkoshy{ 2822147191Sjkoshy struct pmc_op_getmsr gm; 2823147191Sjkoshy 2824147191Sjkoshy gm.pm_pmcid = pmc; 2825147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2826174406Sjkoshy return (-1); 2827147191Sjkoshy *msr = gm.pm_msr; 2828174406Sjkoshy return (0); 2829145256Sjkoshy} 2830145256Sjkoshy 2831145256Sjkoshyint 2832145256Sjkoshypmc_init(void) 2833145256Sjkoshy{ 2834145256Sjkoshy int error, pmc_mod_id; 2835147219Sjkoshy unsigned int n; 2836145256Sjkoshy uint32_t abi_version; 2837145256Sjkoshy struct module_stat pmc_modstat; 2838147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2839198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2840198433Sjkoshy int cpu_has_iaf_counters; 2841198433Sjkoshy unsigned int t; 2842198433Sjkoshy#endif 2843145256Sjkoshy 2844145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2845174406Sjkoshy return (0); 2846145256Sjkoshy 2847145256Sjkoshy /* retrieve the system call number from the KLD */ 2848145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2849174406Sjkoshy return (-1); 2850145256Sjkoshy 2851145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2852145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2853174406Sjkoshy return (-1); 2854145256Sjkoshy 2855145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2856145256Sjkoshy 2857147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2858147191Sjkoshy abi_version = PMC_VERSION; 2859145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2860145256Sjkoshy return (pmc_syscall = -1); 2861145256Sjkoshy 2862147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2863147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2864145256Sjkoshy errno = EPROGMISMATCH; 2865145256Sjkoshy return (pmc_syscall = -1); 2866145256Sjkoshy } 2867145256Sjkoshy 2868147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2869145256Sjkoshy return (pmc_syscall = -1); 2870145256Sjkoshy 2871147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2872147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2873147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2874147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2875147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2876147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2877147219Sjkoshy 2878185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2879185363Sjkoshy sizeof(struct pmc_class_descr *)); 2880185363Sjkoshy 2881185363Sjkoshy if (pmc_class_table == NULL) 2882185363Sjkoshy return (-1); 2883185363Sjkoshy 2884198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2885198433Sjkoshy pmc_class_table[n] = NULL; 2886185363Sjkoshy 2887185363Sjkoshy /* 2888233628Sfabient * Get soft events list. 2889233628Sfabient */ 2890233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 2891233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 2892233628Sfabient return (pmc_syscall = -1); 2893233628Sfabient 2894233628Sfabient /* Map soft events to static list. */ 2895233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 2896233628Sfabient soft_event_table[n].pm_ev_name = 2897233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 2898233628Sfabient soft_event_table[n].pm_ev_code = 2899233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 2900233628Sfabient } 2901233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 2902233628Sfabient soft_event_info.pm_nevent; 2903233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 2904233628Sfabient soft_event_table; 2905233628Sfabient 2906233628Sfabient /* 2907185363Sjkoshy * Fill in the class table. 2908185363Sjkoshy */ 2909185363Sjkoshy n = 0; 2910233628Sfabient 2911233628Sfabient /* Fill soft events information. */ 2912233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 2913185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 2914233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 2915233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 2916198433Sjkoshy 2917198433Sjkoshy /* 2918198433Sjkoshy * Check if this CPU has fixed function counters. 2919198433Sjkoshy */ 2920198433Sjkoshy cpu_has_iaf_counters = 0; 2921198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 2922212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 2923212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 2924198433Sjkoshy cpu_has_iaf_counters = 1; 2925185363Sjkoshy#endif 2926185363Sjkoshy 2927183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 2928183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 2929183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 2930183725Sjkoshy pmc_mdep_class_list_size = \ 2931183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 2932183725Sjkoshy } while (0) 2933183725Sjkoshy 2934198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 2935198433Sjkoshy PMC_MDEP_INIT(C); \ 2936212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 2937212224Sfabient if (!cpu_has_iaf_counters) \ 2938198433Sjkoshy pmc_mdep_event_aliases = \ 2939198433Sjkoshy C##_aliases_without_iaf; \ 2940198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 2941198433Sjkoshy } while (0) 2942198433Sjkoshy 2943183725Sjkoshy /* Configure the event name parser. */ 2944145256Sjkoshy switch (cpu_info.pm_cputype) { 2945145340Smarcel#if defined(__i386__) 2946145256Sjkoshy case PMC_CPU_AMD_K7: 2947183725Sjkoshy PMC_MDEP_INIT(k7); 2948185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 2949145256Sjkoshy break; 2950145256Sjkoshy case PMC_CPU_INTEL_P5: 2951183725Sjkoshy PMC_MDEP_INIT(p5); 2952185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 2953145256Sjkoshy break; 2954145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 2955145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 2956145256Sjkoshy case PMC_CPU_INTEL_PIII: 2957145256Sjkoshy case PMC_CPU_INTEL_PM: 2958183725Sjkoshy PMC_MDEP_INIT(p6); 2959185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 2960145256Sjkoshy break; 2961147759Sjkoshy#endif 2962147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 2963183725Sjkoshy case PMC_CPU_AMD_K8: 2964183725Sjkoshy PMC_MDEP_INIT(k8); 2965185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 2966183725Sjkoshy break; 2967185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2968198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 2969185363Sjkoshy break; 2970185363Sjkoshy case PMC_CPU_INTEL_CORE: 2971185363Sjkoshy PMC_MDEP_INIT(core); 2972202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 2973185363Sjkoshy break; 2974185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2975185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2976198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 2977185363Sjkoshy break; 2978187761Sjeff case PMC_CPU_INTEL_COREI7: 2979206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2980206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 2981198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 2982187761Sjeff break; 2983240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2984240164Sfabient PMC_MDEP_INIT_INTEL_V2(ivybridge); 2985240164Sfabient break; 2986232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2987232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 2988232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 2989232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 2990232366Sdavide break; 2991241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2992241738Ssbruno PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); 2993241738Ssbruno break; 2994206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2995206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2996206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 2997206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 2998206089Sfabient break; 2999145256Sjkoshy case PMC_CPU_INTEL_PIV: 3000183725Sjkoshy PMC_MDEP_INIT(p4); 3001185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 3002145256Sjkoshy break; 3003145256Sjkoshy#endif 3004233628Sfabient case PMC_CPU_GENERIC: 3005233628Sfabient PMC_MDEP_INIT(generic); 3006233628Sfabient break; 3007200928Srpaulo#if defined(__XSCALE__) 3008200928Srpaulo case PMC_CPU_INTEL_XSCALE: 3009200928Srpaulo PMC_MDEP_INIT(xscale); 3010200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 3011200928Srpaulo break; 3012200928Srpaulo#endif 3013204635Sgnn#if defined(__mips__) 3014204635Sgnn case PMC_CPU_MIPS_24K: 3015204635Sgnn PMC_MDEP_INIT(mips24k); 3016204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 3017204635Sgnn break; 3018233335Sgonzo case PMC_CPU_MIPS_OCTEON: 3019233335Sgonzo PMC_MDEP_INIT(octeon); 3020233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 3021233335Sgonzo break; 3022204635Sgnn#endif /* __mips__ */ 3023228869Sjhibbits#if defined(__powerpc__) 3024228869Sjhibbits case PMC_CPU_PPC_7450: 3025228869Sjhibbits PMC_MDEP_INIT(ppc7450); 3026228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 3027228869Sjhibbits break; 3028228869Sjhibbits#endif 3029145256Sjkoshy default: 3030145256Sjkoshy /* 3031145256Sjkoshy * Some kind of CPU this version of the library knows nothing 3032145256Sjkoshy * about. This shouldn't happen since the abi version check 3033145256Sjkoshy * should have caught this. 3034145256Sjkoshy */ 3035145256Sjkoshy errno = ENXIO; 3036145256Sjkoshy return (pmc_syscall = -1); 3037145256Sjkoshy } 3038145256Sjkoshy 3039174406Sjkoshy return (0); 3040145256Sjkoshy} 3041145256Sjkoshy 3042147191Sjkoshyconst char * 3043147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 3044145256Sjkoshy{ 3045147191Sjkoshy int i; 3046145256Sjkoshy 3047147191Sjkoshy /* 3048147191Sjkoshy * 'cap' should have a single bit set and should be in 3049147191Sjkoshy * range. 3050147191Sjkoshy */ 3051147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 3052147191Sjkoshy cap > PMC_CAP_LAST) { 3053145256Sjkoshy errno = EINVAL; 3054174406Sjkoshy return (NULL); 3055145256Sjkoshy } 3056145256Sjkoshy 3057147191Sjkoshy i = ffs(cap); 3058174406Sjkoshy return (pmc_capability_names[i - 1]); 3059147191Sjkoshy} 3060145256Sjkoshy 3061147191Sjkoshyconst char * 3062147191Sjkoshypmc_name_of_class(enum pmc_class pc) 3063147191Sjkoshy{ 3064147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 3065147191Sjkoshy pc <= PMC_CLASS_LAST) 3066174406Sjkoshy return (pmc_class_names[pc]); 3067145256Sjkoshy 3068147191Sjkoshy errno = EINVAL; 3069174406Sjkoshy return (NULL); 3070147191Sjkoshy} 3071145256Sjkoshy 3072147191Sjkoshyconst char * 3073147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3074147191Sjkoshy{ 3075183725Sjkoshy size_t n; 3076183725Sjkoshy 3077183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3078183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3079183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3080183725Sjkoshy 3081147191Sjkoshy errno = EINVAL; 3082174406Sjkoshy return (NULL); 3083147191Sjkoshy} 3084145256Sjkoshy 3085147191Sjkoshyconst char * 3086147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3087147191Sjkoshy{ 3088147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3089147191Sjkoshy pd <= PMC_DISP_LAST) 3090174406Sjkoshy return (pmc_disposition_names[pd]); 3091145256Sjkoshy 3092147191Sjkoshy errno = EINVAL; 3093174406Sjkoshy return (NULL); 3094147191Sjkoshy} 3095145256Sjkoshy 3096147191Sjkoshyconst char * 3097185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3098147191Sjkoshy{ 3099183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3100145256Sjkoshy 3101183725Sjkoshy ev = evfence = NULL; 3102185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3103185363Sjkoshy ev = iaf_event_table; 3104185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3105185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3106185363Sjkoshy switch (cpu) { 3107185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3108185363Sjkoshy ev = atom_event_table; 3109185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3110185363Sjkoshy break; 3111185363Sjkoshy case PMC_CPU_INTEL_CORE: 3112185363Sjkoshy ev = core_event_table; 3113185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3114185363Sjkoshy break; 3115185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3116185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3117185363Sjkoshy ev = core2_event_table; 3118185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3119185363Sjkoshy break; 3120187761Sjeff case PMC_CPU_INTEL_COREI7: 3121187761Sjeff ev = corei7_event_table; 3122187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3123187761Sjeff break; 3124240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3125240164Sfabient ev = ivybridge_event_table; 3126240164Sfabient evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); 3127240164Sfabient break; 3128232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3129232366Sdavide ev = sandybridge_event_table; 3130232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3131232366Sdavide break; 3132241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3133241738Ssbruno ev = sandybridge_xeon_event_table; 3134241738Ssbruno evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 3135241738Ssbruno break; 3136206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3137206089Sfabient ev = westmere_event_table; 3138206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3139206089Sfabient break; 3140185363Sjkoshy default: /* Unknown CPU type. */ 3141185363Sjkoshy break; 3142185363Sjkoshy } 3143206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3144206089Sfabient ev = ucf_event_table; 3145206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3146206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3147206089Sfabient switch (cpu) { 3148206089Sfabient case PMC_CPU_INTEL_COREI7: 3149206089Sfabient ev = corei7uc_event_table; 3150206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3151206089Sfabient break; 3152232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3153232366Sdavide ev = sandybridgeuc_event_table; 3154232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3155232366Sdavide break; 3156206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3157206089Sfabient ev = westmereuc_event_table; 3158206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3159206089Sfabient break; 3160206089Sfabient default: /* Unknown CPU type. */ 3161206089Sfabient break; 3162206089Sfabient } 3163206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3164183725Sjkoshy ev = k7_event_table; 3165183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3166183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3167183725Sjkoshy ev = k8_event_table; 3168183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3169183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3170183725Sjkoshy ev = p4_event_table; 3171183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3172183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3173183725Sjkoshy ev = p5_event_table; 3174183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3175183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3176183725Sjkoshy ev = p6_event_table; 3177183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3178200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3179200928Srpaulo ev = xscale_event_table; 3180200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3181204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3182204635Sgnn ev = mips24k_event_table; 3183233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3184233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3185233335Sgonzo ev = octeon_event_table; 3186233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3187228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3188228869Sjhibbits ev = ppc7450_event_table; 3189233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3190183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3191183725Sjkoshy ev = tsc_event_table; 3192183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3193233628Sfabient } else if (pe >= PMC_EV_SOFT_FIRST && pe <= PMC_EV_SOFT_LAST) { 3194233628Sfabient ev = soft_event_table; 3195233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3196183725Sjkoshy } 3197183725Sjkoshy 3198183725Sjkoshy for (; ev != evfence; ev++) 3199183725Sjkoshy if (pe == ev->pm_ev_code) 3200183725Sjkoshy return (ev->pm_ev_name); 3201183725Sjkoshy 3202185363Sjkoshy return (NULL); 3203185363Sjkoshy} 3204185363Sjkoshy 3205185363Sjkoshyconst char * 3206185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3207185363Sjkoshy{ 3208185363Sjkoshy const char *n; 3209185363Sjkoshy 3210185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3211185363Sjkoshy return (n); 3212185363Sjkoshy 3213147191Sjkoshy errno = EINVAL; 3214174406Sjkoshy return (NULL); 3215147191Sjkoshy} 3216145256Sjkoshy 3217147191Sjkoshyconst char * 3218147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3219147191Sjkoshy{ 3220147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3221147191Sjkoshy pm <= PMC_MODE_LAST) 3222174406Sjkoshy return (pmc_mode_names[pm]); 3223145256Sjkoshy 3224147191Sjkoshy errno = EINVAL; 3225174406Sjkoshy return (NULL); 3226147191Sjkoshy} 3227145256Sjkoshy 3228147191Sjkoshyconst char * 3229147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3230147191Sjkoshy{ 3231147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3232147191Sjkoshy ps <= PMC_STATE_LAST) 3233174406Sjkoshy return (pmc_state_names[ps]); 3234145256Sjkoshy 3235147191Sjkoshy errno = EINVAL; 3236174406Sjkoshy return (NULL); 3237145256Sjkoshy} 3238145256Sjkoshy 3239145256Sjkoshyint 3240147191Sjkoshypmc_ncpu(void) 3241145256Sjkoshy{ 3242147191Sjkoshy if (pmc_syscall == -1) { 3243147191Sjkoshy errno = ENXIO; 3244174406Sjkoshy return (-1); 3245147191Sjkoshy } 3246145256Sjkoshy 3247174406Sjkoshy return (cpu_info.pm_ncpu); 3248145256Sjkoshy} 3249145256Sjkoshy 3250145256Sjkoshyint 3251147191Sjkoshypmc_npmc(int cpu) 3252145256Sjkoshy{ 3253147191Sjkoshy if (pmc_syscall == -1) { 3254147191Sjkoshy errno = ENXIO; 3255174406Sjkoshy return (-1); 3256147191Sjkoshy } 3257145256Sjkoshy 3258147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3259147191Sjkoshy errno = EINVAL; 3260174406Sjkoshy return (-1); 3261147191Sjkoshy } 3262145256Sjkoshy 3263174406Sjkoshy return (cpu_info.pm_npmc); 3264145256Sjkoshy} 3265145256Sjkoshy 3266145256Sjkoshyint 3267147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3268145256Sjkoshy{ 3269147191Sjkoshy int nbytes, npmc; 3270147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3271145256Sjkoshy 3272147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3273174406Sjkoshy return (-1); 3274145256Sjkoshy 3275147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3276147191Sjkoshy npmc * sizeof(struct pmc_info); 3277145256Sjkoshy 3278147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3279174406Sjkoshy return (-1); 3280145256Sjkoshy 3281147191Sjkoshy pmci->pm_cpu = cpu; 3282145256Sjkoshy 3283147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3284147191Sjkoshy free(pmci); 3285174406Sjkoshy return (-1); 3286147191Sjkoshy } 3287145256Sjkoshy 3288147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3289147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3290174406Sjkoshy return (0); 3291145256Sjkoshy} 3292145256Sjkoshy 3293145256Sjkoshyint 3294145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3295145256Sjkoshy{ 3296145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3297145256Sjkoshy 3298145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3299145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3300145256Sjkoshy pmc_read_op.pm_value = -1; 3301145256Sjkoshy 3302145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3303174406Sjkoshy return (-1); 3304145256Sjkoshy 3305145256Sjkoshy *value = pmc_read_op.pm_value; 3306174406Sjkoshy return (0); 3307145256Sjkoshy} 3308145256Sjkoshy 3309145256Sjkoshyint 3310147191Sjkoshypmc_release(pmc_id_t pmc) 3311145256Sjkoshy{ 3312147191Sjkoshy struct pmc_op_simple pmc_release_args; 3313145256Sjkoshy 3314147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3315174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3316145256Sjkoshy} 3317145256Sjkoshy 3318145256Sjkoshyint 3319145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3320145256Sjkoshy{ 3321145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3322145256Sjkoshy 3323145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3324145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3325145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3326145256Sjkoshy 3327145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3328174406Sjkoshy return (-1); 3329145256Sjkoshy 3330145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3331174406Sjkoshy return (0); 3332145256Sjkoshy} 3333145256Sjkoshy 3334145256Sjkoshyint 3335145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3336145256Sjkoshy{ 3337145256Sjkoshy struct pmc_op_pmcsetcount sc; 3338145256Sjkoshy 3339145256Sjkoshy sc.pm_pmcid = pmc; 3340145256Sjkoshy sc.pm_count = value; 3341145256Sjkoshy 3342145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3343174406Sjkoshy return (-1); 3344174406Sjkoshy return (0); 3345145256Sjkoshy} 3346145256Sjkoshy 3347145256Sjkoshyint 3348147191Sjkoshypmc_start(pmc_id_t pmc) 3349145256Sjkoshy{ 3350147191Sjkoshy struct pmc_op_simple pmc_start_args; 3351145256Sjkoshy 3352147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3353174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3354145256Sjkoshy} 3355145256Sjkoshy 3356145256Sjkoshyint 3357147191Sjkoshypmc_stop(pmc_id_t pmc) 3358145256Sjkoshy{ 3359147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3360145256Sjkoshy 3361147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3362174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3363145256Sjkoshy} 3364145256Sjkoshy 3365145256Sjkoshyint 3366145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3367145774Sjkoshy{ 3368145774Sjkoshy unsigned int i; 3369145774Sjkoshy enum pmc_class cl; 3370145774Sjkoshy 3371145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3372145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3373145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3374145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3375174406Sjkoshy return (0); 3376145774Sjkoshy } 3377177107Sjkoshy errno = EINVAL; 3378177107Sjkoshy return (-1); 3379145774Sjkoshy} 3380145774Sjkoshy 3381145774Sjkoshyint 3382147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3383145774Sjkoshy{ 3384147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3385145774Sjkoshy 3386147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3387147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3388147191Sjkoshy pmc_write_op.pm_value = value; 3389174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3390145256Sjkoshy} 3391145256Sjkoshy 3392145256Sjkoshyint 3393147191Sjkoshypmc_writelog(uint32_t userdata) 3394145256Sjkoshy{ 3395147191Sjkoshy struct pmc_op_writelog wl; 3396145256Sjkoshy 3397147191Sjkoshy wl.pm_userdata = userdata; 3398174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3399145256Sjkoshy} 3400