libpmc.c revision 277835
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 277835 2015-01-28 16:08:07Z br $"); 29145256Sjkoshy 30145256Sjkoshy#include <sys/types.h> 31261342Sjhibbits#include <sys/param.h> 32145256Sjkoshy#include <sys/module.h> 33145256Sjkoshy#include <sys/pmc.h> 34145256Sjkoshy#include <sys/syscall.h> 35145256Sjkoshy 36145256Sjkoshy#include <ctype.h> 37145256Sjkoshy#include <errno.h> 38145256Sjkoshy#include <fcntl.h> 39145256Sjkoshy#include <pmc.h> 40145256Sjkoshy#include <stdio.h> 41145256Sjkoshy#include <stdlib.h> 42145256Sjkoshy#include <string.h> 43145256Sjkoshy#include <strings.h> 44145256Sjkoshy#include <unistd.h> 45145256Sjkoshy 46185363Sjkoshy#include "libpmcinternal.h" 47185363Sjkoshy 48145256Sjkoshy/* Function prototypes */ 49145340Smarcel#if defined(__i386__) 50145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 51145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 52147191Sjkoshy#endif 53147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 54185363Sjkoshystatic int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 55185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 56185363Sjkoshystatic int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 57185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 58206089Sfabientstatic int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 59206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 60206089Sfabientstatic int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 61206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 62147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 63145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 64147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 65147759Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 66147191Sjkoshy#endif 67147191Sjkoshy#if defined(__i386__) 68145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 69145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 70147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 71145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 72145256Sjkoshy#endif 73183725Sjkoshy#if defined(__amd64__) || defined(__i386__) 74183725Sjkoshystatic int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 75183725Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 76183725Sjkoshy#endif 77277835Sbr#if defined(__arm__) 78200928Srpaulo#if defined(__XSCALE__) 79200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 80200928Srpaulo struct pmc_op_pmcallocate *_pmc_config); 81200928Srpaulo#endif 82277835Sbrstatic int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 83277835Sbr struct pmc_op_pmcallocate *_pmc_config); 84277835Sbr#endif 85204635Sgnn#if defined(__mips__) 86233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 87204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 88204635Sgnn#endif /* __mips__ */ 89233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 90233628Sfabient struct pmc_op_pmcallocate *_pmc_config); 91204635Sgnn 92228869Sjhibbits#if defined(__powerpc__) 93261342Sjhibbitsstatic int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec, 94228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 95228869Sjhibbits#endif /* __powerpc__ */ 96204635Sgnn 97145256Sjkoshy#define PMC_CALL(cmd, params) \ 98145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 99145256Sjkoshy 100145256Sjkoshy/* 101145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 102145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 103145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 104145256Sjkoshy * lookup table. 105145256Sjkoshy */ 106145256Sjkoshystruct pmc_event_alias { 107145256Sjkoshy const char *pm_alias; 108145256Sjkoshy const char *pm_spec; 109145256Sjkoshy}; 110145256Sjkoshy 111145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 112145256Sjkoshy 113145256Sjkoshy/* 114183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 115145256Sjkoshy * to integer codes used by the PMC KLD. 116145256Sjkoshy */ 117145256Sjkoshystruct pmc_event_descr { 118145256Sjkoshy const char *pm_ev_name; 119145256Sjkoshy enum pmc_event pm_ev_code; 120145256Sjkoshy}; 121145256Sjkoshy 122183725Sjkoshy/* 123183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 124183725Sjkoshy * event names to event tables and other PMC class data. 125183725Sjkoshy */ 126183725Sjkoshystruct pmc_class_descr { 127183725Sjkoshy const char *pm_evc_name; 128183725Sjkoshy size_t pm_evc_name_size; 129183725Sjkoshy enum pmc_class pm_evc_class; 130183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 131183725Sjkoshy size_t pm_evc_event_table_size; 132183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 133183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 134183725Sjkoshy}; 135183725Sjkoshy 136183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 137183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 138183725Sjkoshy 139183725Sjkoshy#undef __PMC_EV 140183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 141183725Sjkoshy 142183725Sjkoshy/* 143185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 144183725Sjkoshy * 145185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 146183725Sjkoshy */ 147185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 148183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 149183725Sjkoshy { \ 150183725Sjkoshy __PMC_EV_##C() \ 151185363Sjkoshy } 152185363Sjkoshy 153185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 154185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 155185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 156185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 157185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 158185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 159200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 160277835SbrPMC_CLASSDEP_TABLE(armv7, ARMV7); 161204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 162233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON); 163206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 164228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 165261342SjhibbitsPMC_CLASSDEP_TABLE(ppc970, PPC970); 166185363Sjkoshy 167233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; 168233628Sfabient 169185363Sjkoshy#undef __PMC_EV_ALIAS 170185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 171185363Sjkoshy 172185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 173185363Sjkoshy{ 174185363Sjkoshy __PMC_EV_ALIAS_ATOM() 175185363Sjkoshy}; 176185363Sjkoshy 177263446Shirenstatic const struct pmc_event_descr atom_silvermont_event_table[] = 178263446Shiren{ 179263446Shiren __PMC_EV_ALIAS_ATOM_SILVERMONT() 180263446Shiren}; 181263446Shiren 182185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 183185363Sjkoshy{ 184185363Sjkoshy __PMC_EV_ALIAS_CORE() 185185363Sjkoshy}; 186185363Sjkoshy 187185363Sjkoshy 188185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 189185363Sjkoshy{ 190185363Sjkoshy __PMC_EV_ALIAS_CORE2() 191185363Sjkoshy}; 192185363Sjkoshy 193187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 194187761Sjeff{ 195187761Sjeff __PMC_EV_ALIAS_COREI7() 196187761Sjeff}; 197187761Sjeff 198267062Skibstatic const struct pmc_event_descr nehalem_ex_event_table[] = 199267062Skib{ 200267062Skib __PMC_EV_ALIAS_COREI7() 201267062Skib}; 202267062Skib 203248842Ssbrunostatic const struct pmc_event_descr haswell_event_table[] = 204248842Ssbruno{ 205248842Ssbruno __PMC_EV_ALIAS_HASWELL() 206248842Ssbruno}; 207248842Ssbruno 208277177Srrsstatic const struct pmc_event_descr haswell_xeon_event_table[] = 209277177Srrs{ 210277177Srrs __PMC_EV_ALIAS_HASWELL_XEON() 211277177Srrs}; 212277177Srrs 213277177Srrs 214240164Sfabientstatic const struct pmc_event_descr ivybridge_event_table[] = 215240164Sfabient{ 216240164Sfabient __PMC_EV_ALIAS_IVYBRIDGE() 217240164Sfabient}; 218240164Sfabient 219246166Ssbrunostatic const struct pmc_event_descr ivybridge_xeon_event_table[] = 220246166Ssbruno{ 221246166Ssbruno __PMC_EV_ALIAS_IVYBRIDGE_XEON() 222246166Ssbruno}; 223246166Ssbruno 224232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 225232366Sdavide{ 226232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 227232366Sdavide}; 228232366Sdavide 229241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] = 230241738Ssbruno{ 231241738Ssbruno __PMC_EV_ALIAS_SANDYBRIDGE_XEON() 232241738Ssbruno}; 233241738Ssbruno 234206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 235206089Sfabient{ 236206089Sfabient __PMC_EV_ALIAS_WESTMERE() 237206089Sfabient}; 238206089Sfabient 239267062Skibstatic const struct pmc_event_descr westmere_ex_event_table[] = 240267062Skib{ 241267062Skib __PMC_EV_ALIAS_WESTMERE() 242267062Skib}; 243267062Skib 244206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 245206089Sfabient{ 246206089Sfabient __PMC_EV_ALIAS_COREI7UC() 247206089Sfabient}; 248206089Sfabient 249248842Ssbrunostatic const struct pmc_event_descr haswelluc_event_table[] = 250248842Ssbruno{ 251248842Ssbruno __PMC_EV_ALIAS_HASWELLUC() 252248842Ssbruno}; 253248842Ssbruno 254232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 255232366Sdavide{ 256232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 257232366Sdavide}; 258232366Sdavide 259206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 260206089Sfabient{ 261206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 262206089Sfabient}; 263206089Sfabient 264185363Sjkoshy/* 265185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 266185363Sjkoshy * 267185363Sjkoshy * Map a CPU to the PMC classes it supports. 268185363Sjkoshy */ 269185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 270183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 271183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 272183725Sjkoshy } 273183725Sjkoshy 274233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 275263446ShirenPMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 276233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 277233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 278233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 279267062SkibPMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 280248842SsbrunoPMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 281277177SrrsPMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 282240164SfabientPMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 283246166SsbrunoPMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 284233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 285241738SsbrunoPMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 286233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 287267062SkibPMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 288233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); 289233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); 290233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); 291233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); 292233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); 293233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); 294277835SbrPMC_MDEP_TABLE(armv7, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); 295233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 296233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 297233628SfabientPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450); 298261342SjhibbitsPMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970); 299233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 300183725Sjkoshy 301183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 302145256Sjkoshy{ 303183725Sjkoshy __PMC_EV_TSC() 304145256Sjkoshy}; 305145256Sjkoshy 306183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 307185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 308185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 309185363Sjkoshy { \ 310185363Sjkoshy .pm_evc_name = #CLASS "-", \ 311185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 312185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 313185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 314183725Sjkoshy .pm_evc_event_table_size = \ 315185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 316185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 317183725Sjkoshy } 318183725Sjkoshy 319185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 320185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 321185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 322263446ShirenPMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap); 323185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 324185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 325187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 326267062SkibPMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap); 327248842SsbrunoPMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap); 328277177SrrsPMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell, iap); 329240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); 330246166SsbrunoPMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap); 331232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 332241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); 333206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 334267062SkibPMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap); 335206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 336206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 337248842SsbrunoPMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp); 338232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 339206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 340185363Sjkoshy#endif 341183725Sjkoshy#if defined(__i386__) 342185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 343183725Sjkoshy#endif 344183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 345185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 346185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 347183725Sjkoshy#endif 348183725Sjkoshy#if defined(__i386__) 349185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 350185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 351183725Sjkoshy#endif 352183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 353185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 354183725Sjkoshy#endif 355277835Sbr#if defined(__arm__) 356200928Srpaulo#if defined(__XSCALE__) 357200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 358200928Srpaulo#endif 359277835SbrPMC_CLASS_TABLE_DESC(armv7, ARMV7, armv7, armv7); 360277835Sbr#endif 361204635Sgnn#if defined(__mips__) 362233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 363233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 364204635Sgnn#endif /* __mips__ */ 365228869Sjhibbits#if defined(__powerpc__) 366261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc); 367261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc); 368228869Sjhibbits#endif 369228869Sjhibbits 370233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 371233628Sfabient{ 372233628Sfabient .pm_evc_name = "SOFT-", 373233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 374233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 375233628Sfabient .pm_evc_event_table = NULL, 376233628Sfabient .pm_evc_event_table_size = 0, 377233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 378233628Sfabient}; 379233628Sfabient 380183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 381183725Sjkoshy 382185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 383185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 384185363Sjkoshy 385183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 386183725Sjkoshystatic size_t pmc_mdep_class_list_size; 387183725Sjkoshy 388145256Sjkoshy/* 389145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 390145256Sjkoshy * strings. 391145256Sjkoshy */ 392145256Sjkoshy 393145256Sjkoshystatic const char * pmc_capability_names[] = { 394145256Sjkoshy#undef __PMC_CAP 395145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 396145256Sjkoshy __PMC_CAPS() 397145256Sjkoshy}; 398145256Sjkoshy 399145256Sjkoshystatic const char * pmc_class_names[] = { 400145256Sjkoshy#undef __PMC_CLASS 401145256Sjkoshy#define __PMC_CLASS(C) #C , 402145256Sjkoshy __PMC_CLASSES() 403145256Sjkoshy}; 404145256Sjkoshy 405183725Sjkoshystruct pmc_cputype_map { 406228557Sdim enum pmc_cputype pm_cputype; 407183725Sjkoshy const char *pm_name; 408183725Sjkoshy}; 409183725Sjkoshy 410183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 411145256Sjkoshy#undef __PMC_CPU 412183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 413145256Sjkoshy __PMC_CPUS() 414145256Sjkoshy}; 415145256Sjkoshy 416145256Sjkoshystatic const char * pmc_disposition_names[] = { 417145256Sjkoshy#undef __PMC_DISP 418145256Sjkoshy#define __PMC_DISP(D) #D , 419145256Sjkoshy __PMC_DISPOSITIONS() 420145256Sjkoshy}; 421145256Sjkoshy 422145256Sjkoshystatic const char * pmc_mode_names[] = { 423145256Sjkoshy#undef __PMC_MODE 424145256Sjkoshy#define __PMC_MODE(M,N) #M , 425145256Sjkoshy __PMC_MODES() 426145256Sjkoshy}; 427145256Sjkoshy 428145256Sjkoshystatic const char * pmc_state_names[] = { 429145256Sjkoshy#undef __PMC_STATE 430145256Sjkoshy#define __PMC_STATE(S) #S , 431145256Sjkoshy __PMC_STATES() 432145256Sjkoshy}; 433145256Sjkoshy 434233628Sfabient/* 435233628Sfabient * Filled in by pmc_init(). 436233628Sfabient */ 437233628Sfabientstatic int pmc_syscall = -1; 438233628Sfabientstatic struct pmc_cpuinfo cpu_info; 439233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 440145256Sjkoshy 441145256Sjkoshy/* Event masks for events */ 442145256Sjkoshystruct pmc_masks { 443145256Sjkoshy const char *pm_name; 444240164Sfabient const uint64_t pm_value; 445145256Sjkoshy}; 446145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 447206089Sfabient#define NULLMASK { .pm_name = NULL } 448145256Sjkoshy 449147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 450145256Sjkoshystatic int 451240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) 452145256Sjkoshy{ 453145256Sjkoshy const struct pmc_masks *pm; 454145256Sjkoshy char *q, *r; 455145256Sjkoshy int c; 456145256Sjkoshy 457145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 458174406Sjkoshy return (-1); 459183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 460145256Sjkoshy if (*++q == '\0') /* no more data */ 461174406Sjkoshy return (-1); 462145256Sjkoshy c = 0; /* count of mask keywords seen */ 463145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 464183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 465183725Sjkoshy pm++) 466145256Sjkoshy ; 467145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 468174406Sjkoshy return (-1); 469145256Sjkoshy *evmask |= pm->pm_value; 470145256Sjkoshy c++; 471145256Sjkoshy } 472174406Sjkoshy return (c); 473145256Sjkoshy} 474145340Smarcel#endif 475145256Sjkoshy 476145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 477145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 478145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 479145256Sjkoshy 480145340Smarcel#if defined(__i386__) 481145256Sjkoshy 482145256Sjkoshy/* 483145256Sjkoshy * AMD K7 (Athlon) CPUs. 484145256Sjkoshy */ 485145256Sjkoshy 486145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 487145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 488145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 489145351Sjkoshy EV_ALIAS("cycles", "tsc"), 490183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 491145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 492145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 493145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 494145351Sjkoshy EV_ALIAS(NULL, NULL) 495145256Sjkoshy}; 496145256Sjkoshy 497145256Sjkoshy#define K7_KW_COUNT "count" 498145256Sjkoshy#define K7_KW_EDGE "edge" 499145256Sjkoshy#define K7_KW_INV "inv" 500145256Sjkoshy#define K7_KW_OS "os" 501145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 502145256Sjkoshy#define K7_KW_USR "usr" 503145256Sjkoshy 504145256Sjkoshystatic int 505145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 506145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 507145256Sjkoshy{ 508183107Sjkoshy char *e, *p, *q; 509183107Sjkoshy int c, has_unitmask; 510145256Sjkoshy uint32_t count, unitmask; 511145256Sjkoshy 512147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 513183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 514145256Sjkoshy 515145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 516145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 517145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 518145256Sjkoshy has_unitmask = 1; 519147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 520145256Sjkoshy } else 521145256Sjkoshy unitmask = has_unitmask = 0; 522145256Sjkoshy 523145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 524145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 525145256Sjkoshy q = strchr(p, '='); 526145256Sjkoshy if (*++q == '\0') /* skip '=' */ 527174406Sjkoshy return (-1); 528145256Sjkoshy 529145256Sjkoshy count = strtol(q, &e, 0); 530145256Sjkoshy if (e == q || *e != '\0') 531174406Sjkoshy return (-1); 532145256Sjkoshy 533145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 534147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 535147191Sjkoshy AMD_PMC_TO_COUNTER(count); 536145256Sjkoshy 537145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 538145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 539145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 540145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 541145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 542145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 543145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 544145256Sjkoshy if (has_unitmask == 0) 545174406Sjkoshy return (-1); 546145256Sjkoshy unitmask = 0; 547145256Sjkoshy q = strchr(p, '='); 548145256Sjkoshy if (*++q == '\0') /* skip '=' */ 549174406Sjkoshy return (-1); 550145256Sjkoshy 551145256Sjkoshy while ((c = tolower(*q++)) != 0) 552145256Sjkoshy if (c == 'm') 553147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 554145256Sjkoshy else if (c == 'o') 555147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 556145256Sjkoshy else if (c == 'e') 557147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 558145256Sjkoshy else if (c == 's') 559147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 560145256Sjkoshy else if (c == 'i') 561147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 562145256Sjkoshy else if (c == '+') 563145256Sjkoshy continue; 564145256Sjkoshy else 565174406Sjkoshy return (-1); 566145256Sjkoshy 567145256Sjkoshy if (unitmask == 0) 568174406Sjkoshy return (-1); 569145256Sjkoshy 570145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 571145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 572145256Sjkoshy } else 573174406Sjkoshy return (-1); 574145256Sjkoshy } 575145256Sjkoshy 576145256Sjkoshy if (has_unitmask) { 577145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 578147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 579147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 580145256Sjkoshy } 581145256Sjkoshy 582174406Sjkoshy return (0); 583145256Sjkoshy 584145256Sjkoshy} 585145256Sjkoshy 586147191Sjkoshy#endif 587147191Sjkoshy 588147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 589147191Sjkoshy 590145256Sjkoshy/* 591185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 592185363Sjkoshy */ 593185363Sjkoshy 594185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 595185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 596185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 597185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 598185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 599185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 600185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 601185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 602185363Sjkoshy EV_ALIAS(NULL, NULL) 603185363Sjkoshy}; 604185363Sjkoshy 605185363Sjkoshy/* 606185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 607185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 608198433Sjkoshy * 609198433Sjkoshy * We map aliases to events on the fixed-function counters if these 610198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 611198433Sjkoshy * counters. 612185363Sjkoshy */ 613185363Sjkoshy 614185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 615185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 616185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 617185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 618185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 619185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 620185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 621185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 622185363Sjkoshy EV_ALIAS(NULL, NULL) 623185363Sjkoshy}; 624185363Sjkoshy 625198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 626198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 627198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 628198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 629198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 630198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 631198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 632198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 633198433Sjkoshy EV_ALIAS(NULL, NULL) 634198433Sjkoshy}; 635198433Sjkoshy 636198433Sjkoshy#define atom_aliases core2_aliases 637198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 638263446Shiren#define atom_silvermont_aliases core2_aliases 639263446Shiren#define atom_silvermont_aliases_without_iaf core2_aliases_without_iaf 640198433Sjkoshy#define corei7_aliases core2_aliases 641198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 642267062Skib#define nehalem_ex_aliases core2_aliases 643267062Skib#define nehalem_ex_aliases_without_iaf core2_aliases_without_iaf 644248842Ssbruno#define haswell_aliases core2_aliases 645248842Ssbruno#define haswell_aliases_without_iaf core2_aliases_without_iaf 646277177Srrs#define haswell_xeon_aliases core2_aliases 647277177Srrs#define haswell_xeon_aliases_without_iaf core2_aliases_without_iaf 648240164Sfabient#define ivybridge_aliases core2_aliases 649240164Sfabient#define ivybridge_aliases_without_iaf core2_aliases_without_iaf 650246166Ssbruno#define ivybridge_xeon_aliases core2_aliases 651246166Ssbruno#define ivybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 652232366Sdavide#define sandybridge_aliases core2_aliases 653232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 654241738Ssbruno#define sandybridge_xeon_aliases core2_aliases 655241738Ssbruno#define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 656206089Sfabient#define westmere_aliases core2_aliases 657206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 658267062Skib#define westmere_ex_aliases core2_aliases 659267062Skib#define westmere_ex_aliases_without_iaf core2_aliases_without_iaf 660198433Sjkoshy 661185363Sjkoshy#define IAF_KW_OS "os" 662185363Sjkoshy#define IAF_KW_USR "usr" 663185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 664185363Sjkoshy 665185363Sjkoshy/* 666185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 667185363Sjkoshy */ 668185363Sjkoshystatic int 669185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 670185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 671185363Sjkoshy{ 672185363Sjkoshy char *p; 673185363Sjkoshy 674185363Sjkoshy (void) pe; 675185363Sjkoshy 676185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 677185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 678185363Sjkoshy 679185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 680185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 681185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 682185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 683185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 684185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 685185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 686185363Sjkoshy else 687185363Sjkoshy return (-1); 688185363Sjkoshy } 689185363Sjkoshy 690185363Sjkoshy return (0); 691185363Sjkoshy} 692185363Sjkoshy 693185363Sjkoshy/* 694185363Sjkoshy * Core/Core2 support. 695185363Sjkoshy */ 696185363Sjkoshy 697185363Sjkoshy#define IAP_KW_AGENT "agent" 698185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 699185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 700185363Sjkoshy#define IAP_KW_CMASK "cmask" 701185363Sjkoshy#define IAP_KW_CORE "core" 702185363Sjkoshy#define IAP_KW_EDGE "edge" 703185363Sjkoshy#define IAP_KW_INV "inv" 704185363Sjkoshy#define IAP_KW_OS "os" 705185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 706185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 707185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 708185363Sjkoshy#define IAP_KW_TRANSITION "trans" 709185363Sjkoshy#define IAP_KW_USR "usr" 710206089Sfabient#define IAP_KW_RSP "rsp" 711185363Sjkoshy 712185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 713185363Sjkoshy PMCMASK(all, (0x3 << 14)), 714185363Sjkoshy PMCMASK(this, (0x1 << 14)), 715185363Sjkoshy NULLMASK 716185363Sjkoshy}; 717185363Sjkoshy 718185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 719185363Sjkoshy PMCMASK(this, 0), 720185363Sjkoshy PMCMASK(any, (0x1 << 13)), 721185363Sjkoshy NULLMASK 722185363Sjkoshy}; 723185363Sjkoshy 724185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 725185363Sjkoshy PMCMASK(both, (0x3 << 12)), 726185363Sjkoshy PMCMASK(only, (0x1 << 12)), 727185363Sjkoshy PMCMASK(exclude, 0), 728185363Sjkoshy NULLMASK 729185363Sjkoshy}; 730185363Sjkoshy 731185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 732185363Sjkoshy PMCMASK(i, (1 << 8)), 733185363Sjkoshy PMCMASK(s, (1 << 9)), 734185363Sjkoshy PMCMASK(e, (1 << 10)), 735185363Sjkoshy PMCMASK(m, (1 << 11)), 736185363Sjkoshy NULLMASK 737185363Sjkoshy}; 738185363Sjkoshy 739185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 740185363Sjkoshy PMCMASK(clean, (1 << 8)), 741185363Sjkoshy PMCMASK(hit, (1 << 9)), 742185363Sjkoshy PMCMASK(hitm, (1 << 11)), 743185363Sjkoshy NULLMASK 744185363Sjkoshy}; 745185363Sjkoshy 746185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 747185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 748185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 749185363Sjkoshy NULLMASK 750185363Sjkoshy}; 751185363Sjkoshy 752185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 753185363Sjkoshy PMCMASK(any, 0x00), 754185363Sjkoshy PMCMASK(frequency, 0x10), 755185363Sjkoshy NULLMASK 756185363Sjkoshy}; 757185363Sjkoshy 758240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = { 759206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 760206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 761206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 762206089Sfabient PMCMASK(WB, (1 << 3)), 763206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 764206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 765206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 766206089Sfabient PMCMASK(OTHER, (1 << 7)), 767206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 768206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 769206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 770206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 771206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 772206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 773206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 774206089Sfabient NULLMASK 775206089Sfabient}; 776206089Sfabient 777241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { 778240164Sfabient PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 779240164Sfabient PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 780240164Sfabient PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 781240164Sfabient PMCMASK(REQ_WB, (1ULL << 3)), 782240164Sfabient PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 783240164Sfabient PMCMASK(REQ_PF_RFO, (1ULL << 5)), 784240164Sfabient PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 785240164Sfabient PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), 786240164Sfabient PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), 787240164Sfabient PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), 788240164Sfabient PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), 789240164Sfabient PMCMASK(REQ_STRM_ST, (1ULL << 11)), 790240164Sfabient PMCMASK(REQ_OTHER, (1ULL << 15)), 791240164Sfabient PMCMASK(RES_ANY, (1ULL << 16)), 792240164Sfabient PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 793240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 794240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 795240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 796240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 797240164Sfabient PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 798241974Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 799240164Sfabient PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 800240164Sfabient PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 801240164Sfabient PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 802240164Sfabient PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 803240164Sfabient PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 804240164Sfabient PMCMASK(RES_NON_DRAM, (1ULL << 37)), 805240164Sfabient NULLMASK 806240164Sfabient}; 807240164Sfabient 808248842Ssbrunostatic struct pmc_masks iap_rsp_mask_haswell[] = { 809248842Ssbruno PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 810248842Ssbruno PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 811248842Ssbruno PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 812248842Ssbruno PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 813248842Ssbruno PMCMASK(REQ_PF_RFO, (1ULL << 5)), 814248842Ssbruno PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 815248842Ssbruno PMCMASK(REQ_OTHER, (1ULL << 15)), 816248842Ssbruno PMCMASK(RES_ANY, (1ULL << 16)), 817248842Ssbruno PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 818248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 819248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 820248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 821248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 822248842Ssbruno PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 823248842Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 824248842Ssbruno PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 825248842Ssbruno PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 826248842Ssbruno PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 827248842Ssbruno PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 828248842Ssbruno PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 829248842Ssbruno PMCMASK(RES_NON_DRAM, (1ULL << 37)), 830248842Ssbruno NULLMASK 831248842Ssbruno}; 832248842Ssbruno 833185363Sjkoshystatic int 834185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 835185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 836185363Sjkoshy{ 837185363Sjkoshy char *e, *p, *q; 838240164Sfabient uint64_t cachestate, evmask, rsp; 839185363Sjkoshy int count, n; 840185363Sjkoshy 841185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 842185363Sjkoshy PMC_CAP_QUALIFIER); 843185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 844185363Sjkoshy 845206089Sfabient cachestate = evmask = rsp = 0; 846185363Sjkoshy 847185363Sjkoshy /* Parse additional modifiers if present */ 848185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 849185363Sjkoshy 850185363Sjkoshy n = 0; 851185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 852185363Sjkoshy q = strchr(p, '='); 853185363Sjkoshy if (*++q == '\0') /* skip '=' */ 854185363Sjkoshy return (-1); 855185363Sjkoshy count = strtol(q, &e, 0); 856185363Sjkoshy if (e == q || *e != '\0') 857185363Sjkoshy return (-1); 858185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 859185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 860185363Sjkoshy IAP_CMASK(count); 861185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 862185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 863185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 864185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 865185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 866185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 867185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 868185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 869185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 870185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 871193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 872185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 873185363Sjkoshy if (n != 1) 874185363Sjkoshy return (-1); 875193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 876185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 877185363Sjkoshy if (n != 1) 878185363Sjkoshy return (-1); 879193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 880185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 881185363Sjkoshy if (n != 1) 882185363Sjkoshy return (-1); 883193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 884185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 885185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 886193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 887185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 888185363Sjkoshy if (n != 1) 889185363Sjkoshy return (-1); 890185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 891263446Shiren cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT || 892185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 893206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 894193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 895185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 896185363Sjkoshy &evmask); 897193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 898185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 899185363Sjkoshy &evmask); 900185363Sjkoshy } else 901185363Sjkoshy return (-1); 902206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 903267062Skib cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE || 904267062Skib cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX || 905267062Skib cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) { 906206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 907240164Sfabient n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); 908206089Sfabient } else 909206089Sfabient return (-1); 910240164Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || 911241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || 912246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE || 913246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) { 914240164Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 915241738Ssbruno n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); 916240164Sfabient } else 917240164Sfabient return (-1); 918277177Srrs } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL || 919277177Srrs cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) { 920248842Ssbruno if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 921248842Ssbruno n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); 922248842Ssbruno } else 923248842Ssbruno return (-1); 924185363Sjkoshy } else 925185363Sjkoshy return (-1); 926185363Sjkoshy 927185363Sjkoshy if (n < 0) /* Parsing failed. */ 928185363Sjkoshy return (-1); 929185363Sjkoshy } 930185363Sjkoshy 931185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 932185363Sjkoshy 933185363Sjkoshy /* 934185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 935185363Sjkoshy * specified by the user, use a sensible default. 936185363Sjkoshy */ 937185363Sjkoshy switch (pe) { 938185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 939185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 940185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 941185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 942185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 943185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 944185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 945185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 946185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 947185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 948185363Sjkoshy if (cachestate == 0) 949185363Sjkoshy cachestate = (0xF << 8); 950207482Srstone break; 951207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 952207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 953207482Srstone * Atom processor 954207482Srstone */ 955207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 956207482Srstone cachestate = (0xF << 8); 957207482Srstone break; 958185363Sjkoshy default: 959185363Sjkoshy break; 960185363Sjkoshy } 961185363Sjkoshy 962185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 963206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 964185363Sjkoshy 965185363Sjkoshy return (0); 966185363Sjkoshy} 967185363Sjkoshy 968185363Sjkoshy/* 969206089Sfabient * Intel Uncore. 970206089Sfabient */ 971206089Sfabient 972206089Sfabientstatic int 973206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 974206089Sfabient struct pmc_op_pmcallocate *pmc_config) 975206089Sfabient{ 976206089Sfabient (void) pe; 977206089Sfabient (void) ctrspec; 978206089Sfabient 979206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 980206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 981206089Sfabient 982206089Sfabient return (0); 983206089Sfabient} 984206089Sfabient 985206089Sfabient#define UCP_KW_CMASK "cmask" 986206089Sfabient#define UCP_KW_EDGE "edge" 987206089Sfabient#define UCP_KW_INV "inv" 988206089Sfabient 989206089Sfabientstatic int 990206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 991206089Sfabient struct pmc_op_pmcallocate *pmc_config) 992206089Sfabient{ 993206089Sfabient char *e, *p, *q; 994206089Sfabient int count, n; 995206089Sfabient 996206089Sfabient (void) pe; 997206089Sfabient 998206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 999206089Sfabient PMC_CAP_QUALIFIER); 1000206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 1001206089Sfabient 1002206089Sfabient /* Parse additional modifiers if present */ 1003206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 1004206089Sfabient 1005206089Sfabient n = 0; 1006206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 1007206089Sfabient q = strchr(p, '='); 1008206089Sfabient if (*++q == '\0') /* skip '=' */ 1009206089Sfabient return (-1); 1010206089Sfabient count = strtol(q, &e, 0); 1011206089Sfabient if (e == q || *e != '\0') 1012206089Sfabient return (-1); 1013206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1014206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 1015206089Sfabient UCP_CMASK(count); 1016206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 1017206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 1018206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 1019206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 1020206089Sfabient } else 1021206089Sfabient return (-1); 1022206089Sfabient 1023206089Sfabient if (n < 0) /* Parsing failed. */ 1024206089Sfabient return (-1); 1025206089Sfabient } 1026206089Sfabient 1027206089Sfabient return (0); 1028206089Sfabient} 1029206089Sfabient 1030206089Sfabient/* 1031147191Sjkoshy * AMD K8 PMCs. 1032147191Sjkoshy * 1033147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 1034147191Sjkoshy * events. 1035147191Sjkoshy */ 1036147191Sjkoshy 1037147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 1038147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 1039147191Sjkoshy EV_ALIAS("branch-mispredicts", 1040147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 1041147191Sjkoshy EV_ALIAS("cycles", "tsc"), 1042147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 1043147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 1044183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 1045147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 1046155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 1047147191Sjkoshy EV_ALIAS(NULL, NULL) 1048147191Sjkoshy}; 1049147191Sjkoshy 1050147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 1051147191Sjkoshy 1052147191Sjkoshy/* 1053147191Sjkoshy * Parsing tables 1054147191Sjkoshy */ 1055147191Sjkoshy 1056147191Sjkoshy/* fp dispatched fpu ops */ 1057147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 1058147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 1059147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 1060147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 1061147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 1062147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 1063147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 1064147191Sjkoshy NULLMASK 1065147191Sjkoshy}; 1066147191Sjkoshy 1067147191Sjkoshy/* ls segment register loads */ 1068147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 1069147191Sjkoshy __K8MASK(es, 0), 1070147191Sjkoshy __K8MASK(cs, 1), 1071147191Sjkoshy __K8MASK(ss, 2), 1072147191Sjkoshy __K8MASK(ds, 3), 1073147191Sjkoshy __K8MASK(fs, 4), 1074147191Sjkoshy __K8MASK(gs, 5), 1075147191Sjkoshy __K8MASK(hs, 6), 1076147191Sjkoshy NULLMASK 1077147191Sjkoshy}; 1078147191Sjkoshy 1079147191Sjkoshy/* ls locked operation */ 1080147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 1081147191Sjkoshy __K8MASK(locked-instructions, 0), 1082147191Sjkoshy __K8MASK(cycles-in-request, 1), 1083147191Sjkoshy __K8MASK(cycles-to-complete, 2), 1084147191Sjkoshy NULLMASK 1085147191Sjkoshy}; 1086147191Sjkoshy 1087147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 1088147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 1089147191Sjkoshy __K8MASK(invalid, 0), 1090147191Sjkoshy __K8MASK(shared, 1), 1091147191Sjkoshy __K8MASK(exclusive, 2), 1092147191Sjkoshy __K8MASK(owner, 3), 1093147191Sjkoshy __K8MASK(modified, 4), 1094147191Sjkoshy NULLMASK 1095147191Sjkoshy}; 1096147191Sjkoshy 1097147191Sjkoshy/* dc one bit ecc error */ 1098147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 1099147191Sjkoshy __K8MASK(scrubber, 0), 1100147191Sjkoshy __K8MASK(piggyback, 1), 1101147191Sjkoshy NULLMASK 1102147191Sjkoshy}; 1103147191Sjkoshy 1104147191Sjkoshy/* dc dispatched prefetch instructions */ 1105147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 1106147191Sjkoshy __K8MASK(load, 0), 1107147191Sjkoshy __K8MASK(store, 1), 1108147191Sjkoshy __K8MASK(nta, 2), 1109147191Sjkoshy NULLMASK 1110147191Sjkoshy}; 1111147191Sjkoshy 1112147191Sjkoshy/* dc dcache accesses by locks */ 1113147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1114147191Sjkoshy __K8MASK(accesses, 0), 1115147191Sjkoshy __K8MASK(misses, 1), 1116147191Sjkoshy NULLMASK 1117147191Sjkoshy}; 1118147191Sjkoshy 1119147191Sjkoshy/* bu internal l2 request */ 1120147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1121147191Sjkoshy __K8MASK(ic-fill, 0), 1122147191Sjkoshy __K8MASK(dc-fill, 1), 1123147191Sjkoshy __K8MASK(tlb-reload, 2), 1124147191Sjkoshy __K8MASK(tag-snoop, 3), 1125147191Sjkoshy __K8MASK(cancelled, 4), 1126147191Sjkoshy NULLMASK 1127147191Sjkoshy}; 1128147191Sjkoshy 1129147191Sjkoshy/* bu fill request l2 miss */ 1130147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1131147191Sjkoshy __K8MASK(ic-fill, 0), 1132147191Sjkoshy __K8MASK(dc-fill, 1), 1133147191Sjkoshy __K8MASK(tlb-reload, 2), 1134147191Sjkoshy NULLMASK 1135147191Sjkoshy}; 1136147191Sjkoshy 1137147191Sjkoshy/* bu fill into l2 */ 1138147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1139147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 1140147191Sjkoshy __K8MASK(victim-from-l2, 1), 1141147191Sjkoshy NULLMASK 1142147191Sjkoshy}; 1143147191Sjkoshy 1144147191Sjkoshy/* fr retired fpu instructions */ 1145147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1146147191Sjkoshy __K8MASK(x87, 0), 1147147191Sjkoshy __K8MASK(mmx-3dnow, 1), 1148147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 1149147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1150147191Sjkoshy NULLMASK 1151147191Sjkoshy}; 1152147191Sjkoshy 1153147191Sjkoshy/* fr retired fastpath double op instructions */ 1154147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1155147191Sjkoshy __K8MASK(low-op-pos-0, 0), 1156147191Sjkoshy __K8MASK(low-op-pos-1, 1), 1157147191Sjkoshy __K8MASK(low-op-pos-2, 2), 1158147191Sjkoshy NULLMASK 1159147191Sjkoshy}; 1160147191Sjkoshy 1161147191Sjkoshy/* fr fpu exceptions */ 1162147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1163147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1164147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1165147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1166147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1167147191Sjkoshy NULLMASK 1168147191Sjkoshy}; 1169147191Sjkoshy 1170147191Sjkoshy/* nb memory controller page access event */ 1171147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1172147191Sjkoshy __K8MASK(page-hit, 0), 1173147191Sjkoshy __K8MASK(page-miss, 1), 1174147191Sjkoshy __K8MASK(page-conflict, 2), 1175147191Sjkoshy NULLMASK 1176147191Sjkoshy}; 1177147191Sjkoshy 1178147191Sjkoshy/* nb memory controller turnaround */ 1179147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1180147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1181147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1182147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1183147191Sjkoshy NULLMASK 1184147191Sjkoshy}; 1185147191Sjkoshy 1186147191Sjkoshy/* nb memory controller bypass saturation */ 1187147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1188147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1189147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1190147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1191147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1192147191Sjkoshy NULLMASK 1193147191Sjkoshy}; 1194147191Sjkoshy 1195147191Sjkoshy/* nb sized commands */ 1196147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1197147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1198147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1199147191Sjkoshy __K8MASK(postwrszbyte, 2), 1200147191Sjkoshy __K8MASK(postwrszdword, 3), 1201147191Sjkoshy __K8MASK(rdszbyte, 4), 1202147191Sjkoshy __K8MASK(rdszdword, 5), 1203147191Sjkoshy __K8MASK(rdmodwr, 6), 1204147191Sjkoshy NULLMASK 1205147191Sjkoshy}; 1206147191Sjkoshy 1207147191Sjkoshy/* nb probe result */ 1208147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1209147191Sjkoshy __K8MASK(probe-miss, 0), 1210147191Sjkoshy __K8MASK(probe-hit, 1), 1211147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1212147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1213147191Sjkoshy NULLMASK 1214147191Sjkoshy}; 1215147191Sjkoshy 1216147191Sjkoshy/* nb hypertransport bus bandwidth */ 1217147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1218147191Sjkoshy __K8MASK(command, 0), 1219183107Sjkoshy __K8MASK(data, 1), 1220147191Sjkoshy __K8MASK(buffer-release, 2), 1221147191Sjkoshy __K8MASK(nop, 3), 1222147191Sjkoshy NULLMASK 1223147191Sjkoshy}; 1224147191Sjkoshy 1225147191Sjkoshy#undef __K8MASK 1226147191Sjkoshy 1227147191Sjkoshy#define K8_KW_COUNT "count" 1228147191Sjkoshy#define K8_KW_EDGE "edge" 1229147191Sjkoshy#define K8_KW_INV "inv" 1230147191Sjkoshy#define K8_KW_MASK "mask" 1231147191Sjkoshy#define K8_KW_OS "os" 1232147191Sjkoshy#define K8_KW_USR "usr" 1233147191Sjkoshy 1234147191Sjkoshystatic int 1235147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1236147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1237147191Sjkoshy{ 1238183107Sjkoshy char *e, *p, *q; 1239183107Sjkoshy int n; 1240240164Sfabient uint32_t count; 1241240164Sfabient uint64_t evmask; 1242147191Sjkoshy const struct pmc_masks *pm, *pmask; 1243147191Sjkoshy 1244183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1245147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1246147191Sjkoshy 1247147191Sjkoshy pmask = NULL; 1248147191Sjkoshy evmask = 0; 1249147191Sjkoshy 1250147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1251147191Sjkoshy 1252147191Sjkoshy /* setup parsing tables */ 1253147191Sjkoshy switch (pe) { 1254147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1255147191Sjkoshy __K8SETMASK(fdfo); 1256147191Sjkoshy break; 1257147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1258147191Sjkoshy __K8SETMASK(lsrl); 1259147191Sjkoshy break; 1260147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1261147191Sjkoshy __K8SETMASK(llo); 1262147191Sjkoshy break; 1263147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1264147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1265147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1266147191Sjkoshy __K8SETMASK(dc); 1267147191Sjkoshy break; 1268147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1269147191Sjkoshy __K8SETMASK(dobee); 1270147191Sjkoshy break; 1271147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1272147191Sjkoshy __K8SETMASK(ddpi); 1273147191Sjkoshy break; 1274147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1275147191Sjkoshy __K8SETMASK(dabl); 1276147191Sjkoshy break; 1277147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1278147191Sjkoshy __K8SETMASK(bilr); 1279147191Sjkoshy break; 1280147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1281147191Sjkoshy __K8SETMASK(bfrlm); 1282147191Sjkoshy break; 1283147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1284147191Sjkoshy __K8SETMASK(bfil); 1285147191Sjkoshy break; 1286147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1287147191Sjkoshy __K8SETMASK(frfi); 1288147191Sjkoshy break; 1289147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1290147191Sjkoshy __K8SETMASK(frfdoi); 1291147191Sjkoshy break; 1292147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1293147191Sjkoshy __K8SETMASK(ffe); 1294147191Sjkoshy break; 1295147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1296147191Sjkoshy __K8SETMASK(nmcpae); 1297147191Sjkoshy break; 1298147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1299147191Sjkoshy __K8SETMASK(nmct); 1300147191Sjkoshy break; 1301147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1302147191Sjkoshy __K8SETMASK(nmcbs); 1303147191Sjkoshy break; 1304147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1305147191Sjkoshy __K8SETMASK(nsc); 1306147191Sjkoshy break; 1307147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1308147191Sjkoshy __K8SETMASK(npr); 1309147191Sjkoshy break; 1310147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1311147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1312147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1313147191Sjkoshy __K8SETMASK(nhbb); 1314147191Sjkoshy break; 1315147191Sjkoshy 1316147191Sjkoshy default: 1317147191Sjkoshy break; /* no options defined */ 1318147191Sjkoshy } 1319147191Sjkoshy 1320147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1321147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1322147191Sjkoshy q = strchr(p, '='); 1323147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1324174406Sjkoshy return (-1); 1325147191Sjkoshy 1326147191Sjkoshy count = strtol(q, &e, 0); 1327147191Sjkoshy if (e == q || *e != '\0') 1328174406Sjkoshy return (-1); 1329147191Sjkoshy 1330147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1331147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1332147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1333147191Sjkoshy 1334147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1335147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1336147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1337147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1338147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1339147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1340174406Sjkoshy return (-1); 1341147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1342147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1343147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1344147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1345147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1346147191Sjkoshy } else 1347174406Sjkoshy return (-1); 1348147191Sjkoshy } 1349147191Sjkoshy 1350147191Sjkoshy /* other post processing */ 1351147191Sjkoshy switch (pe) { 1352147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1353147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1354147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1355147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1356147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1357147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1358147191Sjkoshy /* XXX only available in rev B and later */ 1359147191Sjkoshy break; 1360147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1361147191Sjkoshy /* XXX only available in rev C and later */ 1362147191Sjkoshy break; 1363147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1364147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1365147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1366174406Sjkoshy return (-1); 1367147191Sjkoshy if (evmask == 0) { 1368147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1369147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1370147191Sjkoshy } 1371147191Sjkoshy break; 1372147191Sjkoshy default: 1373147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1374147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1375147191Sjkoshy evmask |= pm->pm_value; 1376147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1377147191Sjkoshy } 1378147191Sjkoshy } 1379147191Sjkoshy 1380147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1381147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1382147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1383147191Sjkoshy 1384174406Sjkoshy return (0); 1385147191Sjkoshy} 1386147191Sjkoshy 1387147191Sjkoshy#endif 1388147191Sjkoshy 1389147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1390147191Sjkoshy 1391147191Sjkoshy/* 1392145256Sjkoshy * Intel P4 PMCs 1393145256Sjkoshy */ 1394145256Sjkoshy 1395145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1396145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1397145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1398145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1399145351Sjkoshy EV_ALIAS("instructions", 1400145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1401155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1402145256Sjkoshy EV_ALIAS(NULL, NULL) 1403145256Sjkoshy}; 1404145256Sjkoshy 1405145256Sjkoshy#define P4_KW_ACTIVE "active" 1406145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1407145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1408145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1409145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1410145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1411145256Sjkoshy#define P4_KW_CASCADE "cascade" 1412145256Sjkoshy#define P4_KW_EDGE "edge" 1413145256Sjkoshy#define P4_KW_INV "complement" 1414145256Sjkoshy#define P4_KW_OS "os" 1415145256Sjkoshy#define P4_KW_MASK "mask" 1416145256Sjkoshy#define P4_KW_PRECISE "precise" 1417145256Sjkoshy#define P4_KW_TAG "tag" 1418145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1419145256Sjkoshy#define P4_KW_USR "usr" 1420145256Sjkoshy 1421145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1422145256Sjkoshy 1423145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1424145256Sjkoshy __P4MASK(dd, 0), 1425145256Sjkoshy __P4MASK(db, 1), 1426145256Sjkoshy __P4MASK(di, 2), 1427145256Sjkoshy __P4MASK(bd, 3), 1428145256Sjkoshy __P4MASK(bb, 4), 1429145256Sjkoshy __P4MASK(bi, 5), 1430145256Sjkoshy __P4MASK(id, 6), 1431145256Sjkoshy __P4MASK(ib, 7), 1432145256Sjkoshy NULLMASK 1433145256Sjkoshy}; 1434145256Sjkoshy 1435145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1436145256Sjkoshy __P4MASK(tcmiss, 0), 1437145256Sjkoshy NULLMASK, 1438145256Sjkoshy}; 1439145256Sjkoshy 1440145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1441145256Sjkoshy __P4MASK(hit, 0), 1442145256Sjkoshy __P4MASK(miss, 1), 1443145256Sjkoshy __P4MASK(hit-uc, 2), 1444145256Sjkoshy NULLMASK 1445145256Sjkoshy}; 1446145256Sjkoshy 1447145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1448145256Sjkoshy __P4MASK(st-rb-full, 2), 1449145256Sjkoshy __P4MASK(64k-conf, 3), 1450145256Sjkoshy NULLMASK 1451145256Sjkoshy}; 1452145256Sjkoshy 1453145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1454145256Sjkoshy __P4MASK(lsc, 0), 1455145256Sjkoshy __P4MASK(ssc, 1), 1456145256Sjkoshy NULLMASK 1457145256Sjkoshy}; 1458145256Sjkoshy 1459145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1460145256Sjkoshy __P4MASK(split-ld, 1), 1461145256Sjkoshy NULLMASK 1462145256Sjkoshy}; 1463145256Sjkoshy 1464145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1465145256Sjkoshy __P4MASK(split-st, 1), 1466145256Sjkoshy NULLMASK 1467145256Sjkoshy}; 1468145256Sjkoshy 1469145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1470145256Sjkoshy __P4MASK(no-sta, 1), 1471145256Sjkoshy __P4MASK(no-std, 3), 1472145256Sjkoshy __P4MASK(partial-data, 4), 1473145256Sjkoshy __P4MASK(unalgn-addr, 5), 1474145256Sjkoshy NULLMASK 1475145256Sjkoshy}; 1476145256Sjkoshy 1477145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1478145256Sjkoshy __P4MASK(dtmiss, 0), 1479145256Sjkoshy __P4MASK(itmiss, 1), 1480145256Sjkoshy NULLMASK 1481145256Sjkoshy}; 1482145256Sjkoshy 1483145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1484145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1485145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1486145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1487145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1488145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1489145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1490145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1491145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1492145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1493145256Sjkoshy NULLMASK 1494145256Sjkoshy}; 1495145256Sjkoshy 1496145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1497145256Sjkoshy __P4MASK(all-read, 5), 1498145256Sjkoshy __P4MASK(all-write, 6), 1499145256Sjkoshy __P4MASK(mem-uc, 7), 1500145256Sjkoshy __P4MASK(mem-wc, 8), 1501145256Sjkoshy __P4MASK(mem-wt, 9), 1502145256Sjkoshy __P4MASK(mem-wp, 10), 1503145256Sjkoshy __P4MASK(mem-wb, 11), 1504145256Sjkoshy __P4MASK(own, 13), 1505145256Sjkoshy __P4MASK(other, 14), 1506145256Sjkoshy __P4MASK(prefetch, 15), 1507145256Sjkoshy NULLMASK 1508145256Sjkoshy}; 1509145256Sjkoshy 1510145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1511145256Sjkoshy __P4MASK(all-read, 5), 1512145256Sjkoshy __P4MASK(all-write, 6), 1513145256Sjkoshy __P4MASK(mem-uc, 7), 1514145256Sjkoshy __P4MASK(mem-wc, 8), 1515145256Sjkoshy __P4MASK(mem-wt, 9), 1516145256Sjkoshy __P4MASK(mem-wp, 10), 1517145256Sjkoshy __P4MASK(mem-wb, 11), 1518145256Sjkoshy __P4MASK(own, 13), 1519145256Sjkoshy __P4MASK(other, 14), 1520145256Sjkoshy __P4MASK(prefetch, 15), 1521145256Sjkoshy NULLMASK 1522145256Sjkoshy}; 1523145256Sjkoshy 1524145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1525145256Sjkoshy __P4MASK(drdy-drv, 0), 1526145256Sjkoshy __P4MASK(drdy-own, 1), 1527145256Sjkoshy __P4MASK(drdy-other, 2), 1528145256Sjkoshy __P4MASK(dbsy-drv, 3), 1529145256Sjkoshy __P4MASK(dbsy-own, 4), 1530145256Sjkoshy __P4MASK(dbsy-other, 5), 1531145256Sjkoshy NULLMASK 1532145256Sjkoshy}; 1533145256Sjkoshy 1534145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1535145256Sjkoshy __P4MASK(req-type0, 0), 1536145256Sjkoshy __P4MASK(req-type1, 1), 1537145256Sjkoshy __P4MASK(req-len0, 2), 1538145256Sjkoshy __P4MASK(req-len1, 3), 1539145256Sjkoshy __P4MASK(req-io-type, 5), 1540145256Sjkoshy __P4MASK(req-lock-type, 6), 1541145256Sjkoshy __P4MASK(req-cache-type, 7), 1542145256Sjkoshy __P4MASK(req-split-type, 8), 1543145256Sjkoshy __P4MASK(req-dem-type, 9), 1544145256Sjkoshy __P4MASK(req-ord-type, 10), 1545145256Sjkoshy __P4MASK(mem-type0, 11), 1546145256Sjkoshy __P4MASK(mem-type1, 12), 1547145256Sjkoshy __P4MASK(mem-type2, 13), 1548145256Sjkoshy NULLMASK 1549145256Sjkoshy}; 1550145256Sjkoshy 1551145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1552145256Sjkoshy __P4MASK(all, 15), 1553145256Sjkoshy NULLMASK 1554145256Sjkoshy}; 1555145256Sjkoshy 1556145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1557145256Sjkoshy __P4MASK(all, 15), 1558145256Sjkoshy NULLMASK 1559145256Sjkoshy}; 1560145256Sjkoshy 1561145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1562145256Sjkoshy __P4MASK(all, 15), 1563145256Sjkoshy NULLMASK 1564145256Sjkoshy}; 1565145256Sjkoshy 1566145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1567145256Sjkoshy __P4MASK(all, 15), 1568145256Sjkoshy NULLMASK 1569145256Sjkoshy}; 1570145256Sjkoshy 1571145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1572145256Sjkoshy __P4MASK(all, 15), 1573145256Sjkoshy NULLMASK 1574145256Sjkoshy}; 1575145256Sjkoshy 1576145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1577145256Sjkoshy __P4MASK(all, 15), 1578145256Sjkoshy NULLMASK 1579145256Sjkoshy}; 1580145256Sjkoshy 1581145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1582145256Sjkoshy __P4MASK(all, 15), 1583145256Sjkoshy NULLMASK 1584145256Sjkoshy}; 1585145256Sjkoshy 1586145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1587145256Sjkoshy __P4MASK(all, 15), 1588145256Sjkoshy NULLMASK 1589145256Sjkoshy}; 1590145256Sjkoshy 1591145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1592145256Sjkoshy __P4MASK(allp0, 3), 1593145256Sjkoshy __P4MASK(allp2, 4), 1594145256Sjkoshy NULLMASK 1595145256Sjkoshy}; 1596145256Sjkoshy 1597145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1598145256Sjkoshy __P4MASK(running, 0), 1599145256Sjkoshy NULLMASK 1600145256Sjkoshy}; 1601145256Sjkoshy 1602145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1603145256Sjkoshy __P4MASK(cisc, 0), 1604145256Sjkoshy NULLMASK 1605145256Sjkoshy}; 1606145256Sjkoshy 1607145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1608145256Sjkoshy __P4MASK(from-tc-build, 0), 1609145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1610145256Sjkoshy __P4MASK(from-rom, 2), 1611145256Sjkoshy NULLMASK 1612145256Sjkoshy}; 1613145256Sjkoshy 1614145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1615145351Sjkoshy /* retired mispred branch type */ 1616145256Sjkoshy __P4MASK(conditional, 1), 1617145256Sjkoshy __P4MASK(call, 2), 1618145256Sjkoshy __P4MASK(return, 3), 1619145256Sjkoshy __P4MASK(indirect, 4), 1620145256Sjkoshy NULLMASK 1621145256Sjkoshy}; 1622145256Sjkoshy 1623145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1624145256Sjkoshy __P4MASK(conditional, 1), 1625145256Sjkoshy __P4MASK(call, 2), 1626145256Sjkoshy __P4MASK(retired, 3), 1627145256Sjkoshy __P4MASK(indirect, 4), 1628145256Sjkoshy NULLMASK 1629145256Sjkoshy}; 1630145256Sjkoshy 1631145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1632145256Sjkoshy __P4MASK(sbfull, 5), 1633145256Sjkoshy NULLMASK 1634145256Sjkoshy}; 1635145256Sjkoshy 1636145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1637145256Sjkoshy __P4MASK(wcb-evicts, 0), 1638145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1639145256Sjkoshy NULLMASK 1640145256Sjkoshy}; 1641145256Sjkoshy 1642145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1643145256Sjkoshy __P4MASK(nbogus, 0), 1644145256Sjkoshy __P4MASK(bogus, 1), 1645145256Sjkoshy NULLMASK 1646145256Sjkoshy}; 1647145256Sjkoshy 1648145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1649145256Sjkoshy __P4MASK(nbogus0, 0), 1650145256Sjkoshy __P4MASK(nbogus1, 1), 1651145256Sjkoshy __P4MASK(nbogus2, 2), 1652145256Sjkoshy __P4MASK(nbogus3, 3), 1653145256Sjkoshy __P4MASK(bogus0, 4), 1654145256Sjkoshy __P4MASK(bogus1, 5), 1655145256Sjkoshy __P4MASK(bogus2, 6), 1656145256Sjkoshy __P4MASK(bogus3, 7), 1657145256Sjkoshy NULLMASK 1658145256Sjkoshy}; 1659145256Sjkoshy 1660145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1661145256Sjkoshy __P4MASK(nbogus, 0), 1662145256Sjkoshy __P4MASK(bogus, 1), 1663145256Sjkoshy NULLMASK 1664145256Sjkoshy}; 1665145256Sjkoshy 1666145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1667145256Sjkoshy __P4MASK(nbogusntag, 0), 1668145256Sjkoshy __P4MASK(nbogustag, 1), 1669145256Sjkoshy __P4MASK(bogusntag, 2), 1670145256Sjkoshy __P4MASK(bogustag, 3), 1671145256Sjkoshy NULLMASK 1672145256Sjkoshy}; 1673145256Sjkoshy 1674145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1675145256Sjkoshy __P4MASK(nbogus, 0), 1676145256Sjkoshy __P4MASK(bogus, 1), 1677145256Sjkoshy NULLMASK 1678145256Sjkoshy}; 1679145256Sjkoshy 1680145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1681145256Sjkoshy __P4MASK(tagloads, 1), 1682145256Sjkoshy __P4MASK(tagstores, 2), 1683145256Sjkoshy NULLMASK 1684145256Sjkoshy}; 1685145256Sjkoshy 1686145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1687145256Sjkoshy __P4MASK(mmnp, 0), 1688145256Sjkoshy __P4MASK(mmnm, 1), 1689145256Sjkoshy __P4MASK(mmtp, 2), 1690145256Sjkoshy __P4MASK(mmtm, 3), 1691145256Sjkoshy NULLMASK 1692145256Sjkoshy}; 1693145256Sjkoshy 1694145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1695145256Sjkoshy __P4MASK(nbogus, 0), 1696145256Sjkoshy NULLMASK 1697145256Sjkoshy}; 1698145256Sjkoshy 1699145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1700145256Sjkoshy __P4MASK(fpsu, 0), 1701145256Sjkoshy __P4MASK(fpso, 1), 1702145256Sjkoshy __P4MASK(poao, 2), 1703145256Sjkoshy __P4MASK(poau, 3), 1704145256Sjkoshy __P4MASK(prea, 4), 1705145256Sjkoshy NULLMASK 1706145256Sjkoshy}; 1707145256Sjkoshy 1708145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1709145256Sjkoshy __P4MASK(clear, 0), 1710145256Sjkoshy __P4MASK(moclear, 2), 1711145256Sjkoshy __P4MASK(smclear, 3), 1712145256Sjkoshy NULLMASK 1713145256Sjkoshy}; 1714145256Sjkoshy 1715145256Sjkoshy/* P4 event parser */ 1716145256Sjkoshystatic int 1717145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1718145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1719145256Sjkoshy{ 1720145256Sjkoshy 1721145256Sjkoshy char *e, *p, *q; 1722145256Sjkoshy int count, has_tag, has_busreqtype, n; 1723240164Sfabient uint32_t cccractivemask; 1724240164Sfabient uint64_t evmask; 1725145256Sjkoshy const struct pmc_masks *pm, *pmask; 1726145256Sjkoshy 1727183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1728147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1729147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1730145256Sjkoshy 1731145256Sjkoshy pmask = NULL; 1732145256Sjkoshy evmask = 0; 1733145256Sjkoshy cccractivemask = 0x3; 1734145256Sjkoshy has_tag = has_busreqtype = 0; 1735145256Sjkoshy 1736145256Sjkoshy#define __P4SETMASK(M) do { \ 1737183107Sjkoshy pmask = p4_mask_##M; \ 1738145256Sjkoshy} while (0) 1739145256Sjkoshy 1740145256Sjkoshy switch (pe) { 1741145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1742145256Sjkoshy __P4SETMASK(tcdm); 1743145256Sjkoshy break; 1744145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1745145256Sjkoshy __P4SETMASK(bfr); 1746145256Sjkoshy break; 1747145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1748145256Sjkoshy __P4SETMASK(ir); 1749145256Sjkoshy break; 1750145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1751145256Sjkoshy __P4SETMASK(memcan); 1752145256Sjkoshy break; 1753145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1754145256Sjkoshy __P4SETMASK(memcomp); 1755145256Sjkoshy break; 1756145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1757145256Sjkoshy __P4SETMASK(lpr); 1758145256Sjkoshy break; 1759145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1760145256Sjkoshy __P4SETMASK(spr); 1761145256Sjkoshy break; 1762145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1763145256Sjkoshy __P4SETMASK(mlr); 1764145256Sjkoshy break; 1765145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1766145256Sjkoshy __P4SETMASK(pwt); 1767145256Sjkoshy break; 1768145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1769145256Sjkoshy __P4SETMASK(bcr); 1770145256Sjkoshy break; 1771145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1772145256Sjkoshy __P4SETMASK(ia); 1773145256Sjkoshy has_busreqtype = 1; 1774145256Sjkoshy break; 1775145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1776145256Sjkoshy __P4SETMASK(iae); 1777145256Sjkoshy has_busreqtype = 1; 1778145256Sjkoshy break; 1779145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1780145256Sjkoshy __P4SETMASK(fda); 1781145256Sjkoshy break; 1782145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1783145256Sjkoshy __P4SETMASK(ba); 1784145256Sjkoshy break; 1785145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1786145256Sjkoshy __P4SETMASK(sia); 1787145256Sjkoshy break; 1788145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1789145256Sjkoshy __P4SETMASK(psu); 1790145256Sjkoshy break; 1791145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1792145256Sjkoshy __P4SETMASK(pdu); 1793145256Sjkoshy break; 1794145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1795145256Sjkoshy __P4SETMASK(ssu); 1796145256Sjkoshy break; 1797145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1798145256Sjkoshy __P4SETMASK(sdu); 1799145256Sjkoshy break; 1800145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1801145256Sjkoshy __P4SETMASK(64bmu); 1802145256Sjkoshy break; 1803145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1804145256Sjkoshy __P4SETMASK(128bmu); 1805145256Sjkoshy break; 1806145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1807145256Sjkoshy __P4SETMASK(xfu); 1808145256Sjkoshy break; 1809145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1810145256Sjkoshy __P4SETMASK(xsmu); 1811145256Sjkoshy break; 1812145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1813145256Sjkoshy __P4SETMASK(gpe); 1814145256Sjkoshy break; 1815145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1816145256Sjkoshy __P4SETMASK(tmx); 1817145256Sjkoshy break; 1818145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1819145256Sjkoshy __P4SETMASK(uqw); 1820145256Sjkoshy break; 1821145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1822145256Sjkoshy __P4SETMASK(rmbt); 1823145256Sjkoshy break; 1824145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1825145256Sjkoshy __P4SETMASK(rbt); 1826145256Sjkoshy break; 1827145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1828145256Sjkoshy __P4SETMASK(rs); 1829145256Sjkoshy break; 1830145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1831145256Sjkoshy __P4SETMASK(wb); 1832145256Sjkoshy break; 1833145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1834145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1835145256Sjkoshy case PMC_EV_P4_BNR: 1836145256Sjkoshy case PMC_EV_P4_SNOOP: 1837145256Sjkoshy case PMC_EV_P4_RESPONSE: 1838145256Sjkoshy break; 1839145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1840145256Sjkoshy __P4SETMASK(fee); 1841145256Sjkoshy break; 1842145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1843145256Sjkoshy __P4SETMASK(ee); 1844145256Sjkoshy break; 1845145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1846145256Sjkoshy __P4SETMASK(re); 1847145256Sjkoshy break; 1848145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1849145256Sjkoshy __P4SETMASK(insret); 1850145256Sjkoshy break; 1851145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1852145256Sjkoshy __P4SETMASK(ur); 1853145256Sjkoshy break; 1854145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1855145256Sjkoshy __P4SETMASK(ut); 1856145256Sjkoshy break; 1857145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1858145256Sjkoshy __P4SETMASK(br); 1859145256Sjkoshy break; 1860145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1861145256Sjkoshy __P4SETMASK(mbr); 1862145256Sjkoshy break; 1863145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1864145256Sjkoshy __P4SETMASK(xa); 1865145256Sjkoshy break; 1866145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1867145256Sjkoshy __P4SETMASK(machclr); 1868145256Sjkoshy break; 1869145256Sjkoshy default: 1870174406Sjkoshy return (-1); 1871145256Sjkoshy } 1872145256Sjkoshy 1873145256Sjkoshy /* process additional flags */ 1874145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1875145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1876145256Sjkoshy q = strchr(p, '='); 1877145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1878174406Sjkoshy return (-1); 1879145256Sjkoshy 1880183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1881145256Sjkoshy cccractivemask = 0x0; 1882183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1883145256Sjkoshy cccractivemask = 0x1; 1884183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1885145256Sjkoshy cccractivemask = 0x2; 1886183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1887145256Sjkoshy cccractivemask = 0x3; 1888145256Sjkoshy else 1889174406Sjkoshy return (-1); 1890145256Sjkoshy 1891145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1892145256Sjkoshy if (has_busreqtype == 0) 1893174406Sjkoshy return (-1); 1894145256Sjkoshy 1895145256Sjkoshy q = strchr(p, '='); 1896145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1897174406Sjkoshy return (-1); 1898145256Sjkoshy 1899145256Sjkoshy count = strtol(q, &e, 0); 1900145256Sjkoshy if (e == q || *e != '\0') 1901174406Sjkoshy return (-1); 1902145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1903145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1904145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1905145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1906145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1907145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1908145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1909145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1910145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1911174406Sjkoshy return (-1); 1912145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1913145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1914145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1915145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1916145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1917145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1918145256Sjkoshy if (has_tag == 0) 1919174406Sjkoshy return (-1); 1920145256Sjkoshy 1921145256Sjkoshy q = strchr(p, '='); 1922145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1923174406Sjkoshy return (-1); 1924145256Sjkoshy 1925145256Sjkoshy count = strtol(q, &e, 0); 1926145256Sjkoshy if (e == q || *e != '\0') 1927174406Sjkoshy return (-1); 1928145256Sjkoshy 1929145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1930147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1931145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1932145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1933145256Sjkoshy q = strchr(p, '='); 1934145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1935174406Sjkoshy return (-1); 1936145256Sjkoshy 1937145256Sjkoshy count = strtol(q, &e, 0); 1938145256Sjkoshy if (e == q || *e != '\0') 1939174406Sjkoshy return (-1); 1940145256Sjkoshy 1941145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1942147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1943147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1944147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1945147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1946145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1947145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1948145256Sjkoshy else 1949174406Sjkoshy return (-1); 1950145256Sjkoshy } 1951145256Sjkoshy 1952145256Sjkoshy /* other post processing */ 1953145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1954145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1955145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1956145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1957145256Sjkoshy 1958145256Sjkoshy /* fill in thread activity mask */ 1959147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1960145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1961145256Sjkoshy 1962145256Sjkoshy if (evmask) 1963145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1964145256Sjkoshy 1965145256Sjkoshy switch (pe) { 1966145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1967145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1968145256Sjkoshy (evmask & 0x18) == 0x18) 1969174406Sjkoshy return (-1); /* can't have own+other bits together */ 1970145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1971145256Sjkoshy evmask = 0x1D; 1972145256Sjkoshy break; 1973145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1974145256Sjkoshy /* only one bit is allowed to be set */ 1975145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1976174406Sjkoshy return (-1); 1977145256Sjkoshy if (evmask == 0) { 1978183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1979145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1980145256Sjkoshy } 1981145256Sjkoshy break; 1982145256Sjkoshy default: 1983145256Sjkoshy if (evmask == 0 && pmask) { 1984145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1985145256Sjkoshy evmask |= pm->pm_value; 1986145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1987145256Sjkoshy } 1988145256Sjkoshy } 1989145256Sjkoshy 1990147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1991147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1992145256Sjkoshy 1993174406Sjkoshy return (0); 1994145256Sjkoshy} 1995145256Sjkoshy 1996147759Sjkoshy#endif 1997147759Sjkoshy 1998147759Sjkoshy#if defined(__i386__) 1999147759Sjkoshy 2000145256Sjkoshy/* 2001147191Sjkoshy * Pentium style PMCs 2002147191Sjkoshy */ 2003147191Sjkoshy 2004147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 2005183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 2006183105Sjkoshy EV_ALIAS("cycles", "tsc"), 2007183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 2008183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 2009183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 2010183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 2011183105Sjkoshy EV_ALIAS("unhalted-cycles", 2012183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 2013147191Sjkoshy EV_ALIAS(NULL, NULL) 2014147191Sjkoshy}; 2015147191Sjkoshy 2016147191Sjkoshystatic int 2017147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 2018147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2019147191Sjkoshy{ 2020174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 2021147191Sjkoshy} 2022147191Sjkoshy 2023147191Sjkoshy/* 2024145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 2025145256Sjkoshy * and Pentium M CPUs. 2026145256Sjkoshy */ 2027145256Sjkoshy 2028145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 2029145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 2030145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 2031145351Sjkoshy EV_ALIAS("cycles", "tsc"), 2032145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 2033168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 2034145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 2035145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 2036155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 2037145351Sjkoshy EV_ALIAS(NULL, NULL) 2038145256Sjkoshy}; 2039145256Sjkoshy 2040145256Sjkoshy#define P6_KW_CMASK "cmask" 2041145256Sjkoshy#define P6_KW_EDGE "edge" 2042145256Sjkoshy#define P6_KW_INV "inv" 2043145256Sjkoshy#define P6_KW_OS "os" 2044145256Sjkoshy#define P6_KW_UMASK "umask" 2045145256Sjkoshy#define P6_KW_USR "usr" 2046145256Sjkoshy 2047145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 2048145256Sjkoshy PMCMASK(m, 0x01), 2049145256Sjkoshy PMCMASK(e, 0x02), 2050145256Sjkoshy PMCMASK(s, 0x04), 2051145256Sjkoshy PMCMASK(i, 0x08), 2052145256Sjkoshy NULLMASK 2053145256Sjkoshy}; 2054145256Sjkoshy 2055145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 2056145256Sjkoshy PMCMASK(m, 0x01), 2057145256Sjkoshy PMCMASK(e, 0x02), 2058145256Sjkoshy PMCMASK(s, 0x04), 2059145256Sjkoshy PMCMASK(i, 0x08), 2060145256Sjkoshy PMCMASK(nonhw, 0x00), 2061145256Sjkoshy PMCMASK(hw, 0x10), 2062145256Sjkoshy PMCMASK(both, 0x30), 2063145256Sjkoshy NULLMASK 2064145256Sjkoshy}; 2065145256Sjkoshy 2066145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 2067145256Sjkoshy PMCMASK(nonhw, 0x00), 2068145256Sjkoshy PMCMASK(hw, 0x10), 2069145256Sjkoshy PMCMASK(both, 0x30), 2070145256Sjkoshy NULLMASK 2071145256Sjkoshy}; 2072145256Sjkoshy 2073145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 2074145256Sjkoshy PMCMASK(self, 0x00), 2075145256Sjkoshy PMCMASK(any, 0x20), 2076145256Sjkoshy NULLMASK 2077145256Sjkoshy}; 2078145256Sjkoshy 2079145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 2080145256Sjkoshy PMCMASK(nta, 0x00), 2081145256Sjkoshy PMCMASK(t1, 0x01), 2082145256Sjkoshy PMCMASK(t2, 0x02), 2083145256Sjkoshy PMCMASK(wos, 0x03), 2084145256Sjkoshy NULLMASK 2085145256Sjkoshy}; 2086145256Sjkoshy 2087145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 2088145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 2089145256Sjkoshy PMCMASK(scalar, 0x01), 2090145256Sjkoshy NULLMASK 2091145256Sjkoshy}; 2092145256Sjkoshy 2093145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 2094145256Sjkoshy PMCMASK(packed-multiply, 0x01), 2095145256Sjkoshy PMCMASK(packed-shift, 0x02), 2096145256Sjkoshy PMCMASK(pack, 0x04), 2097145256Sjkoshy PMCMASK(unpack, 0x08), 2098145256Sjkoshy PMCMASK(packed-logical, 0x10), 2099145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 2100145256Sjkoshy NULLMASK 2101145256Sjkoshy}; 2102145256Sjkoshy 2103145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 2104145256Sjkoshy PMCMASK(mmxtofp, 0x00), 2105145256Sjkoshy PMCMASK(fptommx, 0x01), 2106145256Sjkoshy NULLMASK 2107145256Sjkoshy}; 2108145256Sjkoshy 2109145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 2110145256Sjkoshy PMCMASK(es, 0x01), 2111145256Sjkoshy PMCMASK(ds, 0x02), 2112145256Sjkoshy PMCMASK(fs, 0x04), 2113145256Sjkoshy PMCMASK(gs, 0x08), 2114145256Sjkoshy NULLMASK 2115145256Sjkoshy}; 2116145256Sjkoshy 2117145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 2118145256Sjkoshy PMCMASK(all, 0x00), 2119145256Sjkoshy PMCMASK(freq, 0x02), 2120145256Sjkoshy NULLMASK 2121145256Sjkoshy}; 2122145256Sjkoshy 2123145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 2124145256Sjkoshy PMCMASK(all, 0x00), 2125145256Sjkoshy PMCMASK(loadop, 0x01), 2126145256Sjkoshy PMCMASK(stdsta, 0x02), 2127145256Sjkoshy NULLMASK 2128145256Sjkoshy}; 2129145256Sjkoshy 2130145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 2131145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2132145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 2133145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2134145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2135145256Sjkoshy NULLMASK 2136145256Sjkoshy}; 2137145256Sjkoshy 2138145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 2139145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2140145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 2141145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2142145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2143145256Sjkoshy NULLMASK 2144145256Sjkoshy}; 2145145256Sjkoshy 2146145256Sjkoshy/* P6 event parser */ 2147145256Sjkoshystatic int 2148145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 2149145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2150145256Sjkoshy{ 2151145256Sjkoshy char *e, *p, *q; 2152240164Sfabient uint64_t evmask; 2153145256Sjkoshy int count, n; 2154145256Sjkoshy const struct pmc_masks *pm, *pmask; 2155145256Sjkoshy 2156183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2157147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 2158145256Sjkoshy 2159145256Sjkoshy evmask = 0; 2160145256Sjkoshy 2161145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 2162145256Sjkoshy 2163145256Sjkoshy switch(pe) { 2164183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 2165145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 2166145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2167145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2168145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2169145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2170145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2171145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2172145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2173145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2174145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2175145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2176145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2177145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2178145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2179145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2180145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2181145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2182145256Sjkoshy P6MASKSET(any); break; 2183145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2184145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2185145256Sjkoshy P6MASKSET(ekp); break; 2186145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2187145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2188145256Sjkoshy P6MASKSET(pps); break; 2189145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2190145256Sjkoshy P6MASKSET(mite); break; 2191145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2192145256Sjkoshy P6MASKSET(fmt); break; 2193145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2194145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2195145256Sjkoshy P6MASKSET(sr); break; 2196145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2197145256Sjkoshy P6MASKSET(eet); break; 2198145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2199145256Sjkoshy P6MASKSET(efur); break; 2200145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2201145256Sjkoshy P6MASKSET(essir); break; 2202145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2203145256Sjkoshy P6MASKSET(esscir); break; 2204145256Sjkoshy default: 2205145256Sjkoshy pmask = NULL; 2206145256Sjkoshy break; 2207145256Sjkoshy } 2208145256Sjkoshy 2209145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2210145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2211145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2212145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2213145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2214145256Sjkoshy P6MASKSET(mesihw); 2215145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2216145256Sjkoshy P6MASKSET(hw); 2217145256Sjkoshy } 2218145256Sjkoshy 2219145256Sjkoshy /* Parse additional modifiers if present */ 2220145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2221145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2222145256Sjkoshy q = strchr(p, '='); 2223145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2224174406Sjkoshy return (-1); 2225145256Sjkoshy count = strtol(q, &e, 0); 2226145256Sjkoshy if (e == q || *e != '\0') 2227174406Sjkoshy return (-1); 2228145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2229147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2230147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2231145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2232145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2233145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2234145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2235145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2236145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2237145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2238145256Sjkoshy evmask = 0; 2239145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2240174406Sjkoshy return (-1); 2241145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2242145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2243145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2244145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2245145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2246145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2247145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2248145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2249145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2250145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2251145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2252145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2253145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2254145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2255145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2256145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2257145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2258145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2259145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2260145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2261145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2262145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2263145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2264174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2265174406Sjkoshy return (-1); 2266145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2267145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2268145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2269145256Sjkoshy } else 2270174406Sjkoshy return (-1); 2271145256Sjkoshy } 2272145256Sjkoshy 2273145256Sjkoshy /* post processing */ 2274145256Sjkoshy switch (pe) { 2275145256Sjkoshy 2276145256Sjkoshy /* 2277145256Sjkoshy * The following events default to an evmask of 0 2278145256Sjkoshy */ 2279145256Sjkoshy 2280145256Sjkoshy /* default => 'self' */ 2281145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2282145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2283145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2284145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2285145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2286145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2287145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2288145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2289145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2290145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2291145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2292145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2293145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2294145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2295145256Sjkoshy 2296145256Sjkoshy /* default => 'nta' */ 2297145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2298145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2299145256Sjkoshy 2300145256Sjkoshy /* default => 'packed and scalar' */ 2301145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2302145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2303145256Sjkoshy 2304145256Sjkoshy /* default => 'mmx to fp transitions' */ 2305145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2306145256Sjkoshy 2307145256Sjkoshy /* default => 'SSE Packed Single' */ 2308145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2309145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2310145256Sjkoshy 2311145256Sjkoshy /* default => 'all fused micro-ops' */ 2312145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2313145256Sjkoshy 2314145256Sjkoshy /* default => 'all transitions' */ 2315145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2316145256Sjkoshy break; 2317145256Sjkoshy 2318145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2319145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2320145256Sjkoshy break; 2321145256Sjkoshy 2322145256Sjkoshy default: 2323145256Sjkoshy /* 2324145256Sjkoshy * For all other events, set the default event mask 2325145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2326145256Sjkoshy */ 2327145256Sjkoshy if (evmask == 0 && pmask) { 2328145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2329145256Sjkoshy evmask |= pm->pm_value; 2330145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2331145256Sjkoshy } 2332145256Sjkoshy 2333145256Sjkoshy break; 2334145256Sjkoshy } 2335145256Sjkoshy 2336145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2337147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2338147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2339145256Sjkoshy 2340174406Sjkoshy return (0); 2341145256Sjkoshy} 2342145256Sjkoshy 2343147191Sjkoshy#endif 2344147191Sjkoshy 2345183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2346183725Sjkoshystatic int 2347183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2348183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2349183725Sjkoshy{ 2350183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2351183725Sjkoshy return (-1); 2352183725Sjkoshy 2353183725Sjkoshy /* TSC events must be unqualified. */ 2354183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2355183725Sjkoshy return (-1); 2356183725Sjkoshy 2357183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2358183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2359183725Sjkoshy 2360183725Sjkoshy return (0); 2361183725Sjkoshy} 2362183725Sjkoshy#endif 2363183725Sjkoshy 2364233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2365233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2366233628Sfabient EV_ALIAS(NULL, NULL) 2367233628Sfabient}; 2368233628Sfabient 2369233628Sfabientstatic int 2370233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2371233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2372233628Sfabient{ 2373233628Sfabient (void)ctrspec; 2374233628Sfabient (void)pmc_config; 2375233628Sfabient 2376242622Sdim if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST) 2377233628Sfabient return (-1); 2378233628Sfabient 2379233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2380233628Sfabient return (0); 2381233628Sfabient} 2382233628Sfabient 2383277835Sbr#if defined(__arm__) 2384200928Srpaulo#if defined(__XSCALE__) 2385200928Srpaulo 2386200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2387200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2388200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2389200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2390200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2391200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2392200928Srpaulo EV_ALIAS(NULL, NULL) 2393200928Srpaulo}; 2394200928Srpaulostatic int 2395200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2396200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2397200928Srpaulo{ 2398200928Srpaulo switch (pe) { 2399200928Srpaulo default: 2400200928Srpaulo break; 2401200928Srpaulo } 2402200928Srpaulo 2403200928Srpaulo return (0); 2404200928Srpaulo} 2405200928Srpaulo#endif 2406200928Srpaulo 2407277835Sbrstatic struct pmc_event_alias armv7_aliases[] = { 2408277835Sbr EV_ALIAS("dc-misses", "L1_DCACHE_REFILL"), 2409277835Sbr EV_ALIAS("ic-misses", "L1_ICACHE_REFILL"), 2410277835Sbr EV_ALIAS("instructions", "INSTR_EXECUTED"), 2411277835Sbr EV_ALIAS(NULL, NULL) 2412277835Sbr}; 2413277835Sbrstatic int 2414277835Sbrarmv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2415277835Sbr struct pmc_op_pmcallocate *pmc_config __unused) 2416277835Sbr{ 2417277835Sbr switch (pe) { 2418277835Sbr default: 2419277835Sbr break; 2420277835Sbr } 2421277835Sbr 2422277835Sbr return (0); 2423277835Sbr} 2424277835Sbr#endif 2425277835Sbr 2426204635Sgnn#if defined(__mips__) 2427204635Sgnn 2428204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2429204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2430204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2431204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2432204635Sgnn EV_ALIAS(NULL, NULL) 2433204635Sgnn}; 2434204635Sgnn 2435233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2436233335Sgonzo EV_ALIAS("instructions", "RET"), 2437233335Sgonzo EV_ALIAS("branches", "BR"), 2438233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2439233335Sgonzo EV_ALIAS(NULL, NULL) 2440233335Sgonzo}; 2441233335Sgonzo 2442233320Sgonzo#define MIPS_KW_OS "os" 2443233320Sgonzo#define MIPS_KW_USR "usr" 2444233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2445204635Sgnn 2446204635Sgnnstatic int 2447233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2448204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2449204635Sgnn{ 2450204635Sgnn char *p; 2451204635Sgnn 2452204635Sgnn (void) pe; 2453204635Sgnn 2454204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2455204635Sgnn 2456204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2457233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2458204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2459233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2460204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2461233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2462204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2463204635Sgnn else 2464204635Sgnn return (-1); 2465204635Sgnn } 2466204635Sgnn 2467204635Sgnn return (0); 2468204635Sgnn} 2469233320Sgonzo 2470204635Sgnn#endif /* __mips__ */ 2471204635Sgnn 2472228869Sjhibbits#if defined(__powerpc__) 2473204635Sgnn 2474228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2475228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2476228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2477228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2478228869Sjhibbits EV_ALIAS(NULL, NULL) 2479228869Sjhibbits}; 2480228869Sjhibbits 2481261342Sjhibbitsstatic struct pmc_event_alias ppc970_aliases[] = { 2482261342Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2483261342Sjhibbits EV_ALIAS("cycles", "CYCLES"), 2484261342Sjhibbits EV_ALIAS(NULL, NULL) 2485261342Sjhibbits}; 2486228869Sjhibbits 2487261342Sjhibbits#define POWERPC_KW_OS "os" 2488261342Sjhibbits#define POWERPC_KW_USR "usr" 2489261342Sjhibbits#define POWERPC_KW_ANYTHREAD "anythread" 2490261342Sjhibbits 2491228869Sjhibbitsstatic int 2492261342Sjhibbitspowerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2493261342Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2494228869Sjhibbits{ 2495228869Sjhibbits char *p; 2496228869Sjhibbits 2497228869Sjhibbits (void) pe; 2498228869Sjhibbits 2499228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2500228869Sjhibbits 2501228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2502261342Sjhibbits if (KWMATCH(p, POWERPC_KW_OS)) 2503228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2504261342Sjhibbits else if (KWMATCH(p, POWERPC_KW_USR)) 2505228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2506261342Sjhibbits else if (KWMATCH(p, POWERPC_KW_ANYTHREAD)) 2507228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2508228869Sjhibbits else 2509228869Sjhibbits return (-1); 2510228869Sjhibbits } 2511228869Sjhibbits 2512228869Sjhibbits return (0); 2513228869Sjhibbits} 2514261342Sjhibbits 2515228869Sjhibbits#endif /* __powerpc__ */ 2516228869Sjhibbits 2517228869Sjhibbits 2518145256Sjkoshy/* 2519183725Sjkoshy * Match an event name `name' with its canonical form. 2520183725Sjkoshy * 2521185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2522185363Sjkoshy * hyphen characters are considered to match each other. 2523185363Sjkoshy * 2524183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2525183725Sjkoshy */ 2526183725Sjkoshy 2527183725Sjkoshystatic int 2528183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2529183725Sjkoshy{ 2530183725Sjkoshy int cc, nc; 2531183725Sjkoshy const unsigned char *c, *n; 2532183725Sjkoshy 2533183725Sjkoshy c = (const unsigned char *) canonicalname; 2534183725Sjkoshy n = (const unsigned char *) name; 2535183725Sjkoshy 2536183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2537183725Sjkoshy 2538185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2539185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2540183725Sjkoshy continue; 2541183725Sjkoshy 2542185363Sjkoshy if (toupper(nc) == toupper(cc)) 2543183725Sjkoshy continue; 2544183725Sjkoshy 2545185363Sjkoshy 2546183725Sjkoshy return (0); 2547183725Sjkoshy } 2548183725Sjkoshy 2549183725Sjkoshy if (*n == '\0' && *c == '\0') 2550183725Sjkoshy return (1); 2551183725Sjkoshy 2552183725Sjkoshy return (0); 2553183725Sjkoshy} 2554183725Sjkoshy 2555183725Sjkoshy/* 2556183725Sjkoshy * Match an event name against all the event named supported by a 2557183725Sjkoshy * PMC class. 2558183725Sjkoshy * 2559183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2560183725Sjkoshy */ 2561183725Sjkoshystatic const struct pmc_event_descr * 2562183725Sjkoshypmc_match_event_class(const char *name, 2563183725Sjkoshy const struct pmc_class_descr *pcd) 2564183725Sjkoshy{ 2565183725Sjkoshy size_t n; 2566183725Sjkoshy const struct pmc_event_descr *ev; 2567185363Sjkoshy 2568183725Sjkoshy ev = pcd->pm_evc_event_table; 2569183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2570183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2571183725Sjkoshy return (ev); 2572183725Sjkoshy 2573183725Sjkoshy return (NULL); 2574183725Sjkoshy} 2575183725Sjkoshy 2576183725Sjkoshystatic int 2577183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2578183725Sjkoshy{ 2579183725Sjkoshy size_t n; 2580183725Sjkoshy 2581183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2582183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2583183725Sjkoshy return (1); 2584183725Sjkoshy return (0); 2585183725Sjkoshy} 2586183725Sjkoshy 2587183725Sjkoshy/* 2588147191Sjkoshy * API entry points 2589145256Sjkoshy */ 2590145256Sjkoshy 2591147191Sjkoshyint 2592147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2593147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2594145256Sjkoshy{ 2595183725Sjkoshy size_t n; 2596147191Sjkoshy int retval; 2597147191Sjkoshy char *r, *spec_copy; 2598147191Sjkoshy const char *ctrname; 2599183725Sjkoshy const struct pmc_event_descr *ev; 2600183725Sjkoshy const struct pmc_event_alias *alias; 2601147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2602183725Sjkoshy const struct pmc_class_descr *pcd; 2603145256Sjkoshy 2604147191Sjkoshy spec_copy = NULL; 2605147191Sjkoshy retval = -1; 2606145256Sjkoshy 2607147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2608147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2609147191Sjkoshy errno = EINVAL; 2610147191Sjkoshy goto out; 2611147191Sjkoshy } 2612145256Sjkoshy 2613147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2614147191Sjkoshy if (pmc_mdep_event_aliases) 2615183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2616183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2617183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2618147191Sjkoshy break; 2619147191Sjkoshy } 2620145256Sjkoshy 2621147191Sjkoshy if (spec_copy == NULL) 2622147191Sjkoshy spec_copy = strdup(ctrspec); 2623145256Sjkoshy 2624147191Sjkoshy r = spec_copy; 2625147191Sjkoshy ctrname = strsep(&r, ","); 2626145256Sjkoshy 2627183725Sjkoshy /* 2628183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2629183725Sjkoshy * search for the event to the specified PMC class. 2630183725Sjkoshy */ 2631183725Sjkoshy ev = NULL; 2632185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2633185363Sjkoshy pcd = pmc_class_table[n]; 2634183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2635183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2636183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2637183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2638183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2639183725Sjkoshy errno = EINVAL; 2640183725Sjkoshy goto out; 2641183725Sjkoshy } 2642147191Sjkoshy break; 2643183725Sjkoshy } 2644183725Sjkoshy } 2645145256Sjkoshy 2646183725Sjkoshy /* 2647183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2648183725Sjkoshy * classes. 2649183725Sjkoshy */ 2650185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2651185363Sjkoshy pcd = pmc_class_table[n]; 2652183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2653183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2654183725Sjkoshy } 2655183725Sjkoshy 2656183725Sjkoshy if (ev == NULL) { 2657147191Sjkoshy errno = EINVAL; 2658147191Sjkoshy goto out; 2659147191Sjkoshy } 2660145256Sjkoshy 2661147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2662183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2663183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2664147191Sjkoshy pmc_config.pm_cpu = cpu; 2665147191Sjkoshy pmc_config.pm_mode = mode; 2666147191Sjkoshy pmc_config.pm_flags = flags; 2667145256Sjkoshy 2668147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2669147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2670145256Sjkoshy 2671183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2672147191Sjkoshy errno = EINVAL; 2673147191Sjkoshy goto out; 2674147191Sjkoshy } 2675145256Sjkoshy 2676147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2677147191Sjkoshy goto out; 2678145256Sjkoshy 2679147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2680145256Sjkoshy 2681147191Sjkoshy retval = 0; 2682145256Sjkoshy 2683147191Sjkoshy out: 2684147191Sjkoshy if (spec_copy) 2685147191Sjkoshy free(spec_copy); 2686145256Sjkoshy 2687174406Sjkoshy return (retval); 2688147191Sjkoshy} 2689145256Sjkoshy 2690147191Sjkoshyint 2691147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2692147191Sjkoshy{ 2693147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2694145256Sjkoshy 2695147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2696147191Sjkoshy pmc_attach_args.pm_pid = pid; 2697145256Sjkoshy 2698174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2699147191Sjkoshy} 2700145256Sjkoshy 2701147191Sjkoshyint 2702147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2703147191Sjkoshy{ 2704147191Sjkoshy unsigned int i; 2705147191Sjkoshy enum pmc_class cl; 2706145256Sjkoshy 2707147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2708147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2709147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2710147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2711174406Sjkoshy return (0); 2712147191Sjkoshy } 2713177107Sjkoshy errno = EINVAL; 2714177107Sjkoshy return (-1); 2715147191Sjkoshy} 2716145256Sjkoshy 2717147191Sjkoshyint 2718147191Sjkoshypmc_configure_logfile(int fd) 2719147191Sjkoshy{ 2720147191Sjkoshy struct pmc_op_configurelog cla; 2721145256Sjkoshy 2722147191Sjkoshy cla.pm_logfd = fd; 2723147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2724174406Sjkoshy return (-1); 2725174406Sjkoshy return (0); 2726147191Sjkoshy} 2727145256Sjkoshy 2728147191Sjkoshyint 2729147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2730147191Sjkoshy{ 2731147191Sjkoshy if (pmc_syscall == -1) { 2732147191Sjkoshy errno = ENXIO; 2733174406Sjkoshy return (-1); 2734147191Sjkoshy } 2735145256Sjkoshy 2736147219Sjkoshy *pci = &cpu_info; 2737174406Sjkoshy return (0); 2738147191Sjkoshy} 2739145256Sjkoshy 2740147191Sjkoshyint 2741147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2742147191Sjkoshy{ 2743147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2744145256Sjkoshy 2745147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2746147191Sjkoshy pmc_detach_args.pm_pid = pid; 2747174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2748147191Sjkoshy} 2749147191Sjkoshy 2750147191Sjkoshyint 2751147191Sjkoshypmc_disable(int cpu, int pmc) 2752145256Sjkoshy{ 2753147191Sjkoshy struct pmc_op_pmcadmin ssa; 2754145256Sjkoshy 2755147191Sjkoshy ssa.pm_cpu = cpu; 2756147191Sjkoshy ssa.pm_pmc = pmc; 2757147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2758174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2759147191Sjkoshy} 2760145256Sjkoshy 2761147191Sjkoshyint 2762147191Sjkoshypmc_enable(int cpu, int pmc) 2763147191Sjkoshy{ 2764147191Sjkoshy struct pmc_op_pmcadmin ssa; 2765145256Sjkoshy 2766147191Sjkoshy ssa.pm_cpu = cpu; 2767147191Sjkoshy ssa.pm_pmc = pmc; 2768147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2769174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2770147191Sjkoshy} 2771145256Sjkoshy 2772147191Sjkoshy/* 2773147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2774147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2775147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2776147191Sjkoshy * the number of event name pointers returned. 2777147191Sjkoshy * 2778147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2779147191Sjkoshy * is responsible for freeing this space when done. 2780147191Sjkoshy */ 2781147191Sjkoshyint 2782147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2783147191Sjkoshy int *nevents) 2784147191Sjkoshy{ 2785147191Sjkoshy int count; 2786147191Sjkoshy const char **names; 2787147191Sjkoshy const struct pmc_event_descr *ev; 2788147191Sjkoshy 2789147191Sjkoshy switch (cl) 2790147191Sjkoshy { 2791185363Sjkoshy case PMC_CLASS_IAF: 2792185363Sjkoshy ev = iaf_event_table; 2793185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2794185363Sjkoshy break; 2795185363Sjkoshy case PMC_CLASS_IAP: 2796185363Sjkoshy /* 2797185363Sjkoshy * Return the most appropriate set of event name 2798185363Sjkoshy * spellings for the current CPU. 2799185363Sjkoshy */ 2800185363Sjkoshy switch (cpu_info.pm_cputype) { 2801185363Sjkoshy default: 2802185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2803185363Sjkoshy ev = atom_event_table; 2804185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2805185363Sjkoshy break; 2806263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 2807263446Shiren ev = atom_silvermont_event_table; 2808263446Shiren count = PMC_EVENT_TABLE_SIZE(atom_silvermont); 2809263446Shiren break; 2810185363Sjkoshy case PMC_CPU_INTEL_CORE: 2811185363Sjkoshy ev = core_event_table; 2812185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2813185363Sjkoshy break; 2814185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2815185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2816185363Sjkoshy ev = core2_event_table; 2817185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2818185363Sjkoshy break; 2819187761Sjeff case PMC_CPU_INTEL_COREI7: 2820187761Sjeff ev = corei7_event_table; 2821187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2822187761Sjeff break; 2823267062Skib case PMC_CPU_INTEL_NEHALEM_EX: 2824267062Skib ev = nehalem_ex_event_table; 2825267062Skib count = PMC_EVENT_TABLE_SIZE(nehalem_ex); 2826267062Skib break; 2827248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2828248842Ssbruno ev = haswell_event_table; 2829248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswell); 2830248842Ssbruno break; 2831277177Srrs case PMC_CPU_INTEL_HASWELL_XEON: 2832277177Srrs ev = haswell_xeon_event_table; 2833277177Srrs count = PMC_EVENT_TABLE_SIZE(haswell_xeon); 2834277177Srrs break; 2835240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2836240164Sfabient ev = ivybridge_event_table; 2837240164Sfabient count = PMC_EVENT_TABLE_SIZE(ivybridge); 2838240164Sfabient break; 2839246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 2840246166Ssbruno ev = ivybridge_xeon_event_table; 2841246166Ssbruno count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 2842246166Ssbruno break; 2843232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2844232366Sdavide ev = sandybridge_event_table; 2845232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2846232366Sdavide break; 2847241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2848241738Ssbruno ev = sandybridge_xeon_event_table; 2849241738Ssbruno count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 2850241738Ssbruno break; 2851206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2852206089Sfabient ev = westmere_event_table; 2853206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2854206089Sfabient break; 2855267062Skib case PMC_CPU_INTEL_WESTMERE_EX: 2856267062Skib ev = westmere_ex_event_table; 2857267062Skib count = PMC_EVENT_TABLE_SIZE(westmere_ex); 2858267062Skib break; 2859185363Sjkoshy } 2860185363Sjkoshy break; 2861206089Sfabient case PMC_CLASS_UCF: 2862206089Sfabient ev = ucf_event_table; 2863206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2864206089Sfabient break; 2865206089Sfabient case PMC_CLASS_UCP: 2866206089Sfabient /* 2867206089Sfabient * Return the most appropriate set of event name 2868206089Sfabient * spellings for the current CPU. 2869206089Sfabient */ 2870206089Sfabient switch (cpu_info.pm_cputype) { 2871206089Sfabient default: 2872206089Sfabient case PMC_CPU_INTEL_COREI7: 2873206089Sfabient ev = corei7uc_event_table; 2874206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2875206089Sfabient break; 2876248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2877248842Ssbruno ev = haswelluc_event_table; 2878248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswelluc); 2879248842Ssbruno break; 2880232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2881232366Sdavide ev = sandybridgeuc_event_table; 2882232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2883232366Sdavide break; 2884206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2885206089Sfabient ev = westmereuc_event_table; 2886206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2887206089Sfabient break; 2888206089Sfabient } 2889206089Sfabient break; 2890147191Sjkoshy case PMC_CLASS_TSC: 2891183725Sjkoshy ev = tsc_event_table; 2892183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2893145256Sjkoshy break; 2894147191Sjkoshy case PMC_CLASS_K7: 2895183725Sjkoshy ev = k7_event_table; 2896183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2897145256Sjkoshy break; 2898147191Sjkoshy case PMC_CLASS_K8: 2899183725Sjkoshy ev = k8_event_table; 2900183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2901145256Sjkoshy break; 2902183725Sjkoshy case PMC_CLASS_P4: 2903183725Sjkoshy ev = p4_event_table; 2904183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2905183725Sjkoshy break; 2906147191Sjkoshy case PMC_CLASS_P5: 2907183725Sjkoshy ev = p5_event_table; 2908183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2909145256Sjkoshy break; 2910147191Sjkoshy case PMC_CLASS_P6: 2911183725Sjkoshy ev = p6_event_table; 2912183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2913145256Sjkoshy break; 2914200928Srpaulo case PMC_CLASS_XSCALE: 2915200928Srpaulo ev = xscale_event_table; 2916200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2917200928Srpaulo break; 2918277835Sbr case PMC_CLASS_ARMV7: 2919277835Sbr ev = armv7_event_table; 2920277835Sbr count = PMC_EVENT_TABLE_SIZE(armv7); 2921277835Sbr break; 2922204635Sgnn case PMC_CLASS_MIPS24K: 2923204635Sgnn ev = mips24k_event_table; 2924204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2925204635Sgnn break; 2926233335Sgonzo case PMC_CLASS_OCTEON: 2927233335Sgonzo ev = octeon_event_table; 2928233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 2929233335Sgonzo break; 2930228869Sjhibbits case PMC_CLASS_PPC7450: 2931228869Sjhibbits ev = ppc7450_event_table; 2932228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2933228869Sjhibbits break; 2934261342Sjhibbits case PMC_CLASS_PPC970: 2935261342Sjhibbits ev = ppc970_event_table; 2936261342Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc970); 2937261342Sjhibbits break; 2938233628Sfabient case PMC_CLASS_SOFT: 2939233628Sfabient ev = soft_event_table; 2940233628Sfabient count = soft_event_info.pm_nevent; 2941233628Sfabient break; 2942145256Sjkoshy default: 2943147191Sjkoshy errno = EINVAL; 2944174406Sjkoshy return (-1); 2945145256Sjkoshy } 2946145256Sjkoshy 2947147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2948174406Sjkoshy return (-1); 2949145256Sjkoshy 2950147191Sjkoshy *eventnames = names; 2951147191Sjkoshy *nevents = count; 2952145256Sjkoshy 2953147191Sjkoshy for (;count--; ev++, names++) 2954147191Sjkoshy *names = ev->pm_ev_name; 2955233628Sfabient 2956174406Sjkoshy return (0); 2957147191Sjkoshy} 2958145256Sjkoshy 2959147191Sjkoshyint 2960147191Sjkoshypmc_flush_logfile(void) 2961147191Sjkoshy{ 2962174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2963147191Sjkoshy} 2964145256Sjkoshy 2965147191Sjkoshyint 2966226514Sfabientpmc_close_logfile(void) 2967226514Sfabient{ 2968226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2969226514Sfabient} 2970226514Sfabient 2971226514Sfabientint 2972147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2973147191Sjkoshy{ 2974147191Sjkoshy struct pmc_op_getdriverstats gms; 2975145256Sjkoshy 2976147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2977174406Sjkoshy return (-1); 2978145256Sjkoshy 2979147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2980147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2981147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2982147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2983147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2984147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2985147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2986147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2987147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2988174406Sjkoshy return (0); 2989147191Sjkoshy} 2990145256Sjkoshy 2991147191Sjkoshyint 2992147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2993147191Sjkoshy{ 2994147191Sjkoshy struct pmc_op_getmsr gm; 2995147191Sjkoshy 2996147191Sjkoshy gm.pm_pmcid = pmc; 2997147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2998174406Sjkoshy return (-1); 2999147191Sjkoshy *msr = gm.pm_msr; 3000174406Sjkoshy return (0); 3001145256Sjkoshy} 3002145256Sjkoshy 3003145256Sjkoshyint 3004145256Sjkoshypmc_init(void) 3005145256Sjkoshy{ 3006145256Sjkoshy int error, pmc_mod_id; 3007147219Sjkoshy unsigned int n; 3008145256Sjkoshy uint32_t abi_version; 3009145256Sjkoshy struct module_stat pmc_modstat; 3010147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 3011198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 3012198433Sjkoshy int cpu_has_iaf_counters; 3013198433Sjkoshy unsigned int t; 3014198433Sjkoshy#endif 3015145256Sjkoshy 3016145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 3017174406Sjkoshy return (0); 3018145256Sjkoshy 3019145256Sjkoshy /* retrieve the system call number from the KLD */ 3020145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 3021174406Sjkoshy return (-1); 3022145256Sjkoshy 3023145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 3024145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 3025174406Sjkoshy return (-1); 3026145256Sjkoshy 3027145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 3028145256Sjkoshy 3029147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 3030147191Sjkoshy abi_version = PMC_VERSION; 3031145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 3032145256Sjkoshy return (pmc_syscall = -1); 3033145256Sjkoshy 3034147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 3035147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 3036145256Sjkoshy errno = EPROGMISMATCH; 3037145256Sjkoshy return (pmc_syscall = -1); 3038145256Sjkoshy } 3039145256Sjkoshy 3040147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 3041145256Sjkoshy return (pmc_syscall = -1); 3042145256Sjkoshy 3043147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 3044147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 3045147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 3046147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 3047147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 3048147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 3049147219Sjkoshy 3050185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 3051185363Sjkoshy sizeof(struct pmc_class_descr *)); 3052185363Sjkoshy 3053185363Sjkoshy if (pmc_class_table == NULL) 3054185363Sjkoshy return (-1); 3055185363Sjkoshy 3056198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 3057198433Sjkoshy pmc_class_table[n] = NULL; 3058185363Sjkoshy 3059185363Sjkoshy /* 3060233628Sfabient * Get soft events list. 3061233628Sfabient */ 3062233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 3063233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 3064233628Sfabient return (pmc_syscall = -1); 3065233628Sfabient 3066233628Sfabient /* Map soft events to static list. */ 3067233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 3068233628Sfabient soft_event_table[n].pm_ev_name = 3069233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 3070233628Sfabient soft_event_table[n].pm_ev_code = 3071233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 3072233628Sfabient } 3073233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 3074233628Sfabient soft_event_info.pm_nevent; 3075233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 3076233628Sfabient soft_event_table; 3077233628Sfabient 3078233628Sfabient /* 3079185363Sjkoshy * Fill in the class table. 3080185363Sjkoshy */ 3081185363Sjkoshy n = 0; 3082233628Sfabient 3083233628Sfabient /* Fill soft events information. */ 3084233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 3085185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 3086233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 3087233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 3088198433Sjkoshy 3089198433Sjkoshy /* 3090198433Sjkoshy * Check if this CPU has fixed function counters. 3091198433Sjkoshy */ 3092198433Sjkoshy cpu_has_iaf_counters = 0; 3093198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 3094212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 3095212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 3096198433Sjkoshy cpu_has_iaf_counters = 1; 3097185363Sjkoshy#endif 3098185363Sjkoshy 3099183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 3100183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 3101183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 3102183725Sjkoshy pmc_mdep_class_list_size = \ 3103183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 3104183725Sjkoshy } while (0) 3105183725Sjkoshy 3106198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 3107198433Sjkoshy PMC_MDEP_INIT(C); \ 3108212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 3109212224Sfabient if (!cpu_has_iaf_counters) \ 3110198433Sjkoshy pmc_mdep_event_aliases = \ 3111198433Sjkoshy C##_aliases_without_iaf; \ 3112198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 3113198433Sjkoshy } while (0) 3114198433Sjkoshy 3115183725Sjkoshy /* Configure the event name parser. */ 3116145256Sjkoshy switch (cpu_info.pm_cputype) { 3117145340Smarcel#if defined(__i386__) 3118145256Sjkoshy case PMC_CPU_AMD_K7: 3119183725Sjkoshy PMC_MDEP_INIT(k7); 3120185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 3121145256Sjkoshy break; 3122145256Sjkoshy case PMC_CPU_INTEL_P5: 3123183725Sjkoshy PMC_MDEP_INIT(p5); 3124185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 3125145256Sjkoshy break; 3126145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 3127145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 3128145256Sjkoshy case PMC_CPU_INTEL_PIII: 3129145256Sjkoshy case PMC_CPU_INTEL_PM: 3130183725Sjkoshy PMC_MDEP_INIT(p6); 3131185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 3132145256Sjkoshy break; 3133147759Sjkoshy#endif 3134147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 3135183725Sjkoshy case PMC_CPU_AMD_K8: 3136183725Sjkoshy PMC_MDEP_INIT(k8); 3137185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 3138183725Sjkoshy break; 3139185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3140198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 3141185363Sjkoshy break; 3142263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3143263446Shiren PMC_MDEP_INIT_INTEL_V2(atom_silvermont); 3144263446Shiren break; 3145185363Sjkoshy case PMC_CPU_INTEL_CORE: 3146185363Sjkoshy PMC_MDEP_INIT(core); 3147202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 3148185363Sjkoshy break; 3149185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3150185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3151198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 3152185363Sjkoshy break; 3153187761Sjeff case PMC_CPU_INTEL_COREI7: 3154206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3155206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 3156198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 3157187761Sjeff break; 3158267062Skib case PMC_CPU_INTEL_NEHALEM_EX: 3159267062Skib PMC_MDEP_INIT_INTEL_V2(nehalem_ex); 3160267062Skib break; 3161248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3162248842Ssbruno pmc_class_table[n++] = &ucf_class_table_descr; 3163248842Ssbruno pmc_class_table[n++] = &haswelluc_class_table_descr; 3164248842Ssbruno PMC_MDEP_INIT_INTEL_V2(haswell); 3165248842Ssbruno break; 3166277177Srrs case PMC_CPU_INTEL_HASWELL_XEON: 3167277177Srrs PMC_MDEP_INIT_INTEL_V2(haswell_xeon); 3168277177Srrs break; 3169240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3170240164Sfabient PMC_MDEP_INIT_INTEL_V2(ivybridge); 3171240164Sfabient break; 3172246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3173246166Ssbruno PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon); 3174246166Ssbruno break; 3175232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3176232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 3177232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 3178232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 3179232366Sdavide break; 3180241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3181241738Ssbruno PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); 3182241738Ssbruno break; 3183206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3184206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3185206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 3186206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 3187206089Sfabient break; 3188267062Skib case PMC_CPU_INTEL_WESTMERE_EX: 3189267062Skib PMC_MDEP_INIT_INTEL_V2(westmere_ex); 3190267062Skib break; 3191145256Sjkoshy case PMC_CPU_INTEL_PIV: 3192183725Sjkoshy PMC_MDEP_INIT(p4); 3193185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 3194145256Sjkoshy break; 3195145256Sjkoshy#endif 3196233628Sfabient case PMC_CPU_GENERIC: 3197233628Sfabient PMC_MDEP_INIT(generic); 3198233628Sfabient break; 3199277835Sbr#if defined(__arm__) 3200200928Srpaulo#if defined(__XSCALE__) 3201200928Srpaulo case PMC_CPU_INTEL_XSCALE: 3202200928Srpaulo PMC_MDEP_INIT(xscale); 3203200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 3204200928Srpaulo break; 3205200928Srpaulo#endif 3206277835Sbr case PMC_CPU_ARMV7: 3207277835Sbr PMC_MDEP_INIT(armv7); 3208277835Sbr pmc_class_table[n] = &armv7_class_table_descr; 3209277835Sbr break; 3210277835Sbr#endif 3211204635Sgnn#if defined(__mips__) 3212204635Sgnn case PMC_CPU_MIPS_24K: 3213204635Sgnn PMC_MDEP_INIT(mips24k); 3214204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 3215204635Sgnn break; 3216233335Sgonzo case PMC_CPU_MIPS_OCTEON: 3217233335Sgonzo PMC_MDEP_INIT(octeon); 3218233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 3219233335Sgonzo break; 3220204635Sgnn#endif /* __mips__ */ 3221228869Sjhibbits#if defined(__powerpc__) 3222228869Sjhibbits case PMC_CPU_PPC_7450: 3223228869Sjhibbits PMC_MDEP_INIT(ppc7450); 3224228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 3225228869Sjhibbits break; 3226261342Sjhibbits case PMC_CPU_PPC_970: 3227261342Sjhibbits PMC_MDEP_INIT(ppc970); 3228261342Sjhibbits pmc_class_table[n] = &ppc970_class_table_descr; 3229261342Sjhibbits break; 3230228869Sjhibbits#endif 3231145256Sjkoshy default: 3232145256Sjkoshy /* 3233145256Sjkoshy * Some kind of CPU this version of the library knows nothing 3234145256Sjkoshy * about. This shouldn't happen since the abi version check 3235145256Sjkoshy * should have caught this. 3236145256Sjkoshy */ 3237145256Sjkoshy errno = ENXIO; 3238145256Sjkoshy return (pmc_syscall = -1); 3239145256Sjkoshy } 3240145256Sjkoshy 3241174406Sjkoshy return (0); 3242145256Sjkoshy} 3243145256Sjkoshy 3244147191Sjkoshyconst char * 3245147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 3246145256Sjkoshy{ 3247147191Sjkoshy int i; 3248145256Sjkoshy 3249147191Sjkoshy /* 3250147191Sjkoshy * 'cap' should have a single bit set and should be in 3251147191Sjkoshy * range. 3252147191Sjkoshy */ 3253147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 3254147191Sjkoshy cap > PMC_CAP_LAST) { 3255145256Sjkoshy errno = EINVAL; 3256174406Sjkoshy return (NULL); 3257145256Sjkoshy } 3258145256Sjkoshy 3259147191Sjkoshy i = ffs(cap); 3260174406Sjkoshy return (pmc_capability_names[i - 1]); 3261147191Sjkoshy} 3262145256Sjkoshy 3263147191Sjkoshyconst char * 3264147191Sjkoshypmc_name_of_class(enum pmc_class pc) 3265147191Sjkoshy{ 3266147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 3267147191Sjkoshy pc <= PMC_CLASS_LAST) 3268174406Sjkoshy return (pmc_class_names[pc]); 3269145256Sjkoshy 3270147191Sjkoshy errno = EINVAL; 3271174406Sjkoshy return (NULL); 3272147191Sjkoshy} 3273145256Sjkoshy 3274147191Sjkoshyconst char * 3275147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3276147191Sjkoshy{ 3277183725Sjkoshy size_t n; 3278183725Sjkoshy 3279183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3280183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3281183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3282183725Sjkoshy 3283147191Sjkoshy errno = EINVAL; 3284174406Sjkoshy return (NULL); 3285147191Sjkoshy} 3286145256Sjkoshy 3287147191Sjkoshyconst char * 3288147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3289147191Sjkoshy{ 3290147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3291147191Sjkoshy pd <= PMC_DISP_LAST) 3292174406Sjkoshy return (pmc_disposition_names[pd]); 3293145256Sjkoshy 3294147191Sjkoshy errno = EINVAL; 3295174406Sjkoshy return (NULL); 3296147191Sjkoshy} 3297145256Sjkoshy 3298147191Sjkoshyconst char * 3299185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3300147191Sjkoshy{ 3301183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3302145256Sjkoshy 3303183725Sjkoshy ev = evfence = NULL; 3304185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3305185363Sjkoshy ev = iaf_event_table; 3306185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3307185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3308185363Sjkoshy switch (cpu) { 3309185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3310185363Sjkoshy ev = atom_event_table; 3311185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3312185363Sjkoshy break; 3313263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3314263446Shiren ev = atom_silvermont_event_table; 3315263446Shiren evfence = atom_silvermont_event_table + 3316263446Shiren PMC_EVENT_TABLE_SIZE(atom_silvermont); 3317263446Shiren break; 3318185363Sjkoshy case PMC_CPU_INTEL_CORE: 3319185363Sjkoshy ev = core_event_table; 3320185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3321185363Sjkoshy break; 3322185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3323185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3324185363Sjkoshy ev = core2_event_table; 3325185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3326185363Sjkoshy break; 3327187761Sjeff case PMC_CPU_INTEL_COREI7: 3328187761Sjeff ev = corei7_event_table; 3329187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3330187761Sjeff break; 3331267062Skib case PMC_CPU_INTEL_NEHALEM_EX: 3332267062Skib ev = nehalem_ex_event_table; 3333267062Skib evfence = nehalem_ex_event_table + 3334267062Skib PMC_EVENT_TABLE_SIZE(nehalem_ex); 3335267062Skib break; 3336248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3337248842Ssbruno ev = haswell_event_table; 3338248842Ssbruno evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell); 3339248842Ssbruno break; 3340277177Srrs case PMC_CPU_INTEL_HASWELL_XEON: 3341277177Srrs ev = haswell_xeon_event_table; 3342277177Srrs evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon); 3343277177Srrs break; 3344277177Srrs 3345240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3346240164Sfabient ev = ivybridge_event_table; 3347240164Sfabient evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); 3348240164Sfabient break; 3349246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3350246166Ssbruno ev = ivybridge_xeon_event_table; 3351246166Ssbruno evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 3352246166Ssbruno break; 3353232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3354232366Sdavide ev = sandybridge_event_table; 3355232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3356232366Sdavide break; 3357241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3358241738Ssbruno ev = sandybridge_xeon_event_table; 3359241738Ssbruno evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 3360241738Ssbruno break; 3361206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3362206089Sfabient ev = westmere_event_table; 3363206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3364206089Sfabient break; 3365267062Skib case PMC_CPU_INTEL_WESTMERE_EX: 3366267062Skib ev = westmere_ex_event_table; 3367267062Skib evfence = westmere_ex_event_table + 3368267062Skib PMC_EVENT_TABLE_SIZE(westmere_ex); 3369267062Skib break; 3370185363Sjkoshy default: /* Unknown CPU type. */ 3371185363Sjkoshy break; 3372185363Sjkoshy } 3373206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3374206089Sfabient ev = ucf_event_table; 3375206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3376206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3377206089Sfabient switch (cpu) { 3378206089Sfabient case PMC_CPU_INTEL_COREI7: 3379206089Sfabient ev = corei7uc_event_table; 3380206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3381206089Sfabient break; 3382232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3383232366Sdavide ev = sandybridgeuc_event_table; 3384232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3385232366Sdavide break; 3386206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3387206089Sfabient ev = westmereuc_event_table; 3388206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3389206089Sfabient break; 3390206089Sfabient default: /* Unknown CPU type. */ 3391206089Sfabient break; 3392206089Sfabient } 3393206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3394183725Sjkoshy ev = k7_event_table; 3395183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3396183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3397183725Sjkoshy ev = k8_event_table; 3398183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3399183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3400183725Sjkoshy ev = p4_event_table; 3401183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3402183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3403183725Sjkoshy ev = p5_event_table; 3404183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3405183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3406183725Sjkoshy ev = p6_event_table; 3407183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3408200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3409200928Srpaulo ev = xscale_event_table; 3410200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3411277835Sbr } else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) { 3412277835Sbr ev = armv7_event_table; 3413277835Sbr evfence = armv7_event_table + PMC_EVENT_TABLE_SIZE(armv7); 3414204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3415204635Sgnn ev = mips24k_event_table; 3416233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3417233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3418233335Sgonzo ev = octeon_event_table; 3419233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3420228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3421228869Sjhibbits ev = ppc7450_event_table; 3422233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3423261342Sjhibbits } else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) { 3424261342Sjhibbits ev = ppc970_event_table; 3425261342Sjhibbits evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970); 3426183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3427183725Sjkoshy ev = tsc_event_table; 3428183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3429242622Sdim } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { 3430233628Sfabient ev = soft_event_table; 3431233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3432183725Sjkoshy } 3433183725Sjkoshy 3434183725Sjkoshy for (; ev != evfence; ev++) 3435183725Sjkoshy if (pe == ev->pm_ev_code) 3436183725Sjkoshy return (ev->pm_ev_name); 3437183725Sjkoshy 3438185363Sjkoshy return (NULL); 3439185363Sjkoshy} 3440185363Sjkoshy 3441185363Sjkoshyconst char * 3442185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3443185363Sjkoshy{ 3444185363Sjkoshy const char *n; 3445185363Sjkoshy 3446185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3447185363Sjkoshy return (n); 3448185363Sjkoshy 3449147191Sjkoshy errno = EINVAL; 3450174406Sjkoshy return (NULL); 3451147191Sjkoshy} 3452145256Sjkoshy 3453147191Sjkoshyconst char * 3454147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3455147191Sjkoshy{ 3456147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3457147191Sjkoshy pm <= PMC_MODE_LAST) 3458174406Sjkoshy return (pmc_mode_names[pm]); 3459145256Sjkoshy 3460147191Sjkoshy errno = EINVAL; 3461174406Sjkoshy return (NULL); 3462147191Sjkoshy} 3463145256Sjkoshy 3464147191Sjkoshyconst char * 3465147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3466147191Sjkoshy{ 3467147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3468147191Sjkoshy ps <= PMC_STATE_LAST) 3469174406Sjkoshy return (pmc_state_names[ps]); 3470145256Sjkoshy 3471147191Sjkoshy errno = EINVAL; 3472174406Sjkoshy return (NULL); 3473145256Sjkoshy} 3474145256Sjkoshy 3475145256Sjkoshyint 3476147191Sjkoshypmc_ncpu(void) 3477145256Sjkoshy{ 3478147191Sjkoshy if (pmc_syscall == -1) { 3479147191Sjkoshy errno = ENXIO; 3480174406Sjkoshy return (-1); 3481147191Sjkoshy } 3482145256Sjkoshy 3483174406Sjkoshy return (cpu_info.pm_ncpu); 3484145256Sjkoshy} 3485145256Sjkoshy 3486145256Sjkoshyint 3487147191Sjkoshypmc_npmc(int cpu) 3488145256Sjkoshy{ 3489147191Sjkoshy if (pmc_syscall == -1) { 3490147191Sjkoshy errno = ENXIO; 3491174406Sjkoshy return (-1); 3492147191Sjkoshy } 3493145256Sjkoshy 3494147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3495147191Sjkoshy errno = EINVAL; 3496174406Sjkoshy return (-1); 3497147191Sjkoshy } 3498145256Sjkoshy 3499174406Sjkoshy return (cpu_info.pm_npmc); 3500145256Sjkoshy} 3501145256Sjkoshy 3502145256Sjkoshyint 3503147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3504145256Sjkoshy{ 3505147191Sjkoshy int nbytes, npmc; 3506147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3507145256Sjkoshy 3508147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3509174406Sjkoshy return (-1); 3510145256Sjkoshy 3511147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3512147191Sjkoshy npmc * sizeof(struct pmc_info); 3513145256Sjkoshy 3514147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3515174406Sjkoshy return (-1); 3516145256Sjkoshy 3517147191Sjkoshy pmci->pm_cpu = cpu; 3518145256Sjkoshy 3519147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3520147191Sjkoshy free(pmci); 3521174406Sjkoshy return (-1); 3522147191Sjkoshy } 3523145256Sjkoshy 3524147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3525147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3526174406Sjkoshy return (0); 3527145256Sjkoshy} 3528145256Sjkoshy 3529145256Sjkoshyint 3530145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3531145256Sjkoshy{ 3532145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3533145256Sjkoshy 3534145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3535145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3536145256Sjkoshy pmc_read_op.pm_value = -1; 3537145256Sjkoshy 3538145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3539174406Sjkoshy return (-1); 3540145256Sjkoshy 3541145256Sjkoshy *value = pmc_read_op.pm_value; 3542174406Sjkoshy return (0); 3543145256Sjkoshy} 3544145256Sjkoshy 3545145256Sjkoshyint 3546147191Sjkoshypmc_release(pmc_id_t pmc) 3547145256Sjkoshy{ 3548147191Sjkoshy struct pmc_op_simple pmc_release_args; 3549145256Sjkoshy 3550147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3551174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3552145256Sjkoshy} 3553145256Sjkoshy 3554145256Sjkoshyint 3555145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3556145256Sjkoshy{ 3557145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3558145256Sjkoshy 3559145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3560145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3561145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3562145256Sjkoshy 3563145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3564174406Sjkoshy return (-1); 3565145256Sjkoshy 3566145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3567174406Sjkoshy return (0); 3568145256Sjkoshy} 3569145256Sjkoshy 3570145256Sjkoshyint 3571145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3572145256Sjkoshy{ 3573145256Sjkoshy struct pmc_op_pmcsetcount sc; 3574145256Sjkoshy 3575145256Sjkoshy sc.pm_pmcid = pmc; 3576145256Sjkoshy sc.pm_count = value; 3577145256Sjkoshy 3578145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3579174406Sjkoshy return (-1); 3580174406Sjkoshy return (0); 3581145256Sjkoshy} 3582145256Sjkoshy 3583145256Sjkoshyint 3584147191Sjkoshypmc_start(pmc_id_t pmc) 3585145256Sjkoshy{ 3586147191Sjkoshy struct pmc_op_simple pmc_start_args; 3587145256Sjkoshy 3588147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3589174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3590145256Sjkoshy} 3591145256Sjkoshy 3592145256Sjkoshyint 3593147191Sjkoshypmc_stop(pmc_id_t pmc) 3594145256Sjkoshy{ 3595147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3596145256Sjkoshy 3597147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3598174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3599145256Sjkoshy} 3600145256Sjkoshy 3601145256Sjkoshyint 3602145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3603145774Sjkoshy{ 3604145774Sjkoshy unsigned int i; 3605145774Sjkoshy enum pmc_class cl; 3606145774Sjkoshy 3607145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3608145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3609145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3610145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3611174406Sjkoshy return (0); 3612145774Sjkoshy } 3613177107Sjkoshy errno = EINVAL; 3614177107Sjkoshy return (-1); 3615145774Sjkoshy} 3616145774Sjkoshy 3617145774Sjkoshyint 3618147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3619145774Sjkoshy{ 3620147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3621145774Sjkoshy 3622147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3623147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3624147191Sjkoshy pmc_write_op.pm_value = value; 3625174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3626145256Sjkoshy} 3627145256Sjkoshy 3628145256Sjkoshyint 3629147191Sjkoshypmc_writelog(uint32_t userdata) 3630145256Sjkoshy{ 3631147191Sjkoshy struct pmc_op_writelog wl; 3632145256Sjkoshy 3633147191Sjkoshy wl.pm_userdata = userdata; 3634174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3635145256Sjkoshy} 3636