libpmc.c revision 246166
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 246166 2013-01-31 22:09:53Z 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 191246166Ssbrunostatic const struct pmc_event_descr ivybridge_xeon_event_table[] = 192246166Ssbruno{ 193246166Ssbruno __PMC_EV_ALIAS_IVYBRIDGE_XEON() 194246166Ssbruno}; 195246166Ssbruno 196232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 197232366Sdavide{ 198232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 199232366Sdavide}; 200232366Sdavide 201241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] = 202241738Ssbruno{ 203241738Ssbruno __PMC_EV_ALIAS_SANDYBRIDGE_XEON() 204241738Ssbruno}; 205241738Ssbruno 206206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 207206089Sfabient{ 208206089Sfabient __PMC_EV_ALIAS_WESTMERE() 209206089Sfabient}; 210206089Sfabient 211206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 212206089Sfabient{ 213206089Sfabient __PMC_EV_ALIAS_COREI7UC() 214206089Sfabient}; 215206089Sfabient 216232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 217232366Sdavide{ 218232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 219232366Sdavide}; 220232366Sdavide 221206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 222206089Sfabient{ 223206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 224206089Sfabient}; 225206089Sfabient 226185363Sjkoshy/* 227185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 228185363Sjkoshy * 229185363Sjkoshy * Map a CPU to the PMC classes it supports. 230185363Sjkoshy */ 231185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 232183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 233183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 234183725Sjkoshy } 235183725Sjkoshy 236233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 237233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 238233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 239233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 240240164SfabientPMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 241246166SsbrunoPMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 242233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 243241738SsbrunoPMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 244233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 245233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); 246233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); 247233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); 248233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); 249233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); 250233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); 251233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 252233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 253233628SfabientPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450); 254233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 255183725Sjkoshy 256183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 257145256Sjkoshy{ 258183725Sjkoshy __PMC_EV_TSC() 259145256Sjkoshy}; 260145256Sjkoshy 261183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 262185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 263185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 264185363Sjkoshy { \ 265185363Sjkoshy .pm_evc_name = #CLASS "-", \ 266185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 267185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 268185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 269183725Sjkoshy .pm_evc_event_table_size = \ 270185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 271185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 272183725Sjkoshy } 273183725Sjkoshy 274185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 275185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 276185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 277185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 278185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 279187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 280240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); 281246166SsbrunoPMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap); 282232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 283241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); 284206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 285206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 286206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 287232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 288206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 289185363Sjkoshy#endif 290183725Sjkoshy#if defined(__i386__) 291185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 292183725Sjkoshy#endif 293183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 294185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 295185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 296183725Sjkoshy#endif 297183725Sjkoshy#if defined(__i386__) 298185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 299185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 300183725Sjkoshy#endif 301183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 302185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 303183725Sjkoshy#endif 304200928Srpaulo#if defined(__XSCALE__) 305200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 306200928Srpaulo#endif 307204635Sgnn#if defined(__mips__) 308233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 309233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 310204635Sgnn#endif /* __mips__ */ 311228869Sjhibbits#if defined(__powerpc__) 312228869SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450); 313228869Sjhibbits#endif 314228869Sjhibbits 315233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 316233628Sfabient{ 317233628Sfabient .pm_evc_name = "SOFT-", 318233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 319233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 320233628Sfabient .pm_evc_event_table = NULL, 321233628Sfabient .pm_evc_event_table_size = 0, 322233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 323233628Sfabient}; 324233628Sfabient 325183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 326183725Sjkoshy 327185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 328185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 329185363Sjkoshy 330183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 331183725Sjkoshystatic size_t pmc_mdep_class_list_size; 332183725Sjkoshy 333145256Sjkoshy/* 334145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 335145256Sjkoshy * strings. 336145256Sjkoshy */ 337145256Sjkoshy 338145256Sjkoshystatic const char * pmc_capability_names[] = { 339145256Sjkoshy#undef __PMC_CAP 340145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 341145256Sjkoshy __PMC_CAPS() 342145256Sjkoshy}; 343145256Sjkoshy 344145256Sjkoshystatic const char * pmc_class_names[] = { 345145256Sjkoshy#undef __PMC_CLASS 346145256Sjkoshy#define __PMC_CLASS(C) #C , 347145256Sjkoshy __PMC_CLASSES() 348145256Sjkoshy}; 349145256Sjkoshy 350183725Sjkoshystruct pmc_cputype_map { 351228557Sdim enum pmc_cputype pm_cputype; 352183725Sjkoshy const char *pm_name; 353183725Sjkoshy}; 354183725Sjkoshy 355183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 356145256Sjkoshy#undef __PMC_CPU 357183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 358145256Sjkoshy __PMC_CPUS() 359145256Sjkoshy}; 360145256Sjkoshy 361145256Sjkoshystatic const char * pmc_disposition_names[] = { 362145256Sjkoshy#undef __PMC_DISP 363145256Sjkoshy#define __PMC_DISP(D) #D , 364145256Sjkoshy __PMC_DISPOSITIONS() 365145256Sjkoshy}; 366145256Sjkoshy 367145256Sjkoshystatic const char * pmc_mode_names[] = { 368145256Sjkoshy#undef __PMC_MODE 369145256Sjkoshy#define __PMC_MODE(M,N) #M , 370145256Sjkoshy __PMC_MODES() 371145256Sjkoshy}; 372145256Sjkoshy 373145256Sjkoshystatic const char * pmc_state_names[] = { 374145256Sjkoshy#undef __PMC_STATE 375145256Sjkoshy#define __PMC_STATE(S) #S , 376145256Sjkoshy __PMC_STATES() 377145256Sjkoshy}; 378145256Sjkoshy 379233628Sfabient/* 380233628Sfabient * Filled in by pmc_init(). 381233628Sfabient */ 382233628Sfabientstatic int pmc_syscall = -1; 383233628Sfabientstatic struct pmc_cpuinfo cpu_info; 384233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 385145256Sjkoshy 386145256Sjkoshy/* Event masks for events */ 387145256Sjkoshystruct pmc_masks { 388145256Sjkoshy const char *pm_name; 389240164Sfabient const uint64_t pm_value; 390145256Sjkoshy}; 391145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 392206089Sfabient#define NULLMASK { .pm_name = NULL } 393145256Sjkoshy 394147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 395145256Sjkoshystatic int 396240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) 397145256Sjkoshy{ 398145256Sjkoshy const struct pmc_masks *pm; 399145256Sjkoshy char *q, *r; 400145256Sjkoshy int c; 401145256Sjkoshy 402145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 403174406Sjkoshy return (-1); 404183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 405145256Sjkoshy if (*++q == '\0') /* no more data */ 406174406Sjkoshy return (-1); 407145256Sjkoshy c = 0; /* count of mask keywords seen */ 408145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 409183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 410183725Sjkoshy pm++) 411145256Sjkoshy ; 412145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 413174406Sjkoshy return (-1); 414145256Sjkoshy *evmask |= pm->pm_value; 415145256Sjkoshy c++; 416145256Sjkoshy } 417174406Sjkoshy return (c); 418145256Sjkoshy} 419145340Smarcel#endif 420145256Sjkoshy 421145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 422145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 423145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 424145256Sjkoshy 425145340Smarcel#if defined(__i386__) 426145256Sjkoshy 427145256Sjkoshy/* 428145256Sjkoshy * AMD K7 (Athlon) CPUs. 429145256Sjkoshy */ 430145256Sjkoshy 431145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 432145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 433145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 434145351Sjkoshy EV_ALIAS("cycles", "tsc"), 435183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 436145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 437145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 438145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 439145351Sjkoshy EV_ALIAS(NULL, NULL) 440145256Sjkoshy}; 441145256Sjkoshy 442145256Sjkoshy#define K7_KW_COUNT "count" 443145256Sjkoshy#define K7_KW_EDGE "edge" 444145256Sjkoshy#define K7_KW_INV "inv" 445145256Sjkoshy#define K7_KW_OS "os" 446145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 447145256Sjkoshy#define K7_KW_USR "usr" 448145256Sjkoshy 449145256Sjkoshystatic int 450145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 451145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 452145256Sjkoshy{ 453183107Sjkoshy char *e, *p, *q; 454183107Sjkoshy int c, has_unitmask; 455145256Sjkoshy uint32_t count, unitmask; 456145256Sjkoshy 457147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 458183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 459145256Sjkoshy 460145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 461145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 462145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 463145256Sjkoshy has_unitmask = 1; 464147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 465145256Sjkoshy } else 466145256Sjkoshy unitmask = has_unitmask = 0; 467145256Sjkoshy 468145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 469145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 470145256Sjkoshy q = strchr(p, '='); 471145256Sjkoshy if (*++q == '\0') /* skip '=' */ 472174406Sjkoshy return (-1); 473145256Sjkoshy 474145256Sjkoshy count = strtol(q, &e, 0); 475145256Sjkoshy if (e == q || *e != '\0') 476174406Sjkoshy return (-1); 477145256Sjkoshy 478145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 479147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 480147191Sjkoshy AMD_PMC_TO_COUNTER(count); 481145256Sjkoshy 482145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 483145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 484145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 485145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 486145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 487145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 488145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 489145256Sjkoshy if (has_unitmask == 0) 490174406Sjkoshy return (-1); 491145256Sjkoshy unitmask = 0; 492145256Sjkoshy q = strchr(p, '='); 493145256Sjkoshy if (*++q == '\0') /* skip '=' */ 494174406Sjkoshy return (-1); 495145256Sjkoshy 496145256Sjkoshy while ((c = tolower(*q++)) != 0) 497145256Sjkoshy if (c == 'm') 498147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 499145256Sjkoshy else if (c == 'o') 500147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 501145256Sjkoshy else if (c == 'e') 502147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 503145256Sjkoshy else if (c == 's') 504147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 505145256Sjkoshy else if (c == 'i') 506147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 507145256Sjkoshy else if (c == '+') 508145256Sjkoshy continue; 509145256Sjkoshy else 510174406Sjkoshy return (-1); 511145256Sjkoshy 512145256Sjkoshy if (unitmask == 0) 513174406Sjkoshy return (-1); 514145256Sjkoshy 515145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 516145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 517145256Sjkoshy } else 518174406Sjkoshy return (-1); 519145256Sjkoshy } 520145256Sjkoshy 521145256Sjkoshy if (has_unitmask) { 522145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 523147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 524147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 525145256Sjkoshy } 526145256Sjkoshy 527174406Sjkoshy return (0); 528145256Sjkoshy 529145256Sjkoshy} 530145256Sjkoshy 531147191Sjkoshy#endif 532147191Sjkoshy 533147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 534147191Sjkoshy 535145256Sjkoshy/* 536185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 537185363Sjkoshy */ 538185363Sjkoshy 539185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 540185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 541185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 542185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 543185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 544185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 545185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 546185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 547185363Sjkoshy EV_ALIAS(NULL, NULL) 548185363Sjkoshy}; 549185363Sjkoshy 550185363Sjkoshy/* 551185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 552185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 553198433Sjkoshy * 554198433Sjkoshy * We map aliases to events on the fixed-function counters if these 555198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 556198433Sjkoshy * counters. 557185363Sjkoshy */ 558185363Sjkoshy 559185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 560185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 561185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 562185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 563185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 564185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 565185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 566185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 567185363Sjkoshy EV_ALIAS(NULL, NULL) 568185363Sjkoshy}; 569185363Sjkoshy 570198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 571198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 572198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 573198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 574198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 575198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 576198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 577198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 578198433Sjkoshy EV_ALIAS(NULL, NULL) 579198433Sjkoshy}; 580198433Sjkoshy 581198433Sjkoshy#define atom_aliases core2_aliases 582198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 583198433Sjkoshy#define corei7_aliases core2_aliases 584198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 585240164Sfabient#define ivybridge_aliases core2_aliases 586240164Sfabient#define ivybridge_aliases_without_iaf core2_aliases_without_iaf 587246166Ssbruno#define ivybridge_xeon_aliases core2_aliases 588246166Ssbruno#define ivybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 589232366Sdavide#define sandybridge_aliases core2_aliases 590232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 591241738Ssbruno#define sandybridge_xeon_aliases core2_aliases 592241738Ssbruno#define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 593206089Sfabient#define westmere_aliases core2_aliases 594206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 595198433Sjkoshy 596185363Sjkoshy#define IAF_KW_OS "os" 597185363Sjkoshy#define IAF_KW_USR "usr" 598185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 599185363Sjkoshy 600185363Sjkoshy/* 601185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 602185363Sjkoshy */ 603185363Sjkoshystatic int 604185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 605185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 606185363Sjkoshy{ 607185363Sjkoshy char *p; 608185363Sjkoshy 609185363Sjkoshy (void) pe; 610185363Sjkoshy 611185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 612185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 613185363Sjkoshy 614185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 615185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 616185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 617185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 618185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 619185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 620185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 621185363Sjkoshy else 622185363Sjkoshy return (-1); 623185363Sjkoshy } 624185363Sjkoshy 625185363Sjkoshy return (0); 626185363Sjkoshy} 627185363Sjkoshy 628185363Sjkoshy/* 629185363Sjkoshy * Core/Core2 support. 630185363Sjkoshy */ 631185363Sjkoshy 632185363Sjkoshy#define IAP_KW_AGENT "agent" 633185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 634185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 635185363Sjkoshy#define IAP_KW_CMASK "cmask" 636185363Sjkoshy#define IAP_KW_CORE "core" 637185363Sjkoshy#define IAP_KW_EDGE "edge" 638185363Sjkoshy#define IAP_KW_INV "inv" 639185363Sjkoshy#define IAP_KW_OS "os" 640185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 641185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 642185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 643185363Sjkoshy#define IAP_KW_TRANSITION "trans" 644185363Sjkoshy#define IAP_KW_USR "usr" 645206089Sfabient#define IAP_KW_RSP "rsp" 646185363Sjkoshy 647185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 648185363Sjkoshy PMCMASK(all, (0x3 << 14)), 649185363Sjkoshy PMCMASK(this, (0x1 << 14)), 650185363Sjkoshy NULLMASK 651185363Sjkoshy}; 652185363Sjkoshy 653185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 654185363Sjkoshy PMCMASK(this, 0), 655185363Sjkoshy PMCMASK(any, (0x1 << 13)), 656185363Sjkoshy NULLMASK 657185363Sjkoshy}; 658185363Sjkoshy 659185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 660185363Sjkoshy PMCMASK(both, (0x3 << 12)), 661185363Sjkoshy PMCMASK(only, (0x1 << 12)), 662185363Sjkoshy PMCMASK(exclude, 0), 663185363Sjkoshy NULLMASK 664185363Sjkoshy}; 665185363Sjkoshy 666185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 667185363Sjkoshy PMCMASK(i, (1 << 8)), 668185363Sjkoshy PMCMASK(s, (1 << 9)), 669185363Sjkoshy PMCMASK(e, (1 << 10)), 670185363Sjkoshy PMCMASK(m, (1 << 11)), 671185363Sjkoshy NULLMASK 672185363Sjkoshy}; 673185363Sjkoshy 674185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 675185363Sjkoshy PMCMASK(clean, (1 << 8)), 676185363Sjkoshy PMCMASK(hit, (1 << 9)), 677185363Sjkoshy PMCMASK(hitm, (1 << 11)), 678185363Sjkoshy NULLMASK 679185363Sjkoshy}; 680185363Sjkoshy 681185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 682185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 683185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 684185363Sjkoshy NULLMASK 685185363Sjkoshy}; 686185363Sjkoshy 687185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 688185363Sjkoshy PMCMASK(any, 0x00), 689185363Sjkoshy PMCMASK(frequency, 0x10), 690185363Sjkoshy NULLMASK 691185363Sjkoshy}; 692185363Sjkoshy 693240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = { 694206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 695206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 696206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 697206089Sfabient PMCMASK(WB, (1 << 3)), 698206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 699206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 700206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 701206089Sfabient PMCMASK(OTHER, (1 << 7)), 702206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 703206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 704206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 705206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 706206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 707206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 708206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 709206089Sfabient NULLMASK 710206089Sfabient}; 711206089Sfabient 712241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { 713240164Sfabient PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 714240164Sfabient PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 715240164Sfabient PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 716240164Sfabient PMCMASK(REQ_WB, (1ULL << 3)), 717240164Sfabient PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 718240164Sfabient PMCMASK(REQ_PF_RFO, (1ULL << 5)), 719240164Sfabient PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 720240164Sfabient PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), 721240164Sfabient PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), 722240164Sfabient PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), 723240164Sfabient PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), 724240164Sfabient PMCMASK(REQ_STRM_ST, (1ULL << 11)), 725240164Sfabient PMCMASK(REQ_OTHER, (1ULL << 15)), 726240164Sfabient PMCMASK(RES_ANY, (1ULL << 16)), 727240164Sfabient PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 728240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 729240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 730240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 731240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 732240164Sfabient PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 733241974Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 734240164Sfabient PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 735240164Sfabient PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 736240164Sfabient PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 737240164Sfabient PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 738240164Sfabient PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 739240164Sfabient PMCMASK(RES_NON_DRAM, (1ULL << 37)), 740240164Sfabient NULLMASK 741240164Sfabient}; 742240164Sfabient 743185363Sjkoshystatic int 744185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 745185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 746185363Sjkoshy{ 747185363Sjkoshy char *e, *p, *q; 748240164Sfabient uint64_t cachestate, evmask, rsp; 749185363Sjkoshy int count, n; 750185363Sjkoshy 751185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 752185363Sjkoshy PMC_CAP_QUALIFIER); 753185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 754185363Sjkoshy 755206089Sfabient cachestate = evmask = rsp = 0; 756185363Sjkoshy 757185363Sjkoshy /* Parse additional modifiers if present */ 758185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 759185363Sjkoshy 760185363Sjkoshy n = 0; 761185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 762185363Sjkoshy q = strchr(p, '='); 763185363Sjkoshy if (*++q == '\0') /* skip '=' */ 764185363Sjkoshy return (-1); 765185363Sjkoshy count = strtol(q, &e, 0); 766185363Sjkoshy if (e == q || *e != '\0') 767185363Sjkoshy return (-1); 768185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 769185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 770185363Sjkoshy IAP_CMASK(count); 771185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 772185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 773185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 774185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 775185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 776185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 777185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 778185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 779185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 780185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 781193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 782185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 783185363Sjkoshy if (n != 1) 784185363Sjkoshy return (-1); 785193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 786185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 787185363Sjkoshy if (n != 1) 788185363Sjkoshy return (-1); 789193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 790185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 791185363Sjkoshy if (n != 1) 792185363Sjkoshy return (-1); 793193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 794185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 795185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 796193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 797185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 798185363Sjkoshy if (n != 1) 799185363Sjkoshy return (-1); 800185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 801185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 802206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 803193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 804185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 805185363Sjkoshy &evmask); 806193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 807185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 808185363Sjkoshy &evmask); 809185363Sjkoshy } else 810185363Sjkoshy return (-1); 811206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 812206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) { 813206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 814240164Sfabient n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); 815206089Sfabient } else 816206089Sfabient return (-1); 817240164Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || 818241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || 819246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE || 820246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) { 821240164Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 822241738Ssbruno n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); 823240164Sfabient } else 824240164Sfabient return (-1); 825185363Sjkoshy } else 826185363Sjkoshy return (-1); 827185363Sjkoshy 828185363Sjkoshy if (n < 0) /* Parsing failed. */ 829185363Sjkoshy return (-1); 830185363Sjkoshy } 831185363Sjkoshy 832185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 833185363Sjkoshy 834185363Sjkoshy /* 835185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 836185363Sjkoshy * specified by the user, use a sensible default. 837185363Sjkoshy */ 838185363Sjkoshy switch (pe) { 839185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 840185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 841185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 842185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 843185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 844185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 845185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 846185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 847185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 848185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 849185363Sjkoshy if (cachestate == 0) 850185363Sjkoshy cachestate = (0xF << 8); 851207482Srstone break; 852207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 853207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 854207482Srstone * Atom processor 855207482Srstone */ 856207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 857207482Srstone cachestate = (0xF << 8); 858207482Srstone break; 859185363Sjkoshy default: 860185363Sjkoshy break; 861185363Sjkoshy } 862185363Sjkoshy 863185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 864206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 865185363Sjkoshy 866185363Sjkoshy return (0); 867185363Sjkoshy} 868185363Sjkoshy 869185363Sjkoshy/* 870206089Sfabient * Intel Uncore. 871206089Sfabient */ 872206089Sfabient 873206089Sfabientstatic int 874206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 875206089Sfabient struct pmc_op_pmcallocate *pmc_config) 876206089Sfabient{ 877206089Sfabient (void) pe; 878206089Sfabient (void) ctrspec; 879206089Sfabient 880206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 881206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 882206089Sfabient 883206089Sfabient return (0); 884206089Sfabient} 885206089Sfabient 886206089Sfabient#define UCP_KW_CMASK "cmask" 887206089Sfabient#define UCP_KW_EDGE "edge" 888206089Sfabient#define UCP_KW_INV "inv" 889206089Sfabient 890206089Sfabientstatic int 891206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 892206089Sfabient struct pmc_op_pmcallocate *pmc_config) 893206089Sfabient{ 894206089Sfabient char *e, *p, *q; 895206089Sfabient int count, n; 896206089Sfabient 897206089Sfabient (void) pe; 898206089Sfabient 899206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 900206089Sfabient PMC_CAP_QUALIFIER); 901206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 902206089Sfabient 903206089Sfabient /* Parse additional modifiers if present */ 904206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 905206089Sfabient 906206089Sfabient n = 0; 907206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 908206089Sfabient q = strchr(p, '='); 909206089Sfabient if (*++q == '\0') /* skip '=' */ 910206089Sfabient return (-1); 911206089Sfabient count = strtol(q, &e, 0); 912206089Sfabient if (e == q || *e != '\0') 913206089Sfabient return (-1); 914206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 915206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 916206089Sfabient UCP_CMASK(count); 917206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 918206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 919206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 920206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 921206089Sfabient } else 922206089Sfabient return (-1); 923206089Sfabient 924206089Sfabient if (n < 0) /* Parsing failed. */ 925206089Sfabient return (-1); 926206089Sfabient } 927206089Sfabient 928206089Sfabient return (0); 929206089Sfabient} 930206089Sfabient 931206089Sfabient/* 932147191Sjkoshy * AMD K8 PMCs. 933147191Sjkoshy * 934147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 935147191Sjkoshy * events. 936147191Sjkoshy */ 937147191Sjkoshy 938147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 939147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 940147191Sjkoshy EV_ALIAS("branch-mispredicts", 941147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 942147191Sjkoshy EV_ALIAS("cycles", "tsc"), 943147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 944147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 945183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 946147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 947155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 948147191Sjkoshy EV_ALIAS(NULL, NULL) 949147191Sjkoshy}; 950147191Sjkoshy 951147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 952147191Sjkoshy 953147191Sjkoshy/* 954147191Sjkoshy * Parsing tables 955147191Sjkoshy */ 956147191Sjkoshy 957147191Sjkoshy/* fp dispatched fpu ops */ 958147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 959147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 960147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 961147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 962147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 963147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 964147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 965147191Sjkoshy NULLMASK 966147191Sjkoshy}; 967147191Sjkoshy 968147191Sjkoshy/* ls segment register loads */ 969147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 970147191Sjkoshy __K8MASK(es, 0), 971147191Sjkoshy __K8MASK(cs, 1), 972147191Sjkoshy __K8MASK(ss, 2), 973147191Sjkoshy __K8MASK(ds, 3), 974147191Sjkoshy __K8MASK(fs, 4), 975147191Sjkoshy __K8MASK(gs, 5), 976147191Sjkoshy __K8MASK(hs, 6), 977147191Sjkoshy NULLMASK 978147191Sjkoshy}; 979147191Sjkoshy 980147191Sjkoshy/* ls locked operation */ 981147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 982147191Sjkoshy __K8MASK(locked-instructions, 0), 983147191Sjkoshy __K8MASK(cycles-in-request, 1), 984147191Sjkoshy __K8MASK(cycles-to-complete, 2), 985147191Sjkoshy NULLMASK 986147191Sjkoshy}; 987147191Sjkoshy 988147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 989147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 990147191Sjkoshy __K8MASK(invalid, 0), 991147191Sjkoshy __K8MASK(shared, 1), 992147191Sjkoshy __K8MASK(exclusive, 2), 993147191Sjkoshy __K8MASK(owner, 3), 994147191Sjkoshy __K8MASK(modified, 4), 995147191Sjkoshy NULLMASK 996147191Sjkoshy}; 997147191Sjkoshy 998147191Sjkoshy/* dc one bit ecc error */ 999147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 1000147191Sjkoshy __K8MASK(scrubber, 0), 1001147191Sjkoshy __K8MASK(piggyback, 1), 1002147191Sjkoshy NULLMASK 1003147191Sjkoshy}; 1004147191Sjkoshy 1005147191Sjkoshy/* dc dispatched prefetch instructions */ 1006147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 1007147191Sjkoshy __K8MASK(load, 0), 1008147191Sjkoshy __K8MASK(store, 1), 1009147191Sjkoshy __K8MASK(nta, 2), 1010147191Sjkoshy NULLMASK 1011147191Sjkoshy}; 1012147191Sjkoshy 1013147191Sjkoshy/* dc dcache accesses by locks */ 1014147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1015147191Sjkoshy __K8MASK(accesses, 0), 1016147191Sjkoshy __K8MASK(misses, 1), 1017147191Sjkoshy NULLMASK 1018147191Sjkoshy}; 1019147191Sjkoshy 1020147191Sjkoshy/* bu internal l2 request */ 1021147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1022147191Sjkoshy __K8MASK(ic-fill, 0), 1023147191Sjkoshy __K8MASK(dc-fill, 1), 1024147191Sjkoshy __K8MASK(tlb-reload, 2), 1025147191Sjkoshy __K8MASK(tag-snoop, 3), 1026147191Sjkoshy __K8MASK(cancelled, 4), 1027147191Sjkoshy NULLMASK 1028147191Sjkoshy}; 1029147191Sjkoshy 1030147191Sjkoshy/* bu fill request l2 miss */ 1031147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1032147191Sjkoshy __K8MASK(ic-fill, 0), 1033147191Sjkoshy __K8MASK(dc-fill, 1), 1034147191Sjkoshy __K8MASK(tlb-reload, 2), 1035147191Sjkoshy NULLMASK 1036147191Sjkoshy}; 1037147191Sjkoshy 1038147191Sjkoshy/* bu fill into l2 */ 1039147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1040147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 1041147191Sjkoshy __K8MASK(victim-from-l2, 1), 1042147191Sjkoshy NULLMASK 1043147191Sjkoshy}; 1044147191Sjkoshy 1045147191Sjkoshy/* fr retired fpu instructions */ 1046147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1047147191Sjkoshy __K8MASK(x87, 0), 1048147191Sjkoshy __K8MASK(mmx-3dnow, 1), 1049147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 1050147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1051147191Sjkoshy NULLMASK 1052147191Sjkoshy}; 1053147191Sjkoshy 1054147191Sjkoshy/* fr retired fastpath double op instructions */ 1055147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1056147191Sjkoshy __K8MASK(low-op-pos-0, 0), 1057147191Sjkoshy __K8MASK(low-op-pos-1, 1), 1058147191Sjkoshy __K8MASK(low-op-pos-2, 2), 1059147191Sjkoshy NULLMASK 1060147191Sjkoshy}; 1061147191Sjkoshy 1062147191Sjkoshy/* fr fpu exceptions */ 1063147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1064147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1065147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1066147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1067147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1068147191Sjkoshy NULLMASK 1069147191Sjkoshy}; 1070147191Sjkoshy 1071147191Sjkoshy/* nb memory controller page access event */ 1072147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1073147191Sjkoshy __K8MASK(page-hit, 0), 1074147191Sjkoshy __K8MASK(page-miss, 1), 1075147191Sjkoshy __K8MASK(page-conflict, 2), 1076147191Sjkoshy NULLMASK 1077147191Sjkoshy}; 1078147191Sjkoshy 1079147191Sjkoshy/* nb memory controller turnaround */ 1080147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1081147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1082147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1083147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1084147191Sjkoshy NULLMASK 1085147191Sjkoshy}; 1086147191Sjkoshy 1087147191Sjkoshy/* nb memory controller bypass saturation */ 1088147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1089147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1090147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1091147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1092147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1093147191Sjkoshy NULLMASK 1094147191Sjkoshy}; 1095147191Sjkoshy 1096147191Sjkoshy/* nb sized commands */ 1097147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1098147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1099147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1100147191Sjkoshy __K8MASK(postwrszbyte, 2), 1101147191Sjkoshy __K8MASK(postwrszdword, 3), 1102147191Sjkoshy __K8MASK(rdszbyte, 4), 1103147191Sjkoshy __K8MASK(rdszdword, 5), 1104147191Sjkoshy __K8MASK(rdmodwr, 6), 1105147191Sjkoshy NULLMASK 1106147191Sjkoshy}; 1107147191Sjkoshy 1108147191Sjkoshy/* nb probe result */ 1109147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1110147191Sjkoshy __K8MASK(probe-miss, 0), 1111147191Sjkoshy __K8MASK(probe-hit, 1), 1112147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1113147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1114147191Sjkoshy NULLMASK 1115147191Sjkoshy}; 1116147191Sjkoshy 1117147191Sjkoshy/* nb hypertransport bus bandwidth */ 1118147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1119147191Sjkoshy __K8MASK(command, 0), 1120183107Sjkoshy __K8MASK(data, 1), 1121147191Sjkoshy __K8MASK(buffer-release, 2), 1122147191Sjkoshy __K8MASK(nop, 3), 1123147191Sjkoshy NULLMASK 1124147191Sjkoshy}; 1125147191Sjkoshy 1126147191Sjkoshy#undef __K8MASK 1127147191Sjkoshy 1128147191Sjkoshy#define K8_KW_COUNT "count" 1129147191Sjkoshy#define K8_KW_EDGE "edge" 1130147191Sjkoshy#define K8_KW_INV "inv" 1131147191Sjkoshy#define K8_KW_MASK "mask" 1132147191Sjkoshy#define K8_KW_OS "os" 1133147191Sjkoshy#define K8_KW_USR "usr" 1134147191Sjkoshy 1135147191Sjkoshystatic int 1136147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1137147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1138147191Sjkoshy{ 1139183107Sjkoshy char *e, *p, *q; 1140183107Sjkoshy int n; 1141240164Sfabient uint32_t count; 1142240164Sfabient uint64_t evmask; 1143147191Sjkoshy const struct pmc_masks *pm, *pmask; 1144147191Sjkoshy 1145183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1146147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1147147191Sjkoshy 1148147191Sjkoshy pmask = NULL; 1149147191Sjkoshy evmask = 0; 1150147191Sjkoshy 1151147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1152147191Sjkoshy 1153147191Sjkoshy /* setup parsing tables */ 1154147191Sjkoshy switch (pe) { 1155147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1156147191Sjkoshy __K8SETMASK(fdfo); 1157147191Sjkoshy break; 1158147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1159147191Sjkoshy __K8SETMASK(lsrl); 1160147191Sjkoshy break; 1161147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1162147191Sjkoshy __K8SETMASK(llo); 1163147191Sjkoshy break; 1164147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1165147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1166147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1167147191Sjkoshy __K8SETMASK(dc); 1168147191Sjkoshy break; 1169147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1170147191Sjkoshy __K8SETMASK(dobee); 1171147191Sjkoshy break; 1172147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1173147191Sjkoshy __K8SETMASK(ddpi); 1174147191Sjkoshy break; 1175147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1176147191Sjkoshy __K8SETMASK(dabl); 1177147191Sjkoshy break; 1178147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1179147191Sjkoshy __K8SETMASK(bilr); 1180147191Sjkoshy break; 1181147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1182147191Sjkoshy __K8SETMASK(bfrlm); 1183147191Sjkoshy break; 1184147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1185147191Sjkoshy __K8SETMASK(bfil); 1186147191Sjkoshy break; 1187147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1188147191Sjkoshy __K8SETMASK(frfi); 1189147191Sjkoshy break; 1190147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1191147191Sjkoshy __K8SETMASK(frfdoi); 1192147191Sjkoshy break; 1193147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1194147191Sjkoshy __K8SETMASK(ffe); 1195147191Sjkoshy break; 1196147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1197147191Sjkoshy __K8SETMASK(nmcpae); 1198147191Sjkoshy break; 1199147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1200147191Sjkoshy __K8SETMASK(nmct); 1201147191Sjkoshy break; 1202147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1203147191Sjkoshy __K8SETMASK(nmcbs); 1204147191Sjkoshy break; 1205147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1206147191Sjkoshy __K8SETMASK(nsc); 1207147191Sjkoshy break; 1208147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1209147191Sjkoshy __K8SETMASK(npr); 1210147191Sjkoshy break; 1211147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1212147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1213147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1214147191Sjkoshy __K8SETMASK(nhbb); 1215147191Sjkoshy break; 1216147191Sjkoshy 1217147191Sjkoshy default: 1218147191Sjkoshy break; /* no options defined */ 1219147191Sjkoshy } 1220147191Sjkoshy 1221147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1222147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1223147191Sjkoshy q = strchr(p, '='); 1224147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1225174406Sjkoshy return (-1); 1226147191Sjkoshy 1227147191Sjkoshy count = strtol(q, &e, 0); 1228147191Sjkoshy if (e == q || *e != '\0') 1229174406Sjkoshy return (-1); 1230147191Sjkoshy 1231147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1232147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1233147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1234147191Sjkoshy 1235147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1236147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1237147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1238147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1239147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1240147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1241174406Sjkoshy return (-1); 1242147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1243147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1244147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1245147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1246147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1247147191Sjkoshy } else 1248174406Sjkoshy return (-1); 1249147191Sjkoshy } 1250147191Sjkoshy 1251147191Sjkoshy /* other post processing */ 1252147191Sjkoshy switch (pe) { 1253147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1254147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1255147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1256147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1257147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1258147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1259147191Sjkoshy /* XXX only available in rev B and later */ 1260147191Sjkoshy break; 1261147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1262147191Sjkoshy /* XXX only available in rev C and later */ 1263147191Sjkoshy break; 1264147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1265147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1266147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1267174406Sjkoshy return (-1); 1268147191Sjkoshy if (evmask == 0) { 1269147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1270147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1271147191Sjkoshy } 1272147191Sjkoshy break; 1273147191Sjkoshy default: 1274147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1275147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1276147191Sjkoshy evmask |= pm->pm_value; 1277147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1278147191Sjkoshy } 1279147191Sjkoshy } 1280147191Sjkoshy 1281147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1282147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1283147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1284147191Sjkoshy 1285174406Sjkoshy return (0); 1286147191Sjkoshy} 1287147191Sjkoshy 1288147191Sjkoshy#endif 1289147191Sjkoshy 1290147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1291147191Sjkoshy 1292147191Sjkoshy/* 1293145256Sjkoshy * Intel P4 PMCs 1294145256Sjkoshy */ 1295145256Sjkoshy 1296145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1297145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1298145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1299145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1300145351Sjkoshy EV_ALIAS("instructions", 1301145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1302155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1303145256Sjkoshy EV_ALIAS(NULL, NULL) 1304145256Sjkoshy}; 1305145256Sjkoshy 1306145256Sjkoshy#define P4_KW_ACTIVE "active" 1307145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1308145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1309145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1310145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1311145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1312145256Sjkoshy#define P4_KW_CASCADE "cascade" 1313145256Sjkoshy#define P4_KW_EDGE "edge" 1314145256Sjkoshy#define P4_KW_INV "complement" 1315145256Sjkoshy#define P4_KW_OS "os" 1316145256Sjkoshy#define P4_KW_MASK "mask" 1317145256Sjkoshy#define P4_KW_PRECISE "precise" 1318145256Sjkoshy#define P4_KW_TAG "tag" 1319145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1320145256Sjkoshy#define P4_KW_USR "usr" 1321145256Sjkoshy 1322145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1323145256Sjkoshy 1324145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1325145256Sjkoshy __P4MASK(dd, 0), 1326145256Sjkoshy __P4MASK(db, 1), 1327145256Sjkoshy __P4MASK(di, 2), 1328145256Sjkoshy __P4MASK(bd, 3), 1329145256Sjkoshy __P4MASK(bb, 4), 1330145256Sjkoshy __P4MASK(bi, 5), 1331145256Sjkoshy __P4MASK(id, 6), 1332145256Sjkoshy __P4MASK(ib, 7), 1333145256Sjkoshy NULLMASK 1334145256Sjkoshy}; 1335145256Sjkoshy 1336145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1337145256Sjkoshy __P4MASK(tcmiss, 0), 1338145256Sjkoshy NULLMASK, 1339145256Sjkoshy}; 1340145256Sjkoshy 1341145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1342145256Sjkoshy __P4MASK(hit, 0), 1343145256Sjkoshy __P4MASK(miss, 1), 1344145256Sjkoshy __P4MASK(hit-uc, 2), 1345145256Sjkoshy NULLMASK 1346145256Sjkoshy}; 1347145256Sjkoshy 1348145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1349145256Sjkoshy __P4MASK(st-rb-full, 2), 1350145256Sjkoshy __P4MASK(64k-conf, 3), 1351145256Sjkoshy NULLMASK 1352145256Sjkoshy}; 1353145256Sjkoshy 1354145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1355145256Sjkoshy __P4MASK(lsc, 0), 1356145256Sjkoshy __P4MASK(ssc, 1), 1357145256Sjkoshy NULLMASK 1358145256Sjkoshy}; 1359145256Sjkoshy 1360145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1361145256Sjkoshy __P4MASK(split-ld, 1), 1362145256Sjkoshy NULLMASK 1363145256Sjkoshy}; 1364145256Sjkoshy 1365145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1366145256Sjkoshy __P4MASK(split-st, 1), 1367145256Sjkoshy NULLMASK 1368145256Sjkoshy}; 1369145256Sjkoshy 1370145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1371145256Sjkoshy __P4MASK(no-sta, 1), 1372145256Sjkoshy __P4MASK(no-std, 3), 1373145256Sjkoshy __P4MASK(partial-data, 4), 1374145256Sjkoshy __P4MASK(unalgn-addr, 5), 1375145256Sjkoshy NULLMASK 1376145256Sjkoshy}; 1377145256Sjkoshy 1378145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1379145256Sjkoshy __P4MASK(dtmiss, 0), 1380145256Sjkoshy __P4MASK(itmiss, 1), 1381145256Sjkoshy NULLMASK 1382145256Sjkoshy}; 1383145256Sjkoshy 1384145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1385145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1386145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1387145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1388145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1389145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1390145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1391145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1392145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1393145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1394145256Sjkoshy NULLMASK 1395145256Sjkoshy}; 1396145256Sjkoshy 1397145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1398145256Sjkoshy __P4MASK(all-read, 5), 1399145256Sjkoshy __P4MASK(all-write, 6), 1400145256Sjkoshy __P4MASK(mem-uc, 7), 1401145256Sjkoshy __P4MASK(mem-wc, 8), 1402145256Sjkoshy __P4MASK(mem-wt, 9), 1403145256Sjkoshy __P4MASK(mem-wp, 10), 1404145256Sjkoshy __P4MASK(mem-wb, 11), 1405145256Sjkoshy __P4MASK(own, 13), 1406145256Sjkoshy __P4MASK(other, 14), 1407145256Sjkoshy __P4MASK(prefetch, 15), 1408145256Sjkoshy NULLMASK 1409145256Sjkoshy}; 1410145256Sjkoshy 1411145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1412145256Sjkoshy __P4MASK(all-read, 5), 1413145256Sjkoshy __P4MASK(all-write, 6), 1414145256Sjkoshy __P4MASK(mem-uc, 7), 1415145256Sjkoshy __P4MASK(mem-wc, 8), 1416145256Sjkoshy __P4MASK(mem-wt, 9), 1417145256Sjkoshy __P4MASK(mem-wp, 10), 1418145256Sjkoshy __P4MASK(mem-wb, 11), 1419145256Sjkoshy __P4MASK(own, 13), 1420145256Sjkoshy __P4MASK(other, 14), 1421145256Sjkoshy __P4MASK(prefetch, 15), 1422145256Sjkoshy NULLMASK 1423145256Sjkoshy}; 1424145256Sjkoshy 1425145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1426145256Sjkoshy __P4MASK(drdy-drv, 0), 1427145256Sjkoshy __P4MASK(drdy-own, 1), 1428145256Sjkoshy __P4MASK(drdy-other, 2), 1429145256Sjkoshy __P4MASK(dbsy-drv, 3), 1430145256Sjkoshy __P4MASK(dbsy-own, 4), 1431145256Sjkoshy __P4MASK(dbsy-other, 5), 1432145256Sjkoshy NULLMASK 1433145256Sjkoshy}; 1434145256Sjkoshy 1435145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1436145256Sjkoshy __P4MASK(req-type0, 0), 1437145256Sjkoshy __P4MASK(req-type1, 1), 1438145256Sjkoshy __P4MASK(req-len0, 2), 1439145256Sjkoshy __P4MASK(req-len1, 3), 1440145256Sjkoshy __P4MASK(req-io-type, 5), 1441145256Sjkoshy __P4MASK(req-lock-type, 6), 1442145256Sjkoshy __P4MASK(req-cache-type, 7), 1443145256Sjkoshy __P4MASK(req-split-type, 8), 1444145256Sjkoshy __P4MASK(req-dem-type, 9), 1445145256Sjkoshy __P4MASK(req-ord-type, 10), 1446145256Sjkoshy __P4MASK(mem-type0, 11), 1447145256Sjkoshy __P4MASK(mem-type1, 12), 1448145256Sjkoshy __P4MASK(mem-type2, 13), 1449145256Sjkoshy NULLMASK 1450145256Sjkoshy}; 1451145256Sjkoshy 1452145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1453145256Sjkoshy __P4MASK(all, 15), 1454145256Sjkoshy NULLMASK 1455145256Sjkoshy}; 1456145256Sjkoshy 1457145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1458145256Sjkoshy __P4MASK(all, 15), 1459145256Sjkoshy NULLMASK 1460145256Sjkoshy}; 1461145256Sjkoshy 1462145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1463145256Sjkoshy __P4MASK(all, 15), 1464145256Sjkoshy NULLMASK 1465145256Sjkoshy}; 1466145256Sjkoshy 1467145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1468145256Sjkoshy __P4MASK(all, 15), 1469145256Sjkoshy NULLMASK 1470145256Sjkoshy}; 1471145256Sjkoshy 1472145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1473145256Sjkoshy __P4MASK(all, 15), 1474145256Sjkoshy NULLMASK 1475145256Sjkoshy}; 1476145256Sjkoshy 1477145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1478145256Sjkoshy __P4MASK(all, 15), 1479145256Sjkoshy NULLMASK 1480145256Sjkoshy}; 1481145256Sjkoshy 1482145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1483145256Sjkoshy __P4MASK(all, 15), 1484145256Sjkoshy NULLMASK 1485145256Sjkoshy}; 1486145256Sjkoshy 1487145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1488145256Sjkoshy __P4MASK(all, 15), 1489145256Sjkoshy NULLMASK 1490145256Sjkoshy}; 1491145256Sjkoshy 1492145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1493145256Sjkoshy __P4MASK(allp0, 3), 1494145256Sjkoshy __P4MASK(allp2, 4), 1495145256Sjkoshy NULLMASK 1496145256Sjkoshy}; 1497145256Sjkoshy 1498145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1499145256Sjkoshy __P4MASK(running, 0), 1500145256Sjkoshy NULLMASK 1501145256Sjkoshy}; 1502145256Sjkoshy 1503145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1504145256Sjkoshy __P4MASK(cisc, 0), 1505145256Sjkoshy NULLMASK 1506145256Sjkoshy}; 1507145256Sjkoshy 1508145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1509145256Sjkoshy __P4MASK(from-tc-build, 0), 1510145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1511145256Sjkoshy __P4MASK(from-rom, 2), 1512145256Sjkoshy NULLMASK 1513145256Sjkoshy}; 1514145256Sjkoshy 1515145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1516145351Sjkoshy /* retired mispred branch type */ 1517145256Sjkoshy __P4MASK(conditional, 1), 1518145256Sjkoshy __P4MASK(call, 2), 1519145256Sjkoshy __P4MASK(return, 3), 1520145256Sjkoshy __P4MASK(indirect, 4), 1521145256Sjkoshy NULLMASK 1522145256Sjkoshy}; 1523145256Sjkoshy 1524145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1525145256Sjkoshy __P4MASK(conditional, 1), 1526145256Sjkoshy __P4MASK(call, 2), 1527145256Sjkoshy __P4MASK(retired, 3), 1528145256Sjkoshy __P4MASK(indirect, 4), 1529145256Sjkoshy NULLMASK 1530145256Sjkoshy}; 1531145256Sjkoshy 1532145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1533145256Sjkoshy __P4MASK(sbfull, 5), 1534145256Sjkoshy NULLMASK 1535145256Sjkoshy}; 1536145256Sjkoshy 1537145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1538145256Sjkoshy __P4MASK(wcb-evicts, 0), 1539145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1540145256Sjkoshy NULLMASK 1541145256Sjkoshy}; 1542145256Sjkoshy 1543145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1544145256Sjkoshy __P4MASK(nbogus, 0), 1545145256Sjkoshy __P4MASK(bogus, 1), 1546145256Sjkoshy NULLMASK 1547145256Sjkoshy}; 1548145256Sjkoshy 1549145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1550145256Sjkoshy __P4MASK(nbogus0, 0), 1551145256Sjkoshy __P4MASK(nbogus1, 1), 1552145256Sjkoshy __P4MASK(nbogus2, 2), 1553145256Sjkoshy __P4MASK(nbogus3, 3), 1554145256Sjkoshy __P4MASK(bogus0, 4), 1555145256Sjkoshy __P4MASK(bogus1, 5), 1556145256Sjkoshy __P4MASK(bogus2, 6), 1557145256Sjkoshy __P4MASK(bogus3, 7), 1558145256Sjkoshy NULLMASK 1559145256Sjkoshy}; 1560145256Sjkoshy 1561145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1562145256Sjkoshy __P4MASK(nbogus, 0), 1563145256Sjkoshy __P4MASK(bogus, 1), 1564145256Sjkoshy NULLMASK 1565145256Sjkoshy}; 1566145256Sjkoshy 1567145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1568145256Sjkoshy __P4MASK(nbogusntag, 0), 1569145256Sjkoshy __P4MASK(nbogustag, 1), 1570145256Sjkoshy __P4MASK(bogusntag, 2), 1571145256Sjkoshy __P4MASK(bogustag, 3), 1572145256Sjkoshy NULLMASK 1573145256Sjkoshy}; 1574145256Sjkoshy 1575145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1576145256Sjkoshy __P4MASK(nbogus, 0), 1577145256Sjkoshy __P4MASK(bogus, 1), 1578145256Sjkoshy NULLMASK 1579145256Sjkoshy}; 1580145256Sjkoshy 1581145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1582145256Sjkoshy __P4MASK(tagloads, 1), 1583145256Sjkoshy __P4MASK(tagstores, 2), 1584145256Sjkoshy NULLMASK 1585145256Sjkoshy}; 1586145256Sjkoshy 1587145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1588145256Sjkoshy __P4MASK(mmnp, 0), 1589145256Sjkoshy __P4MASK(mmnm, 1), 1590145256Sjkoshy __P4MASK(mmtp, 2), 1591145256Sjkoshy __P4MASK(mmtm, 3), 1592145256Sjkoshy NULLMASK 1593145256Sjkoshy}; 1594145256Sjkoshy 1595145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1596145256Sjkoshy __P4MASK(nbogus, 0), 1597145256Sjkoshy NULLMASK 1598145256Sjkoshy}; 1599145256Sjkoshy 1600145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1601145256Sjkoshy __P4MASK(fpsu, 0), 1602145256Sjkoshy __P4MASK(fpso, 1), 1603145256Sjkoshy __P4MASK(poao, 2), 1604145256Sjkoshy __P4MASK(poau, 3), 1605145256Sjkoshy __P4MASK(prea, 4), 1606145256Sjkoshy NULLMASK 1607145256Sjkoshy}; 1608145256Sjkoshy 1609145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1610145256Sjkoshy __P4MASK(clear, 0), 1611145256Sjkoshy __P4MASK(moclear, 2), 1612145256Sjkoshy __P4MASK(smclear, 3), 1613145256Sjkoshy NULLMASK 1614145256Sjkoshy}; 1615145256Sjkoshy 1616145256Sjkoshy/* P4 event parser */ 1617145256Sjkoshystatic int 1618145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1619145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1620145256Sjkoshy{ 1621145256Sjkoshy 1622145256Sjkoshy char *e, *p, *q; 1623145256Sjkoshy int count, has_tag, has_busreqtype, n; 1624240164Sfabient uint32_t cccractivemask; 1625240164Sfabient uint64_t evmask; 1626145256Sjkoshy const struct pmc_masks *pm, *pmask; 1627145256Sjkoshy 1628183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1629147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1630147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1631145256Sjkoshy 1632145256Sjkoshy pmask = NULL; 1633145256Sjkoshy evmask = 0; 1634145256Sjkoshy cccractivemask = 0x3; 1635145256Sjkoshy has_tag = has_busreqtype = 0; 1636145256Sjkoshy 1637145256Sjkoshy#define __P4SETMASK(M) do { \ 1638183107Sjkoshy pmask = p4_mask_##M; \ 1639145256Sjkoshy} while (0) 1640145256Sjkoshy 1641145256Sjkoshy switch (pe) { 1642145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1643145256Sjkoshy __P4SETMASK(tcdm); 1644145256Sjkoshy break; 1645145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1646145256Sjkoshy __P4SETMASK(bfr); 1647145256Sjkoshy break; 1648145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1649145256Sjkoshy __P4SETMASK(ir); 1650145256Sjkoshy break; 1651145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1652145256Sjkoshy __P4SETMASK(memcan); 1653145256Sjkoshy break; 1654145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1655145256Sjkoshy __P4SETMASK(memcomp); 1656145256Sjkoshy break; 1657145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1658145256Sjkoshy __P4SETMASK(lpr); 1659145256Sjkoshy break; 1660145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1661145256Sjkoshy __P4SETMASK(spr); 1662145256Sjkoshy break; 1663145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1664145256Sjkoshy __P4SETMASK(mlr); 1665145256Sjkoshy break; 1666145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1667145256Sjkoshy __P4SETMASK(pwt); 1668145256Sjkoshy break; 1669145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1670145256Sjkoshy __P4SETMASK(bcr); 1671145256Sjkoshy break; 1672145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1673145256Sjkoshy __P4SETMASK(ia); 1674145256Sjkoshy has_busreqtype = 1; 1675145256Sjkoshy break; 1676145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1677145256Sjkoshy __P4SETMASK(iae); 1678145256Sjkoshy has_busreqtype = 1; 1679145256Sjkoshy break; 1680145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1681145256Sjkoshy __P4SETMASK(fda); 1682145256Sjkoshy break; 1683145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1684145256Sjkoshy __P4SETMASK(ba); 1685145256Sjkoshy break; 1686145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1687145256Sjkoshy __P4SETMASK(sia); 1688145256Sjkoshy break; 1689145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1690145256Sjkoshy __P4SETMASK(psu); 1691145256Sjkoshy break; 1692145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1693145256Sjkoshy __P4SETMASK(pdu); 1694145256Sjkoshy break; 1695145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1696145256Sjkoshy __P4SETMASK(ssu); 1697145256Sjkoshy break; 1698145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1699145256Sjkoshy __P4SETMASK(sdu); 1700145256Sjkoshy break; 1701145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1702145256Sjkoshy __P4SETMASK(64bmu); 1703145256Sjkoshy break; 1704145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1705145256Sjkoshy __P4SETMASK(128bmu); 1706145256Sjkoshy break; 1707145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1708145256Sjkoshy __P4SETMASK(xfu); 1709145256Sjkoshy break; 1710145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1711145256Sjkoshy __P4SETMASK(xsmu); 1712145256Sjkoshy break; 1713145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1714145256Sjkoshy __P4SETMASK(gpe); 1715145256Sjkoshy break; 1716145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1717145256Sjkoshy __P4SETMASK(tmx); 1718145256Sjkoshy break; 1719145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1720145256Sjkoshy __P4SETMASK(uqw); 1721145256Sjkoshy break; 1722145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1723145256Sjkoshy __P4SETMASK(rmbt); 1724145256Sjkoshy break; 1725145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1726145256Sjkoshy __P4SETMASK(rbt); 1727145256Sjkoshy break; 1728145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1729145256Sjkoshy __P4SETMASK(rs); 1730145256Sjkoshy break; 1731145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1732145256Sjkoshy __P4SETMASK(wb); 1733145256Sjkoshy break; 1734145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1735145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1736145256Sjkoshy case PMC_EV_P4_BNR: 1737145256Sjkoshy case PMC_EV_P4_SNOOP: 1738145256Sjkoshy case PMC_EV_P4_RESPONSE: 1739145256Sjkoshy break; 1740145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1741145256Sjkoshy __P4SETMASK(fee); 1742145256Sjkoshy break; 1743145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1744145256Sjkoshy __P4SETMASK(ee); 1745145256Sjkoshy break; 1746145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1747145256Sjkoshy __P4SETMASK(re); 1748145256Sjkoshy break; 1749145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1750145256Sjkoshy __P4SETMASK(insret); 1751145256Sjkoshy break; 1752145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1753145256Sjkoshy __P4SETMASK(ur); 1754145256Sjkoshy break; 1755145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1756145256Sjkoshy __P4SETMASK(ut); 1757145256Sjkoshy break; 1758145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1759145256Sjkoshy __P4SETMASK(br); 1760145256Sjkoshy break; 1761145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1762145256Sjkoshy __P4SETMASK(mbr); 1763145256Sjkoshy break; 1764145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1765145256Sjkoshy __P4SETMASK(xa); 1766145256Sjkoshy break; 1767145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1768145256Sjkoshy __P4SETMASK(machclr); 1769145256Sjkoshy break; 1770145256Sjkoshy default: 1771174406Sjkoshy return (-1); 1772145256Sjkoshy } 1773145256Sjkoshy 1774145256Sjkoshy /* process additional flags */ 1775145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1776145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1777145256Sjkoshy q = strchr(p, '='); 1778145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1779174406Sjkoshy return (-1); 1780145256Sjkoshy 1781183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1782145256Sjkoshy cccractivemask = 0x0; 1783183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1784145256Sjkoshy cccractivemask = 0x1; 1785183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1786145256Sjkoshy cccractivemask = 0x2; 1787183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1788145256Sjkoshy cccractivemask = 0x3; 1789145256Sjkoshy else 1790174406Sjkoshy return (-1); 1791145256Sjkoshy 1792145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1793145256Sjkoshy if (has_busreqtype == 0) 1794174406Sjkoshy return (-1); 1795145256Sjkoshy 1796145256Sjkoshy q = strchr(p, '='); 1797145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1798174406Sjkoshy return (-1); 1799145256Sjkoshy 1800145256Sjkoshy count = strtol(q, &e, 0); 1801145256Sjkoshy if (e == q || *e != '\0') 1802174406Sjkoshy return (-1); 1803145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1804145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1805145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1806145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1807145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1808145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1809145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1810145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1811145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1812174406Sjkoshy return (-1); 1813145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1814145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1815145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1816145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1817145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1818145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1819145256Sjkoshy if (has_tag == 0) 1820174406Sjkoshy return (-1); 1821145256Sjkoshy 1822145256Sjkoshy q = strchr(p, '='); 1823145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1824174406Sjkoshy return (-1); 1825145256Sjkoshy 1826145256Sjkoshy count = strtol(q, &e, 0); 1827145256Sjkoshy if (e == q || *e != '\0') 1828174406Sjkoshy return (-1); 1829145256Sjkoshy 1830145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1831147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1832145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1833145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1834145256Sjkoshy q = strchr(p, '='); 1835145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1836174406Sjkoshy return (-1); 1837145256Sjkoshy 1838145256Sjkoshy count = strtol(q, &e, 0); 1839145256Sjkoshy if (e == q || *e != '\0') 1840174406Sjkoshy return (-1); 1841145256Sjkoshy 1842145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1843147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1844147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1845147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1846147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1847145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1848145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1849145256Sjkoshy else 1850174406Sjkoshy return (-1); 1851145256Sjkoshy } 1852145256Sjkoshy 1853145256Sjkoshy /* other post processing */ 1854145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1855145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1856145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1857145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1858145256Sjkoshy 1859145256Sjkoshy /* fill in thread activity mask */ 1860147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1861145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1862145256Sjkoshy 1863145256Sjkoshy if (evmask) 1864145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1865145256Sjkoshy 1866145256Sjkoshy switch (pe) { 1867145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1868145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1869145256Sjkoshy (evmask & 0x18) == 0x18) 1870174406Sjkoshy return (-1); /* can't have own+other bits together */ 1871145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1872145256Sjkoshy evmask = 0x1D; 1873145256Sjkoshy break; 1874145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1875145256Sjkoshy /* only one bit is allowed to be set */ 1876145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1877174406Sjkoshy return (-1); 1878145256Sjkoshy if (evmask == 0) { 1879183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1880145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1881145256Sjkoshy } 1882145256Sjkoshy break; 1883145256Sjkoshy default: 1884145256Sjkoshy if (evmask == 0 && pmask) { 1885145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1886145256Sjkoshy evmask |= pm->pm_value; 1887145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1888145256Sjkoshy } 1889145256Sjkoshy } 1890145256Sjkoshy 1891147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1892147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1893145256Sjkoshy 1894174406Sjkoshy return (0); 1895145256Sjkoshy} 1896145256Sjkoshy 1897147759Sjkoshy#endif 1898147759Sjkoshy 1899147759Sjkoshy#if defined(__i386__) 1900147759Sjkoshy 1901145256Sjkoshy/* 1902147191Sjkoshy * Pentium style PMCs 1903147191Sjkoshy */ 1904147191Sjkoshy 1905147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1906183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1907183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1908183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1909183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1910183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1911183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1912183105Sjkoshy EV_ALIAS("unhalted-cycles", 1913183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1914147191Sjkoshy EV_ALIAS(NULL, NULL) 1915147191Sjkoshy}; 1916147191Sjkoshy 1917147191Sjkoshystatic int 1918147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1919147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1920147191Sjkoshy{ 1921174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1922147191Sjkoshy} 1923147191Sjkoshy 1924147191Sjkoshy/* 1925145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1926145256Sjkoshy * and Pentium M CPUs. 1927145256Sjkoshy */ 1928145256Sjkoshy 1929145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1930145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1931145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1932145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1933145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1934168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1935145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1936145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1937155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1938145351Sjkoshy EV_ALIAS(NULL, NULL) 1939145256Sjkoshy}; 1940145256Sjkoshy 1941145256Sjkoshy#define P6_KW_CMASK "cmask" 1942145256Sjkoshy#define P6_KW_EDGE "edge" 1943145256Sjkoshy#define P6_KW_INV "inv" 1944145256Sjkoshy#define P6_KW_OS "os" 1945145256Sjkoshy#define P6_KW_UMASK "umask" 1946145256Sjkoshy#define P6_KW_USR "usr" 1947145256Sjkoshy 1948145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1949145256Sjkoshy PMCMASK(m, 0x01), 1950145256Sjkoshy PMCMASK(e, 0x02), 1951145256Sjkoshy PMCMASK(s, 0x04), 1952145256Sjkoshy PMCMASK(i, 0x08), 1953145256Sjkoshy NULLMASK 1954145256Sjkoshy}; 1955145256Sjkoshy 1956145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1957145256Sjkoshy PMCMASK(m, 0x01), 1958145256Sjkoshy PMCMASK(e, 0x02), 1959145256Sjkoshy PMCMASK(s, 0x04), 1960145256Sjkoshy PMCMASK(i, 0x08), 1961145256Sjkoshy PMCMASK(nonhw, 0x00), 1962145256Sjkoshy PMCMASK(hw, 0x10), 1963145256Sjkoshy PMCMASK(both, 0x30), 1964145256Sjkoshy NULLMASK 1965145256Sjkoshy}; 1966145256Sjkoshy 1967145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1968145256Sjkoshy PMCMASK(nonhw, 0x00), 1969145256Sjkoshy PMCMASK(hw, 0x10), 1970145256Sjkoshy PMCMASK(both, 0x30), 1971145256Sjkoshy NULLMASK 1972145256Sjkoshy}; 1973145256Sjkoshy 1974145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1975145256Sjkoshy PMCMASK(self, 0x00), 1976145256Sjkoshy PMCMASK(any, 0x20), 1977145256Sjkoshy NULLMASK 1978145256Sjkoshy}; 1979145256Sjkoshy 1980145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1981145256Sjkoshy PMCMASK(nta, 0x00), 1982145256Sjkoshy PMCMASK(t1, 0x01), 1983145256Sjkoshy PMCMASK(t2, 0x02), 1984145256Sjkoshy PMCMASK(wos, 0x03), 1985145256Sjkoshy NULLMASK 1986145256Sjkoshy}; 1987145256Sjkoshy 1988145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1989145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1990145256Sjkoshy PMCMASK(scalar, 0x01), 1991145256Sjkoshy NULLMASK 1992145256Sjkoshy}; 1993145256Sjkoshy 1994145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1995145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1996145256Sjkoshy PMCMASK(packed-shift, 0x02), 1997145256Sjkoshy PMCMASK(pack, 0x04), 1998145256Sjkoshy PMCMASK(unpack, 0x08), 1999145256Sjkoshy PMCMASK(packed-logical, 0x10), 2000145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 2001145256Sjkoshy NULLMASK 2002145256Sjkoshy}; 2003145256Sjkoshy 2004145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 2005145256Sjkoshy PMCMASK(mmxtofp, 0x00), 2006145256Sjkoshy PMCMASK(fptommx, 0x01), 2007145256Sjkoshy NULLMASK 2008145256Sjkoshy}; 2009145256Sjkoshy 2010145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 2011145256Sjkoshy PMCMASK(es, 0x01), 2012145256Sjkoshy PMCMASK(ds, 0x02), 2013145256Sjkoshy PMCMASK(fs, 0x04), 2014145256Sjkoshy PMCMASK(gs, 0x08), 2015145256Sjkoshy NULLMASK 2016145256Sjkoshy}; 2017145256Sjkoshy 2018145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 2019145256Sjkoshy PMCMASK(all, 0x00), 2020145256Sjkoshy PMCMASK(freq, 0x02), 2021145256Sjkoshy NULLMASK 2022145256Sjkoshy}; 2023145256Sjkoshy 2024145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 2025145256Sjkoshy PMCMASK(all, 0x00), 2026145256Sjkoshy PMCMASK(loadop, 0x01), 2027145256Sjkoshy PMCMASK(stdsta, 0x02), 2028145256Sjkoshy NULLMASK 2029145256Sjkoshy}; 2030145256Sjkoshy 2031145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 2032145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2033145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 2034145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2035145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2036145256Sjkoshy NULLMASK 2037145256Sjkoshy}; 2038145256Sjkoshy 2039145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 2040145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2041145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 2042145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2043145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2044145256Sjkoshy NULLMASK 2045145256Sjkoshy}; 2046145256Sjkoshy 2047145256Sjkoshy/* P6 event parser */ 2048145256Sjkoshystatic int 2049145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 2050145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2051145256Sjkoshy{ 2052145256Sjkoshy char *e, *p, *q; 2053240164Sfabient uint64_t evmask; 2054145256Sjkoshy int count, n; 2055145256Sjkoshy const struct pmc_masks *pm, *pmask; 2056145256Sjkoshy 2057183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2058147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 2059145256Sjkoshy 2060145256Sjkoshy evmask = 0; 2061145256Sjkoshy 2062145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 2063145256Sjkoshy 2064145256Sjkoshy switch(pe) { 2065183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 2066145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 2067145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2068145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2069145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2070145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2071145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2072145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2073145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2074145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2075145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2076145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2077145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2078145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2079145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2080145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2081145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2082145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2083145256Sjkoshy P6MASKSET(any); break; 2084145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2085145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2086145256Sjkoshy P6MASKSET(ekp); break; 2087145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2088145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2089145256Sjkoshy P6MASKSET(pps); break; 2090145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2091145256Sjkoshy P6MASKSET(mite); break; 2092145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2093145256Sjkoshy P6MASKSET(fmt); break; 2094145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2095145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2096145256Sjkoshy P6MASKSET(sr); break; 2097145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2098145256Sjkoshy P6MASKSET(eet); break; 2099145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2100145256Sjkoshy P6MASKSET(efur); break; 2101145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2102145256Sjkoshy P6MASKSET(essir); break; 2103145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2104145256Sjkoshy P6MASKSET(esscir); break; 2105145256Sjkoshy default: 2106145256Sjkoshy pmask = NULL; 2107145256Sjkoshy break; 2108145256Sjkoshy } 2109145256Sjkoshy 2110145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2111145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2112145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2113145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2114145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2115145256Sjkoshy P6MASKSET(mesihw); 2116145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2117145256Sjkoshy P6MASKSET(hw); 2118145256Sjkoshy } 2119145256Sjkoshy 2120145256Sjkoshy /* Parse additional modifiers if present */ 2121145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2122145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2123145256Sjkoshy q = strchr(p, '='); 2124145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2125174406Sjkoshy return (-1); 2126145256Sjkoshy count = strtol(q, &e, 0); 2127145256Sjkoshy if (e == q || *e != '\0') 2128174406Sjkoshy return (-1); 2129145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2130147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2131147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2132145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2133145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2134145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2135145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2136145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2137145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2138145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2139145256Sjkoshy evmask = 0; 2140145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2141174406Sjkoshy return (-1); 2142145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2143145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2144145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2145145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2146145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2147145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2148145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2149145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2150145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2151145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2152145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2153145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2154145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2155145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2156145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2157145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2158145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2159145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2160145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2161145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2162145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2163145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2164145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2165174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2166174406Sjkoshy return (-1); 2167145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2168145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2169145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2170145256Sjkoshy } else 2171174406Sjkoshy return (-1); 2172145256Sjkoshy } 2173145256Sjkoshy 2174145256Sjkoshy /* post processing */ 2175145256Sjkoshy switch (pe) { 2176145256Sjkoshy 2177145256Sjkoshy /* 2178145256Sjkoshy * The following events default to an evmask of 0 2179145256Sjkoshy */ 2180145256Sjkoshy 2181145256Sjkoshy /* default => 'self' */ 2182145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2183145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2184145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2185145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2186145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2187145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2188145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2189145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2190145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2191145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2192145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2193145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2194145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2195145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2196145256Sjkoshy 2197145256Sjkoshy /* default => 'nta' */ 2198145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2199145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2200145256Sjkoshy 2201145256Sjkoshy /* default => 'packed and scalar' */ 2202145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2203145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2204145256Sjkoshy 2205145256Sjkoshy /* default => 'mmx to fp transitions' */ 2206145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2207145256Sjkoshy 2208145256Sjkoshy /* default => 'SSE Packed Single' */ 2209145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2210145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2211145256Sjkoshy 2212145256Sjkoshy /* default => 'all fused micro-ops' */ 2213145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2214145256Sjkoshy 2215145256Sjkoshy /* default => 'all transitions' */ 2216145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2217145256Sjkoshy break; 2218145256Sjkoshy 2219145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2220145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2221145256Sjkoshy break; 2222145256Sjkoshy 2223145256Sjkoshy default: 2224145256Sjkoshy /* 2225145256Sjkoshy * For all other events, set the default event mask 2226145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2227145256Sjkoshy */ 2228145256Sjkoshy if (evmask == 0 && pmask) { 2229145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2230145256Sjkoshy evmask |= pm->pm_value; 2231145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2232145256Sjkoshy } 2233145256Sjkoshy 2234145256Sjkoshy break; 2235145256Sjkoshy } 2236145256Sjkoshy 2237145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2238147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2239147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2240145256Sjkoshy 2241174406Sjkoshy return (0); 2242145256Sjkoshy} 2243145256Sjkoshy 2244147191Sjkoshy#endif 2245147191Sjkoshy 2246183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2247183725Sjkoshystatic int 2248183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2249183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2250183725Sjkoshy{ 2251183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2252183725Sjkoshy return (-1); 2253183725Sjkoshy 2254183725Sjkoshy /* TSC events must be unqualified. */ 2255183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2256183725Sjkoshy return (-1); 2257183725Sjkoshy 2258183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2259183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2260183725Sjkoshy 2261183725Sjkoshy return (0); 2262183725Sjkoshy} 2263183725Sjkoshy#endif 2264183725Sjkoshy 2265233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2266233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2267233628Sfabient EV_ALIAS(NULL, NULL) 2268233628Sfabient}; 2269233628Sfabient 2270233628Sfabientstatic int 2271233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2272233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2273233628Sfabient{ 2274233628Sfabient (void)ctrspec; 2275233628Sfabient (void)pmc_config; 2276233628Sfabient 2277242622Sdim if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST) 2278233628Sfabient return (-1); 2279233628Sfabient 2280233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2281233628Sfabient return (0); 2282233628Sfabient} 2283233628Sfabient 2284200928Srpaulo#if defined(__XSCALE__) 2285200928Srpaulo 2286200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2287200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2288200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2289200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2290200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2291200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2292200928Srpaulo EV_ALIAS(NULL, NULL) 2293200928Srpaulo}; 2294200928Srpaulostatic int 2295200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2296200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2297200928Srpaulo{ 2298200928Srpaulo switch (pe) { 2299200928Srpaulo default: 2300200928Srpaulo break; 2301200928Srpaulo } 2302200928Srpaulo 2303200928Srpaulo return (0); 2304200928Srpaulo} 2305200928Srpaulo#endif 2306200928Srpaulo 2307204635Sgnn#if defined(__mips__) 2308204635Sgnn 2309204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2310204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2311204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2312204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2313204635Sgnn EV_ALIAS(NULL, NULL) 2314204635Sgnn}; 2315204635Sgnn 2316233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2317233335Sgonzo EV_ALIAS("instructions", "RET"), 2318233335Sgonzo EV_ALIAS("branches", "BR"), 2319233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2320233335Sgonzo EV_ALIAS(NULL, NULL) 2321233335Sgonzo}; 2322233335Sgonzo 2323233320Sgonzo#define MIPS_KW_OS "os" 2324233320Sgonzo#define MIPS_KW_USR "usr" 2325233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2326204635Sgnn 2327204635Sgnnstatic int 2328233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2329204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2330204635Sgnn{ 2331204635Sgnn char *p; 2332204635Sgnn 2333204635Sgnn (void) pe; 2334204635Sgnn 2335204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2336204635Sgnn 2337204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2338233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2339204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2340233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2341204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2342233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2343204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2344204635Sgnn else 2345204635Sgnn return (-1); 2346204635Sgnn } 2347204635Sgnn 2348204635Sgnn return (0); 2349204635Sgnn} 2350233320Sgonzo 2351204635Sgnn#endif /* __mips__ */ 2352204635Sgnn 2353228869Sjhibbits#if defined(__powerpc__) 2354204635Sgnn 2355228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2356228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2357228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2358228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2359228869Sjhibbits EV_ALIAS(NULL, NULL) 2360228869Sjhibbits}; 2361228869Sjhibbits 2362228869Sjhibbits#define PPC7450_KW_OS "os" 2363228869Sjhibbits#define PPC7450_KW_USR "usr" 2364228869Sjhibbits#define PPC7450_KW_ANYTHREAD "anythread" 2365228869Sjhibbits 2366228869Sjhibbitsstatic int 2367228869Sjhibbitsppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2368228869Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2369228869Sjhibbits{ 2370228869Sjhibbits char *p; 2371228869Sjhibbits 2372228869Sjhibbits (void) pe; 2373228869Sjhibbits 2374228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2375228869Sjhibbits 2376228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2377228869Sjhibbits if (KWMATCH(p, PPC7450_KW_OS)) 2378228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2379228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_USR)) 2380228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2381228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_ANYTHREAD)) 2382228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2383228869Sjhibbits else 2384228869Sjhibbits return (-1); 2385228869Sjhibbits } 2386228869Sjhibbits 2387228869Sjhibbits return (0); 2388228869Sjhibbits} 2389228869Sjhibbits#endif /* __powerpc__ */ 2390228869Sjhibbits 2391228869Sjhibbits 2392145256Sjkoshy/* 2393183725Sjkoshy * Match an event name `name' with its canonical form. 2394183725Sjkoshy * 2395185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2396185363Sjkoshy * hyphen characters are considered to match each other. 2397185363Sjkoshy * 2398183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2399183725Sjkoshy */ 2400183725Sjkoshy 2401183725Sjkoshystatic int 2402183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2403183725Sjkoshy{ 2404183725Sjkoshy int cc, nc; 2405183725Sjkoshy const unsigned char *c, *n; 2406183725Sjkoshy 2407183725Sjkoshy c = (const unsigned char *) canonicalname; 2408183725Sjkoshy n = (const unsigned char *) name; 2409183725Sjkoshy 2410183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2411183725Sjkoshy 2412185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2413185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2414183725Sjkoshy continue; 2415183725Sjkoshy 2416185363Sjkoshy if (toupper(nc) == toupper(cc)) 2417183725Sjkoshy continue; 2418183725Sjkoshy 2419185363Sjkoshy 2420183725Sjkoshy return (0); 2421183725Sjkoshy } 2422183725Sjkoshy 2423183725Sjkoshy if (*n == '\0' && *c == '\0') 2424183725Sjkoshy return (1); 2425183725Sjkoshy 2426183725Sjkoshy return (0); 2427183725Sjkoshy} 2428183725Sjkoshy 2429183725Sjkoshy/* 2430183725Sjkoshy * Match an event name against all the event named supported by a 2431183725Sjkoshy * PMC class. 2432183725Sjkoshy * 2433183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2434183725Sjkoshy */ 2435183725Sjkoshystatic const struct pmc_event_descr * 2436183725Sjkoshypmc_match_event_class(const char *name, 2437183725Sjkoshy const struct pmc_class_descr *pcd) 2438183725Sjkoshy{ 2439183725Sjkoshy size_t n; 2440183725Sjkoshy const struct pmc_event_descr *ev; 2441185363Sjkoshy 2442183725Sjkoshy ev = pcd->pm_evc_event_table; 2443183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2444183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2445183725Sjkoshy return (ev); 2446183725Sjkoshy 2447183725Sjkoshy return (NULL); 2448183725Sjkoshy} 2449183725Sjkoshy 2450183725Sjkoshystatic int 2451183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2452183725Sjkoshy{ 2453183725Sjkoshy size_t n; 2454183725Sjkoshy 2455183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2456183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2457183725Sjkoshy return (1); 2458183725Sjkoshy return (0); 2459183725Sjkoshy} 2460183725Sjkoshy 2461183725Sjkoshy/* 2462147191Sjkoshy * API entry points 2463145256Sjkoshy */ 2464145256Sjkoshy 2465147191Sjkoshyint 2466147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2467147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2468145256Sjkoshy{ 2469183725Sjkoshy size_t n; 2470147191Sjkoshy int retval; 2471147191Sjkoshy char *r, *spec_copy; 2472147191Sjkoshy const char *ctrname; 2473183725Sjkoshy const struct pmc_event_descr *ev; 2474183725Sjkoshy const struct pmc_event_alias *alias; 2475147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2476183725Sjkoshy const struct pmc_class_descr *pcd; 2477145256Sjkoshy 2478147191Sjkoshy spec_copy = NULL; 2479147191Sjkoshy retval = -1; 2480145256Sjkoshy 2481147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2482147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2483147191Sjkoshy errno = EINVAL; 2484147191Sjkoshy goto out; 2485147191Sjkoshy } 2486145256Sjkoshy 2487147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2488147191Sjkoshy if (pmc_mdep_event_aliases) 2489183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2490183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2491183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2492147191Sjkoshy break; 2493147191Sjkoshy } 2494145256Sjkoshy 2495147191Sjkoshy if (spec_copy == NULL) 2496147191Sjkoshy spec_copy = strdup(ctrspec); 2497145256Sjkoshy 2498147191Sjkoshy r = spec_copy; 2499147191Sjkoshy ctrname = strsep(&r, ","); 2500145256Sjkoshy 2501183725Sjkoshy /* 2502183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2503183725Sjkoshy * search for the event to the specified PMC class. 2504183725Sjkoshy */ 2505183725Sjkoshy ev = NULL; 2506185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2507185363Sjkoshy pcd = pmc_class_table[n]; 2508183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2509183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2510183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2511183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2512183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2513183725Sjkoshy errno = EINVAL; 2514183725Sjkoshy goto out; 2515183725Sjkoshy } 2516147191Sjkoshy break; 2517183725Sjkoshy } 2518183725Sjkoshy } 2519145256Sjkoshy 2520183725Sjkoshy /* 2521183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2522183725Sjkoshy * classes. 2523183725Sjkoshy */ 2524185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2525185363Sjkoshy pcd = pmc_class_table[n]; 2526183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2527183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2528183725Sjkoshy } 2529183725Sjkoshy 2530183725Sjkoshy if (ev == NULL) { 2531147191Sjkoshy errno = EINVAL; 2532147191Sjkoshy goto out; 2533147191Sjkoshy } 2534145256Sjkoshy 2535147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2536183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2537183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2538147191Sjkoshy pmc_config.pm_cpu = cpu; 2539147191Sjkoshy pmc_config.pm_mode = mode; 2540147191Sjkoshy pmc_config.pm_flags = flags; 2541145256Sjkoshy 2542147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2543147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2544145256Sjkoshy 2545183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2546147191Sjkoshy errno = EINVAL; 2547147191Sjkoshy goto out; 2548147191Sjkoshy } 2549145256Sjkoshy 2550147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2551147191Sjkoshy goto out; 2552145256Sjkoshy 2553147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2554145256Sjkoshy 2555147191Sjkoshy retval = 0; 2556145256Sjkoshy 2557147191Sjkoshy out: 2558147191Sjkoshy if (spec_copy) 2559147191Sjkoshy free(spec_copy); 2560145256Sjkoshy 2561174406Sjkoshy return (retval); 2562147191Sjkoshy} 2563145256Sjkoshy 2564147191Sjkoshyint 2565147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2566147191Sjkoshy{ 2567147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2568145256Sjkoshy 2569147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2570147191Sjkoshy pmc_attach_args.pm_pid = pid; 2571145256Sjkoshy 2572174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2573147191Sjkoshy} 2574145256Sjkoshy 2575147191Sjkoshyint 2576147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2577147191Sjkoshy{ 2578147191Sjkoshy unsigned int i; 2579147191Sjkoshy enum pmc_class cl; 2580145256Sjkoshy 2581147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2582147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2583147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2584147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2585174406Sjkoshy return (0); 2586147191Sjkoshy } 2587177107Sjkoshy errno = EINVAL; 2588177107Sjkoshy return (-1); 2589147191Sjkoshy} 2590145256Sjkoshy 2591147191Sjkoshyint 2592147191Sjkoshypmc_configure_logfile(int fd) 2593147191Sjkoshy{ 2594147191Sjkoshy struct pmc_op_configurelog cla; 2595145256Sjkoshy 2596147191Sjkoshy cla.pm_logfd = fd; 2597147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2598174406Sjkoshy return (-1); 2599174406Sjkoshy return (0); 2600147191Sjkoshy} 2601145256Sjkoshy 2602147191Sjkoshyint 2603147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2604147191Sjkoshy{ 2605147191Sjkoshy if (pmc_syscall == -1) { 2606147191Sjkoshy errno = ENXIO; 2607174406Sjkoshy return (-1); 2608147191Sjkoshy } 2609145256Sjkoshy 2610147219Sjkoshy *pci = &cpu_info; 2611174406Sjkoshy return (0); 2612147191Sjkoshy} 2613145256Sjkoshy 2614147191Sjkoshyint 2615147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2616147191Sjkoshy{ 2617147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2618145256Sjkoshy 2619147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2620147191Sjkoshy pmc_detach_args.pm_pid = pid; 2621174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2622147191Sjkoshy} 2623147191Sjkoshy 2624147191Sjkoshyint 2625147191Sjkoshypmc_disable(int cpu, int pmc) 2626145256Sjkoshy{ 2627147191Sjkoshy struct pmc_op_pmcadmin ssa; 2628145256Sjkoshy 2629147191Sjkoshy ssa.pm_cpu = cpu; 2630147191Sjkoshy ssa.pm_pmc = pmc; 2631147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2632174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2633147191Sjkoshy} 2634145256Sjkoshy 2635147191Sjkoshyint 2636147191Sjkoshypmc_enable(int cpu, int pmc) 2637147191Sjkoshy{ 2638147191Sjkoshy struct pmc_op_pmcadmin ssa; 2639145256Sjkoshy 2640147191Sjkoshy ssa.pm_cpu = cpu; 2641147191Sjkoshy ssa.pm_pmc = pmc; 2642147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2643174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2644147191Sjkoshy} 2645145256Sjkoshy 2646147191Sjkoshy/* 2647147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2648147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2649147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2650147191Sjkoshy * the number of event name pointers returned. 2651147191Sjkoshy * 2652147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2653147191Sjkoshy * is responsible for freeing this space when done. 2654147191Sjkoshy */ 2655147191Sjkoshyint 2656147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2657147191Sjkoshy int *nevents) 2658147191Sjkoshy{ 2659147191Sjkoshy int count; 2660147191Sjkoshy const char **names; 2661147191Sjkoshy const struct pmc_event_descr *ev; 2662147191Sjkoshy 2663147191Sjkoshy switch (cl) 2664147191Sjkoshy { 2665185363Sjkoshy case PMC_CLASS_IAF: 2666185363Sjkoshy ev = iaf_event_table; 2667185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2668185363Sjkoshy break; 2669185363Sjkoshy case PMC_CLASS_IAP: 2670185363Sjkoshy /* 2671185363Sjkoshy * Return the most appropriate set of event name 2672185363Sjkoshy * spellings for the current CPU. 2673185363Sjkoshy */ 2674185363Sjkoshy switch (cpu_info.pm_cputype) { 2675185363Sjkoshy default: 2676185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2677185363Sjkoshy ev = atom_event_table; 2678185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2679185363Sjkoshy break; 2680185363Sjkoshy case PMC_CPU_INTEL_CORE: 2681185363Sjkoshy ev = core_event_table; 2682185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2683185363Sjkoshy break; 2684185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2685185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2686185363Sjkoshy ev = core2_event_table; 2687185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2688185363Sjkoshy break; 2689187761Sjeff case PMC_CPU_INTEL_COREI7: 2690187761Sjeff ev = corei7_event_table; 2691187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2692187761Sjeff break; 2693240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2694240164Sfabient ev = ivybridge_event_table; 2695240164Sfabient count = PMC_EVENT_TABLE_SIZE(ivybridge); 2696240164Sfabient break; 2697246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 2698246166Ssbruno ev = ivybridge_xeon_event_table; 2699246166Ssbruno count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 2700246166Ssbruno break; 2701232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2702232366Sdavide ev = sandybridge_event_table; 2703232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2704232366Sdavide break; 2705241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2706241738Ssbruno ev = sandybridge_xeon_event_table; 2707241738Ssbruno count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 2708241738Ssbruno break; 2709206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2710206089Sfabient ev = westmere_event_table; 2711206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2712206089Sfabient break; 2713185363Sjkoshy } 2714185363Sjkoshy break; 2715206089Sfabient case PMC_CLASS_UCF: 2716206089Sfabient ev = ucf_event_table; 2717206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2718206089Sfabient break; 2719206089Sfabient case PMC_CLASS_UCP: 2720206089Sfabient /* 2721206089Sfabient * Return the most appropriate set of event name 2722206089Sfabient * spellings for the current CPU. 2723206089Sfabient */ 2724206089Sfabient switch (cpu_info.pm_cputype) { 2725206089Sfabient default: 2726206089Sfabient case PMC_CPU_INTEL_COREI7: 2727206089Sfabient ev = corei7uc_event_table; 2728206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2729206089Sfabient break; 2730232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2731232366Sdavide ev = sandybridgeuc_event_table; 2732232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2733232366Sdavide break; 2734206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2735206089Sfabient ev = westmereuc_event_table; 2736206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2737206089Sfabient break; 2738206089Sfabient } 2739206089Sfabient break; 2740147191Sjkoshy case PMC_CLASS_TSC: 2741183725Sjkoshy ev = tsc_event_table; 2742183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2743145256Sjkoshy break; 2744147191Sjkoshy case PMC_CLASS_K7: 2745183725Sjkoshy ev = k7_event_table; 2746183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2747145256Sjkoshy break; 2748147191Sjkoshy case PMC_CLASS_K8: 2749183725Sjkoshy ev = k8_event_table; 2750183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2751145256Sjkoshy break; 2752183725Sjkoshy case PMC_CLASS_P4: 2753183725Sjkoshy ev = p4_event_table; 2754183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2755183725Sjkoshy break; 2756147191Sjkoshy case PMC_CLASS_P5: 2757183725Sjkoshy ev = p5_event_table; 2758183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2759145256Sjkoshy break; 2760147191Sjkoshy case PMC_CLASS_P6: 2761183725Sjkoshy ev = p6_event_table; 2762183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2763145256Sjkoshy break; 2764200928Srpaulo case PMC_CLASS_XSCALE: 2765200928Srpaulo ev = xscale_event_table; 2766200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2767200928Srpaulo break; 2768204635Sgnn case PMC_CLASS_MIPS24K: 2769204635Sgnn ev = mips24k_event_table; 2770204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2771204635Sgnn break; 2772233335Sgonzo case PMC_CLASS_OCTEON: 2773233335Sgonzo ev = octeon_event_table; 2774233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 2775233335Sgonzo break; 2776228869Sjhibbits case PMC_CLASS_PPC7450: 2777228869Sjhibbits ev = ppc7450_event_table; 2778228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2779228869Sjhibbits break; 2780233628Sfabient case PMC_CLASS_SOFT: 2781233628Sfabient ev = soft_event_table; 2782233628Sfabient count = soft_event_info.pm_nevent; 2783233628Sfabient break; 2784145256Sjkoshy default: 2785147191Sjkoshy errno = EINVAL; 2786174406Sjkoshy return (-1); 2787145256Sjkoshy } 2788145256Sjkoshy 2789147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2790174406Sjkoshy return (-1); 2791145256Sjkoshy 2792147191Sjkoshy *eventnames = names; 2793147191Sjkoshy *nevents = count; 2794145256Sjkoshy 2795147191Sjkoshy for (;count--; ev++, names++) 2796147191Sjkoshy *names = ev->pm_ev_name; 2797233628Sfabient 2798174406Sjkoshy return (0); 2799147191Sjkoshy} 2800145256Sjkoshy 2801147191Sjkoshyint 2802147191Sjkoshypmc_flush_logfile(void) 2803147191Sjkoshy{ 2804174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2805147191Sjkoshy} 2806145256Sjkoshy 2807147191Sjkoshyint 2808226514Sfabientpmc_close_logfile(void) 2809226514Sfabient{ 2810226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2811226514Sfabient} 2812226514Sfabient 2813226514Sfabientint 2814147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2815147191Sjkoshy{ 2816147191Sjkoshy struct pmc_op_getdriverstats gms; 2817145256Sjkoshy 2818147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2819174406Sjkoshy return (-1); 2820145256Sjkoshy 2821147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2822147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2823147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2824147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2825147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2826147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2827147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2828147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2829147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2830174406Sjkoshy return (0); 2831147191Sjkoshy} 2832145256Sjkoshy 2833147191Sjkoshyint 2834147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2835147191Sjkoshy{ 2836147191Sjkoshy struct pmc_op_getmsr gm; 2837147191Sjkoshy 2838147191Sjkoshy gm.pm_pmcid = pmc; 2839147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2840174406Sjkoshy return (-1); 2841147191Sjkoshy *msr = gm.pm_msr; 2842174406Sjkoshy return (0); 2843145256Sjkoshy} 2844145256Sjkoshy 2845145256Sjkoshyint 2846145256Sjkoshypmc_init(void) 2847145256Sjkoshy{ 2848145256Sjkoshy int error, pmc_mod_id; 2849147219Sjkoshy unsigned int n; 2850145256Sjkoshy uint32_t abi_version; 2851145256Sjkoshy struct module_stat pmc_modstat; 2852147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2853198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2854198433Sjkoshy int cpu_has_iaf_counters; 2855198433Sjkoshy unsigned int t; 2856198433Sjkoshy#endif 2857145256Sjkoshy 2858145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2859174406Sjkoshy return (0); 2860145256Sjkoshy 2861145256Sjkoshy /* retrieve the system call number from the KLD */ 2862145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2863174406Sjkoshy return (-1); 2864145256Sjkoshy 2865145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2866145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2867174406Sjkoshy return (-1); 2868145256Sjkoshy 2869145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2870145256Sjkoshy 2871147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2872147191Sjkoshy abi_version = PMC_VERSION; 2873145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2874145256Sjkoshy return (pmc_syscall = -1); 2875145256Sjkoshy 2876147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2877147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2878145256Sjkoshy errno = EPROGMISMATCH; 2879145256Sjkoshy return (pmc_syscall = -1); 2880145256Sjkoshy } 2881145256Sjkoshy 2882147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2883145256Sjkoshy return (pmc_syscall = -1); 2884145256Sjkoshy 2885147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2886147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2887147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2888147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2889147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2890147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2891147219Sjkoshy 2892185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2893185363Sjkoshy sizeof(struct pmc_class_descr *)); 2894185363Sjkoshy 2895185363Sjkoshy if (pmc_class_table == NULL) 2896185363Sjkoshy return (-1); 2897185363Sjkoshy 2898198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2899198433Sjkoshy pmc_class_table[n] = NULL; 2900185363Sjkoshy 2901185363Sjkoshy /* 2902233628Sfabient * Get soft events list. 2903233628Sfabient */ 2904233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 2905233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 2906233628Sfabient return (pmc_syscall = -1); 2907233628Sfabient 2908233628Sfabient /* Map soft events to static list. */ 2909233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 2910233628Sfabient soft_event_table[n].pm_ev_name = 2911233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 2912233628Sfabient soft_event_table[n].pm_ev_code = 2913233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 2914233628Sfabient } 2915233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 2916233628Sfabient soft_event_info.pm_nevent; 2917233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 2918233628Sfabient soft_event_table; 2919233628Sfabient 2920233628Sfabient /* 2921185363Sjkoshy * Fill in the class table. 2922185363Sjkoshy */ 2923185363Sjkoshy n = 0; 2924233628Sfabient 2925233628Sfabient /* Fill soft events information. */ 2926233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 2927185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 2928233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 2929233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 2930198433Sjkoshy 2931198433Sjkoshy /* 2932198433Sjkoshy * Check if this CPU has fixed function counters. 2933198433Sjkoshy */ 2934198433Sjkoshy cpu_has_iaf_counters = 0; 2935198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 2936212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 2937212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 2938198433Sjkoshy cpu_has_iaf_counters = 1; 2939185363Sjkoshy#endif 2940185363Sjkoshy 2941183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 2942183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 2943183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 2944183725Sjkoshy pmc_mdep_class_list_size = \ 2945183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 2946183725Sjkoshy } while (0) 2947183725Sjkoshy 2948198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 2949198433Sjkoshy PMC_MDEP_INIT(C); \ 2950212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 2951212224Sfabient if (!cpu_has_iaf_counters) \ 2952198433Sjkoshy pmc_mdep_event_aliases = \ 2953198433Sjkoshy C##_aliases_without_iaf; \ 2954198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 2955198433Sjkoshy } while (0) 2956198433Sjkoshy 2957183725Sjkoshy /* Configure the event name parser. */ 2958145256Sjkoshy switch (cpu_info.pm_cputype) { 2959145340Smarcel#if defined(__i386__) 2960145256Sjkoshy case PMC_CPU_AMD_K7: 2961183725Sjkoshy PMC_MDEP_INIT(k7); 2962185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 2963145256Sjkoshy break; 2964145256Sjkoshy case PMC_CPU_INTEL_P5: 2965183725Sjkoshy PMC_MDEP_INIT(p5); 2966185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 2967145256Sjkoshy break; 2968145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 2969145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 2970145256Sjkoshy case PMC_CPU_INTEL_PIII: 2971145256Sjkoshy case PMC_CPU_INTEL_PM: 2972183725Sjkoshy PMC_MDEP_INIT(p6); 2973185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 2974145256Sjkoshy break; 2975147759Sjkoshy#endif 2976147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 2977183725Sjkoshy case PMC_CPU_AMD_K8: 2978183725Sjkoshy PMC_MDEP_INIT(k8); 2979185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 2980183725Sjkoshy break; 2981185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2982198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 2983185363Sjkoshy break; 2984185363Sjkoshy case PMC_CPU_INTEL_CORE: 2985185363Sjkoshy PMC_MDEP_INIT(core); 2986202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 2987185363Sjkoshy break; 2988185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2989185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2990198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 2991185363Sjkoshy break; 2992187761Sjeff case PMC_CPU_INTEL_COREI7: 2993206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2994206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 2995198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 2996187761Sjeff break; 2997240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2998240164Sfabient PMC_MDEP_INIT_INTEL_V2(ivybridge); 2999240164Sfabient break; 3000246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3001246166Ssbruno PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon); 3002246166Ssbruno break; 3003232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3004232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 3005232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 3006232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 3007232366Sdavide break; 3008241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3009241738Ssbruno PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); 3010241738Ssbruno break; 3011206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3012206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3013206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 3014206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 3015206089Sfabient break; 3016145256Sjkoshy case PMC_CPU_INTEL_PIV: 3017183725Sjkoshy PMC_MDEP_INIT(p4); 3018185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 3019145256Sjkoshy break; 3020145256Sjkoshy#endif 3021233628Sfabient case PMC_CPU_GENERIC: 3022233628Sfabient PMC_MDEP_INIT(generic); 3023233628Sfabient break; 3024200928Srpaulo#if defined(__XSCALE__) 3025200928Srpaulo case PMC_CPU_INTEL_XSCALE: 3026200928Srpaulo PMC_MDEP_INIT(xscale); 3027200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 3028200928Srpaulo break; 3029200928Srpaulo#endif 3030204635Sgnn#if defined(__mips__) 3031204635Sgnn case PMC_CPU_MIPS_24K: 3032204635Sgnn PMC_MDEP_INIT(mips24k); 3033204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 3034204635Sgnn break; 3035233335Sgonzo case PMC_CPU_MIPS_OCTEON: 3036233335Sgonzo PMC_MDEP_INIT(octeon); 3037233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 3038233335Sgonzo break; 3039204635Sgnn#endif /* __mips__ */ 3040228869Sjhibbits#if defined(__powerpc__) 3041228869Sjhibbits case PMC_CPU_PPC_7450: 3042228869Sjhibbits PMC_MDEP_INIT(ppc7450); 3043228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 3044228869Sjhibbits break; 3045228869Sjhibbits#endif 3046145256Sjkoshy default: 3047145256Sjkoshy /* 3048145256Sjkoshy * Some kind of CPU this version of the library knows nothing 3049145256Sjkoshy * about. This shouldn't happen since the abi version check 3050145256Sjkoshy * should have caught this. 3051145256Sjkoshy */ 3052145256Sjkoshy errno = ENXIO; 3053145256Sjkoshy return (pmc_syscall = -1); 3054145256Sjkoshy } 3055145256Sjkoshy 3056174406Sjkoshy return (0); 3057145256Sjkoshy} 3058145256Sjkoshy 3059147191Sjkoshyconst char * 3060147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 3061145256Sjkoshy{ 3062147191Sjkoshy int i; 3063145256Sjkoshy 3064147191Sjkoshy /* 3065147191Sjkoshy * 'cap' should have a single bit set and should be in 3066147191Sjkoshy * range. 3067147191Sjkoshy */ 3068147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 3069147191Sjkoshy cap > PMC_CAP_LAST) { 3070145256Sjkoshy errno = EINVAL; 3071174406Sjkoshy return (NULL); 3072145256Sjkoshy } 3073145256Sjkoshy 3074147191Sjkoshy i = ffs(cap); 3075174406Sjkoshy return (pmc_capability_names[i - 1]); 3076147191Sjkoshy} 3077145256Sjkoshy 3078147191Sjkoshyconst char * 3079147191Sjkoshypmc_name_of_class(enum pmc_class pc) 3080147191Sjkoshy{ 3081147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 3082147191Sjkoshy pc <= PMC_CLASS_LAST) 3083174406Sjkoshy return (pmc_class_names[pc]); 3084145256Sjkoshy 3085147191Sjkoshy errno = EINVAL; 3086174406Sjkoshy return (NULL); 3087147191Sjkoshy} 3088145256Sjkoshy 3089147191Sjkoshyconst char * 3090147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3091147191Sjkoshy{ 3092183725Sjkoshy size_t n; 3093183725Sjkoshy 3094183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3095183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3096183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3097183725Sjkoshy 3098147191Sjkoshy errno = EINVAL; 3099174406Sjkoshy return (NULL); 3100147191Sjkoshy} 3101145256Sjkoshy 3102147191Sjkoshyconst char * 3103147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3104147191Sjkoshy{ 3105147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3106147191Sjkoshy pd <= PMC_DISP_LAST) 3107174406Sjkoshy return (pmc_disposition_names[pd]); 3108145256Sjkoshy 3109147191Sjkoshy errno = EINVAL; 3110174406Sjkoshy return (NULL); 3111147191Sjkoshy} 3112145256Sjkoshy 3113147191Sjkoshyconst char * 3114185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3115147191Sjkoshy{ 3116183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3117145256Sjkoshy 3118183725Sjkoshy ev = evfence = NULL; 3119185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3120185363Sjkoshy ev = iaf_event_table; 3121185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3122185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3123185363Sjkoshy switch (cpu) { 3124185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3125185363Sjkoshy ev = atom_event_table; 3126185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3127185363Sjkoshy break; 3128185363Sjkoshy case PMC_CPU_INTEL_CORE: 3129185363Sjkoshy ev = core_event_table; 3130185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3131185363Sjkoshy break; 3132185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3133185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3134185363Sjkoshy ev = core2_event_table; 3135185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3136185363Sjkoshy break; 3137187761Sjeff case PMC_CPU_INTEL_COREI7: 3138187761Sjeff ev = corei7_event_table; 3139187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3140187761Sjeff break; 3141240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3142240164Sfabient ev = ivybridge_event_table; 3143240164Sfabient evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); 3144240164Sfabient break; 3145246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3146246166Ssbruno ev = ivybridge_xeon_event_table; 3147246166Ssbruno evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 3148246166Ssbruno break; 3149232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3150232366Sdavide ev = sandybridge_event_table; 3151232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3152232366Sdavide break; 3153241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3154241738Ssbruno ev = sandybridge_xeon_event_table; 3155241738Ssbruno evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 3156241738Ssbruno break; 3157206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3158206089Sfabient ev = westmere_event_table; 3159206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3160206089Sfabient break; 3161185363Sjkoshy default: /* Unknown CPU type. */ 3162185363Sjkoshy break; 3163185363Sjkoshy } 3164206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3165206089Sfabient ev = ucf_event_table; 3166206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3167206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3168206089Sfabient switch (cpu) { 3169206089Sfabient case PMC_CPU_INTEL_COREI7: 3170206089Sfabient ev = corei7uc_event_table; 3171206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3172206089Sfabient break; 3173232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3174232366Sdavide ev = sandybridgeuc_event_table; 3175232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3176232366Sdavide break; 3177206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3178206089Sfabient ev = westmereuc_event_table; 3179206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3180206089Sfabient break; 3181206089Sfabient default: /* Unknown CPU type. */ 3182206089Sfabient break; 3183206089Sfabient } 3184206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3185183725Sjkoshy ev = k7_event_table; 3186183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3187183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3188183725Sjkoshy ev = k8_event_table; 3189183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3190183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3191183725Sjkoshy ev = p4_event_table; 3192183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3193183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3194183725Sjkoshy ev = p5_event_table; 3195183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3196183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3197183725Sjkoshy ev = p6_event_table; 3198183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3199200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3200200928Srpaulo ev = xscale_event_table; 3201200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3202204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3203204635Sgnn ev = mips24k_event_table; 3204233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3205233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3206233335Sgonzo ev = octeon_event_table; 3207233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3208228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3209228869Sjhibbits ev = ppc7450_event_table; 3210233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3211183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3212183725Sjkoshy ev = tsc_event_table; 3213183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3214242622Sdim } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { 3215233628Sfabient ev = soft_event_table; 3216233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3217183725Sjkoshy } 3218183725Sjkoshy 3219183725Sjkoshy for (; ev != evfence; ev++) 3220183725Sjkoshy if (pe == ev->pm_ev_code) 3221183725Sjkoshy return (ev->pm_ev_name); 3222183725Sjkoshy 3223185363Sjkoshy return (NULL); 3224185363Sjkoshy} 3225185363Sjkoshy 3226185363Sjkoshyconst char * 3227185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3228185363Sjkoshy{ 3229185363Sjkoshy const char *n; 3230185363Sjkoshy 3231185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3232185363Sjkoshy return (n); 3233185363Sjkoshy 3234147191Sjkoshy errno = EINVAL; 3235174406Sjkoshy return (NULL); 3236147191Sjkoshy} 3237145256Sjkoshy 3238147191Sjkoshyconst char * 3239147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3240147191Sjkoshy{ 3241147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3242147191Sjkoshy pm <= PMC_MODE_LAST) 3243174406Sjkoshy return (pmc_mode_names[pm]); 3244145256Sjkoshy 3245147191Sjkoshy errno = EINVAL; 3246174406Sjkoshy return (NULL); 3247147191Sjkoshy} 3248145256Sjkoshy 3249147191Sjkoshyconst char * 3250147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3251147191Sjkoshy{ 3252147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3253147191Sjkoshy ps <= PMC_STATE_LAST) 3254174406Sjkoshy return (pmc_state_names[ps]); 3255145256Sjkoshy 3256147191Sjkoshy errno = EINVAL; 3257174406Sjkoshy return (NULL); 3258145256Sjkoshy} 3259145256Sjkoshy 3260145256Sjkoshyint 3261147191Sjkoshypmc_ncpu(void) 3262145256Sjkoshy{ 3263147191Sjkoshy if (pmc_syscall == -1) { 3264147191Sjkoshy errno = ENXIO; 3265174406Sjkoshy return (-1); 3266147191Sjkoshy } 3267145256Sjkoshy 3268174406Sjkoshy return (cpu_info.pm_ncpu); 3269145256Sjkoshy} 3270145256Sjkoshy 3271145256Sjkoshyint 3272147191Sjkoshypmc_npmc(int cpu) 3273145256Sjkoshy{ 3274147191Sjkoshy if (pmc_syscall == -1) { 3275147191Sjkoshy errno = ENXIO; 3276174406Sjkoshy return (-1); 3277147191Sjkoshy } 3278145256Sjkoshy 3279147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3280147191Sjkoshy errno = EINVAL; 3281174406Sjkoshy return (-1); 3282147191Sjkoshy } 3283145256Sjkoshy 3284174406Sjkoshy return (cpu_info.pm_npmc); 3285145256Sjkoshy} 3286145256Sjkoshy 3287145256Sjkoshyint 3288147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3289145256Sjkoshy{ 3290147191Sjkoshy int nbytes, npmc; 3291147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3292145256Sjkoshy 3293147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3294174406Sjkoshy return (-1); 3295145256Sjkoshy 3296147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3297147191Sjkoshy npmc * sizeof(struct pmc_info); 3298145256Sjkoshy 3299147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3300174406Sjkoshy return (-1); 3301145256Sjkoshy 3302147191Sjkoshy pmci->pm_cpu = cpu; 3303145256Sjkoshy 3304147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3305147191Sjkoshy free(pmci); 3306174406Sjkoshy return (-1); 3307147191Sjkoshy } 3308145256Sjkoshy 3309147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3310147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3311174406Sjkoshy return (0); 3312145256Sjkoshy} 3313145256Sjkoshy 3314145256Sjkoshyint 3315145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3316145256Sjkoshy{ 3317145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3318145256Sjkoshy 3319145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3320145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3321145256Sjkoshy pmc_read_op.pm_value = -1; 3322145256Sjkoshy 3323145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3324174406Sjkoshy return (-1); 3325145256Sjkoshy 3326145256Sjkoshy *value = pmc_read_op.pm_value; 3327174406Sjkoshy return (0); 3328145256Sjkoshy} 3329145256Sjkoshy 3330145256Sjkoshyint 3331147191Sjkoshypmc_release(pmc_id_t pmc) 3332145256Sjkoshy{ 3333147191Sjkoshy struct pmc_op_simple pmc_release_args; 3334145256Sjkoshy 3335147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3336174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3337145256Sjkoshy} 3338145256Sjkoshy 3339145256Sjkoshyint 3340145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3341145256Sjkoshy{ 3342145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3343145256Sjkoshy 3344145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3345145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3346145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3347145256Sjkoshy 3348145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3349174406Sjkoshy return (-1); 3350145256Sjkoshy 3351145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3352174406Sjkoshy return (0); 3353145256Sjkoshy} 3354145256Sjkoshy 3355145256Sjkoshyint 3356145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3357145256Sjkoshy{ 3358145256Sjkoshy struct pmc_op_pmcsetcount sc; 3359145256Sjkoshy 3360145256Sjkoshy sc.pm_pmcid = pmc; 3361145256Sjkoshy sc.pm_count = value; 3362145256Sjkoshy 3363145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3364174406Sjkoshy return (-1); 3365174406Sjkoshy return (0); 3366145256Sjkoshy} 3367145256Sjkoshy 3368145256Sjkoshyint 3369147191Sjkoshypmc_start(pmc_id_t pmc) 3370145256Sjkoshy{ 3371147191Sjkoshy struct pmc_op_simple pmc_start_args; 3372145256Sjkoshy 3373147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3374174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3375145256Sjkoshy} 3376145256Sjkoshy 3377145256Sjkoshyint 3378147191Sjkoshypmc_stop(pmc_id_t pmc) 3379145256Sjkoshy{ 3380147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3381145256Sjkoshy 3382147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3383174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3384145256Sjkoshy} 3385145256Sjkoshy 3386145256Sjkoshyint 3387145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3388145774Sjkoshy{ 3389145774Sjkoshy unsigned int i; 3390145774Sjkoshy enum pmc_class cl; 3391145774Sjkoshy 3392145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3393145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3394145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3395145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3396174406Sjkoshy return (0); 3397145774Sjkoshy } 3398177107Sjkoshy errno = EINVAL; 3399177107Sjkoshy return (-1); 3400145774Sjkoshy} 3401145774Sjkoshy 3402145774Sjkoshyint 3403147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3404145774Sjkoshy{ 3405147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3406145774Sjkoshy 3407147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3408147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3409147191Sjkoshy pmc_write_op.pm_value = value; 3410174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3411145256Sjkoshy} 3412145256Sjkoshy 3413145256Sjkoshyint 3414147191Sjkoshypmc_writelog(uint32_t userdata) 3415145256Sjkoshy{ 3416147191Sjkoshy struct pmc_op_writelog wl; 3417145256Sjkoshy 3418147191Sjkoshy wl.pm_userdata = userdata; 3419174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3420145256Sjkoshy} 3421