libpmc.c revision 283112
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 283112 2015-05-19 15:25:47Z 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 85283112Sbr#if defined(__aarch64__) 86283112Sbrstatic int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 87283112Sbr struct pmc_op_pmcallocate *_pmc_config); 88283112Sbr#endif 89204635Sgnn#if defined(__mips__) 90233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 91204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 92204635Sgnn#endif /* __mips__ */ 93233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 94233628Sfabient struct pmc_op_pmcallocate *_pmc_config); 95204635Sgnn 96228869Sjhibbits#if defined(__powerpc__) 97261342Sjhibbitsstatic int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec, 98228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 99228869Sjhibbits#endif /* __powerpc__ */ 100204635Sgnn 101145256Sjkoshy#define PMC_CALL(cmd, params) \ 102145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 103145256Sjkoshy 104145256Sjkoshy/* 105145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 106145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 107145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 108145256Sjkoshy * lookup table. 109145256Sjkoshy */ 110145256Sjkoshystruct pmc_event_alias { 111145256Sjkoshy const char *pm_alias; 112145256Sjkoshy const char *pm_spec; 113145256Sjkoshy}; 114145256Sjkoshy 115145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 116145256Sjkoshy 117145256Sjkoshy/* 118183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 119145256Sjkoshy * to integer codes used by the PMC KLD. 120145256Sjkoshy */ 121145256Sjkoshystruct pmc_event_descr { 122145256Sjkoshy const char *pm_ev_name; 123145256Sjkoshy enum pmc_event pm_ev_code; 124145256Sjkoshy}; 125145256Sjkoshy 126183725Sjkoshy/* 127183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 128183725Sjkoshy * event names to event tables and other PMC class data. 129183725Sjkoshy */ 130183725Sjkoshystruct pmc_class_descr { 131183725Sjkoshy const char *pm_evc_name; 132183725Sjkoshy size_t pm_evc_name_size; 133183725Sjkoshy enum pmc_class pm_evc_class; 134183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 135183725Sjkoshy size_t pm_evc_event_table_size; 136183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 137183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 138183725Sjkoshy}; 139183725Sjkoshy 140183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 141183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 142183725Sjkoshy 143183725Sjkoshy#undef __PMC_EV 144183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 145183725Sjkoshy 146183725Sjkoshy/* 147185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 148183725Sjkoshy * 149185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 150183725Sjkoshy */ 151185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 152183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 153183725Sjkoshy { \ 154183725Sjkoshy __PMC_EV_##C() \ 155185363Sjkoshy } 156185363Sjkoshy 157185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 158185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 159185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 160185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 161185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 162185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 163200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 164277835SbrPMC_CLASSDEP_TABLE(armv7, ARMV7); 165283112SbrPMC_CLASSDEP_TABLE(armv8, ARMV8); 166204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 167281098SadrianPMC_CLASSDEP_TABLE(mips74k, MIPS74K); 168233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON); 169206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 170228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 171261342SjhibbitsPMC_CLASSDEP_TABLE(ppc970, PPC970); 172281713SjhibbitsPMC_CLASSDEP_TABLE(e500, E500); 173185363Sjkoshy 174233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; 175233628Sfabient 176185363Sjkoshy#undef __PMC_EV_ALIAS 177185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 178185363Sjkoshy 179185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 180185363Sjkoshy{ 181185363Sjkoshy __PMC_EV_ALIAS_ATOM() 182185363Sjkoshy}; 183185363Sjkoshy 184263446Shirenstatic const struct pmc_event_descr atom_silvermont_event_table[] = 185263446Shiren{ 186263446Shiren __PMC_EV_ALIAS_ATOM_SILVERMONT() 187263446Shiren}; 188263446Shiren 189185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 190185363Sjkoshy{ 191185363Sjkoshy __PMC_EV_ALIAS_CORE() 192185363Sjkoshy}; 193185363Sjkoshy 194185363Sjkoshy 195185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 196185363Sjkoshy{ 197185363Sjkoshy __PMC_EV_ALIAS_CORE2() 198185363Sjkoshy}; 199185363Sjkoshy 200187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 201187761Sjeff{ 202187761Sjeff __PMC_EV_ALIAS_COREI7() 203187761Sjeff}; 204187761Sjeff 205267062Skibstatic const struct pmc_event_descr nehalem_ex_event_table[] = 206267062Skib{ 207267062Skib __PMC_EV_ALIAS_COREI7() 208267062Skib}; 209267062Skib 210248842Ssbrunostatic const struct pmc_event_descr haswell_event_table[] = 211248842Ssbruno{ 212248842Ssbruno __PMC_EV_ALIAS_HASWELL() 213248842Ssbruno}; 214248842Ssbruno 215277177Srrsstatic const struct pmc_event_descr haswell_xeon_event_table[] = 216277177Srrs{ 217277177Srrs __PMC_EV_ALIAS_HASWELL_XEON() 218277177Srrs}; 219277177Srrs 220277177Srrs 221240164Sfabientstatic const struct pmc_event_descr ivybridge_event_table[] = 222240164Sfabient{ 223240164Sfabient __PMC_EV_ALIAS_IVYBRIDGE() 224240164Sfabient}; 225240164Sfabient 226246166Ssbrunostatic const struct pmc_event_descr ivybridge_xeon_event_table[] = 227246166Ssbruno{ 228246166Ssbruno __PMC_EV_ALIAS_IVYBRIDGE_XEON() 229246166Ssbruno}; 230246166Ssbruno 231232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 232232366Sdavide{ 233232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 234232366Sdavide}; 235232366Sdavide 236241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] = 237241738Ssbruno{ 238241738Ssbruno __PMC_EV_ALIAS_SANDYBRIDGE_XEON() 239241738Ssbruno}; 240241738Ssbruno 241206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 242206089Sfabient{ 243206089Sfabient __PMC_EV_ALIAS_WESTMERE() 244206089Sfabient}; 245206089Sfabient 246267062Skibstatic const struct pmc_event_descr westmere_ex_event_table[] = 247267062Skib{ 248267062Skib __PMC_EV_ALIAS_WESTMERE() 249267062Skib}; 250267062Skib 251206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 252206089Sfabient{ 253206089Sfabient __PMC_EV_ALIAS_COREI7UC() 254206089Sfabient}; 255206089Sfabient 256248842Ssbrunostatic const struct pmc_event_descr haswelluc_event_table[] = 257248842Ssbruno{ 258248842Ssbruno __PMC_EV_ALIAS_HASWELLUC() 259248842Ssbruno}; 260248842Ssbruno 261232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 262232366Sdavide{ 263232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 264232366Sdavide}; 265232366Sdavide 266206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 267206089Sfabient{ 268206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 269206089Sfabient}; 270206089Sfabient 271283112Sbrstatic const struct pmc_event_descr cortex_a53_event_table[] = 272283112Sbr{ 273283112Sbr __PMC_EV_ALIAS_ARMV8_CORTEX_A53() 274283112Sbr}; 275283112Sbr 276283112Sbrstatic const struct pmc_event_descr cortex_a57_event_table[] = 277283112Sbr{ 278283112Sbr __PMC_EV_ALIAS_ARMV8_CORTEX_A57() 279283112Sbr}; 280283112Sbr 281185363Sjkoshy/* 282185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 283185363Sjkoshy * 284185363Sjkoshy * Map a CPU to the PMC classes it supports. 285185363Sjkoshy */ 286185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 287183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 288183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 289183725Sjkoshy } 290183725Sjkoshy 291233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 292263446ShirenPMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 293233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 294233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 295233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 296267062SkibPMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 297248842SsbrunoPMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 298277177SrrsPMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 299240164SfabientPMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 300246166SsbrunoPMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 301233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 302241738SsbrunoPMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 303233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 304267062SkibPMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 305233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); 306233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); 307233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); 308233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); 309233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); 310233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); 311277835SbrPMC_MDEP_TABLE(armv7, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); 312283112SbrPMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8); 313283112SbrPMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8); 314233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 315281098SadrianPMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K); 316233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 317281713SjhibbitsPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC); 318281713SjhibbitsPMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC); 319281713SjhibbitsPMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC); 320233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 321183725Sjkoshy 322183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 323145256Sjkoshy{ 324183725Sjkoshy __PMC_EV_TSC() 325145256Sjkoshy}; 326145256Sjkoshy 327183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 328185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 329185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 330185363Sjkoshy { \ 331185363Sjkoshy .pm_evc_name = #CLASS "-", \ 332185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 333185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 334185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 335183725Sjkoshy .pm_evc_event_table_size = \ 336185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 337185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 338183725Sjkoshy } 339183725Sjkoshy 340185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 341185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 342185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 343263446ShirenPMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap); 344185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 345185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 346187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 347267062SkibPMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap); 348248842SsbrunoPMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap); 349279833SrstonePMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell_xeon, iap); 350240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); 351246166SsbrunoPMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap); 352232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 353241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); 354206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 355267062SkibPMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap); 356206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 357206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 358248842SsbrunoPMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp); 359232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 360206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 361185363Sjkoshy#endif 362183725Sjkoshy#if defined(__i386__) 363185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 364183725Sjkoshy#endif 365183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 366185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 367185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 368183725Sjkoshy#endif 369183725Sjkoshy#if defined(__i386__) 370185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 371185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 372183725Sjkoshy#endif 373183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 374185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 375183725Sjkoshy#endif 376277835Sbr#if defined(__arm__) 377200928Srpaulo#if defined(__XSCALE__) 378200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 379200928Srpaulo#endif 380277835SbrPMC_CLASS_TABLE_DESC(armv7, ARMV7, armv7, armv7); 381277835Sbr#endif 382283112Sbr#if defined(__aarch64__) 383283112SbrPMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64); 384283112SbrPMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64); 385283112Sbr#endif 386204635Sgnn#if defined(__mips__) 387233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 388281098SadrianPMC_CLASS_TABLE_DESC(mips74k, MIPS74K, mips74k, mips); 389233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 390204635Sgnn#endif /* __mips__ */ 391228869Sjhibbits#if defined(__powerpc__) 392261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc); 393261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc); 394281713SjhibbitsPMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc); 395228869Sjhibbits#endif 396228869Sjhibbits 397233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 398233628Sfabient{ 399233628Sfabient .pm_evc_name = "SOFT-", 400233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 401233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 402233628Sfabient .pm_evc_event_table = NULL, 403233628Sfabient .pm_evc_event_table_size = 0, 404233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 405233628Sfabient}; 406233628Sfabient 407183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 408183725Sjkoshy 409185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 410185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 411185363Sjkoshy 412183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 413183725Sjkoshystatic size_t pmc_mdep_class_list_size; 414183725Sjkoshy 415145256Sjkoshy/* 416145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 417145256Sjkoshy * strings. 418145256Sjkoshy */ 419145256Sjkoshy 420145256Sjkoshystatic const char * pmc_capability_names[] = { 421145256Sjkoshy#undef __PMC_CAP 422145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 423145256Sjkoshy __PMC_CAPS() 424145256Sjkoshy}; 425145256Sjkoshy 426145256Sjkoshystatic const char * pmc_class_names[] = { 427145256Sjkoshy#undef __PMC_CLASS 428145256Sjkoshy#define __PMC_CLASS(C) #C , 429145256Sjkoshy __PMC_CLASSES() 430145256Sjkoshy}; 431145256Sjkoshy 432183725Sjkoshystruct pmc_cputype_map { 433228557Sdim enum pmc_cputype pm_cputype; 434183725Sjkoshy const char *pm_name; 435183725Sjkoshy}; 436183725Sjkoshy 437183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 438145256Sjkoshy#undef __PMC_CPU 439183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 440145256Sjkoshy __PMC_CPUS() 441145256Sjkoshy}; 442145256Sjkoshy 443145256Sjkoshystatic const char * pmc_disposition_names[] = { 444145256Sjkoshy#undef __PMC_DISP 445145256Sjkoshy#define __PMC_DISP(D) #D , 446145256Sjkoshy __PMC_DISPOSITIONS() 447145256Sjkoshy}; 448145256Sjkoshy 449145256Sjkoshystatic const char * pmc_mode_names[] = { 450145256Sjkoshy#undef __PMC_MODE 451145256Sjkoshy#define __PMC_MODE(M,N) #M , 452145256Sjkoshy __PMC_MODES() 453145256Sjkoshy}; 454145256Sjkoshy 455145256Sjkoshystatic const char * pmc_state_names[] = { 456145256Sjkoshy#undef __PMC_STATE 457145256Sjkoshy#define __PMC_STATE(S) #S , 458145256Sjkoshy __PMC_STATES() 459145256Sjkoshy}; 460145256Sjkoshy 461233628Sfabient/* 462233628Sfabient * Filled in by pmc_init(). 463233628Sfabient */ 464233628Sfabientstatic int pmc_syscall = -1; 465233628Sfabientstatic struct pmc_cpuinfo cpu_info; 466233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 467145256Sjkoshy 468145256Sjkoshy/* Event masks for events */ 469145256Sjkoshystruct pmc_masks { 470145256Sjkoshy const char *pm_name; 471240164Sfabient const uint64_t pm_value; 472145256Sjkoshy}; 473145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 474206089Sfabient#define NULLMASK { .pm_name = NULL } 475145256Sjkoshy 476147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 477145256Sjkoshystatic int 478240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) 479145256Sjkoshy{ 480145256Sjkoshy const struct pmc_masks *pm; 481145256Sjkoshy char *q, *r; 482145256Sjkoshy int c; 483145256Sjkoshy 484145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 485174406Sjkoshy return (-1); 486183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 487145256Sjkoshy if (*++q == '\0') /* no more data */ 488174406Sjkoshy return (-1); 489145256Sjkoshy c = 0; /* count of mask keywords seen */ 490145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 491183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 492183725Sjkoshy pm++) 493145256Sjkoshy ; 494145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 495174406Sjkoshy return (-1); 496145256Sjkoshy *evmask |= pm->pm_value; 497145256Sjkoshy c++; 498145256Sjkoshy } 499174406Sjkoshy return (c); 500145256Sjkoshy} 501145340Smarcel#endif 502145256Sjkoshy 503145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 504145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 505145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 506145256Sjkoshy 507145340Smarcel#if defined(__i386__) 508145256Sjkoshy 509145256Sjkoshy/* 510145256Sjkoshy * AMD K7 (Athlon) CPUs. 511145256Sjkoshy */ 512145256Sjkoshy 513145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 514145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 515145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 516145351Sjkoshy EV_ALIAS("cycles", "tsc"), 517183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 518145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 519145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 520145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 521145351Sjkoshy EV_ALIAS(NULL, NULL) 522145256Sjkoshy}; 523145256Sjkoshy 524145256Sjkoshy#define K7_KW_COUNT "count" 525145256Sjkoshy#define K7_KW_EDGE "edge" 526145256Sjkoshy#define K7_KW_INV "inv" 527145256Sjkoshy#define K7_KW_OS "os" 528145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 529145256Sjkoshy#define K7_KW_USR "usr" 530145256Sjkoshy 531145256Sjkoshystatic int 532145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 533145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 534145256Sjkoshy{ 535183107Sjkoshy char *e, *p, *q; 536183107Sjkoshy int c, has_unitmask; 537145256Sjkoshy uint32_t count, unitmask; 538145256Sjkoshy 539147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 540183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 541145256Sjkoshy 542145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 543145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 544145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 545145256Sjkoshy has_unitmask = 1; 546147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 547145256Sjkoshy } else 548145256Sjkoshy unitmask = has_unitmask = 0; 549145256Sjkoshy 550145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 551145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 552145256Sjkoshy q = strchr(p, '='); 553145256Sjkoshy if (*++q == '\0') /* skip '=' */ 554174406Sjkoshy return (-1); 555145256Sjkoshy 556145256Sjkoshy count = strtol(q, &e, 0); 557145256Sjkoshy if (e == q || *e != '\0') 558174406Sjkoshy return (-1); 559145256Sjkoshy 560145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 561147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 562147191Sjkoshy AMD_PMC_TO_COUNTER(count); 563145256Sjkoshy 564145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 565145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 566145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 567145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 568145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 569145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 570145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 571145256Sjkoshy if (has_unitmask == 0) 572174406Sjkoshy return (-1); 573145256Sjkoshy unitmask = 0; 574145256Sjkoshy q = strchr(p, '='); 575145256Sjkoshy if (*++q == '\0') /* skip '=' */ 576174406Sjkoshy return (-1); 577145256Sjkoshy 578145256Sjkoshy while ((c = tolower(*q++)) != 0) 579145256Sjkoshy if (c == 'm') 580147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 581145256Sjkoshy else if (c == 'o') 582147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 583145256Sjkoshy else if (c == 'e') 584147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 585145256Sjkoshy else if (c == 's') 586147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 587145256Sjkoshy else if (c == 'i') 588147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 589145256Sjkoshy else if (c == '+') 590145256Sjkoshy continue; 591145256Sjkoshy else 592174406Sjkoshy return (-1); 593145256Sjkoshy 594145256Sjkoshy if (unitmask == 0) 595174406Sjkoshy return (-1); 596145256Sjkoshy 597145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 598145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 599145256Sjkoshy } else 600174406Sjkoshy return (-1); 601145256Sjkoshy } 602145256Sjkoshy 603145256Sjkoshy if (has_unitmask) { 604145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 605147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 606147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 607145256Sjkoshy } 608145256Sjkoshy 609174406Sjkoshy return (0); 610145256Sjkoshy 611145256Sjkoshy} 612145256Sjkoshy 613147191Sjkoshy#endif 614147191Sjkoshy 615147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 616147191Sjkoshy 617145256Sjkoshy/* 618185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 619185363Sjkoshy */ 620185363Sjkoshy 621185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 622185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 623185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 624185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 625185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 626185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 627185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 628185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 629185363Sjkoshy EV_ALIAS(NULL, NULL) 630185363Sjkoshy}; 631185363Sjkoshy 632185363Sjkoshy/* 633185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 634185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 635198433Sjkoshy * 636198433Sjkoshy * We map aliases to events on the fixed-function counters if these 637198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 638198433Sjkoshy * counters. 639185363Sjkoshy */ 640185363Sjkoshy 641185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 642185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 643185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 644185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 645185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 646185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 647185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 648185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 649185363Sjkoshy EV_ALIAS(NULL, NULL) 650185363Sjkoshy}; 651185363Sjkoshy 652198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 653198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 654198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 655198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 656198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 657198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 658198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 659198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 660198433Sjkoshy EV_ALIAS(NULL, NULL) 661198433Sjkoshy}; 662198433Sjkoshy 663198433Sjkoshy#define atom_aliases core2_aliases 664198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 665263446Shiren#define atom_silvermont_aliases core2_aliases 666263446Shiren#define atom_silvermont_aliases_without_iaf core2_aliases_without_iaf 667198433Sjkoshy#define corei7_aliases core2_aliases 668198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 669267062Skib#define nehalem_ex_aliases core2_aliases 670267062Skib#define nehalem_ex_aliases_without_iaf core2_aliases_without_iaf 671248842Ssbruno#define haswell_aliases core2_aliases 672248842Ssbruno#define haswell_aliases_without_iaf core2_aliases_without_iaf 673277177Srrs#define haswell_xeon_aliases core2_aliases 674277177Srrs#define haswell_xeon_aliases_without_iaf core2_aliases_without_iaf 675240164Sfabient#define ivybridge_aliases core2_aliases 676240164Sfabient#define ivybridge_aliases_without_iaf core2_aliases_without_iaf 677246166Ssbruno#define ivybridge_xeon_aliases core2_aliases 678246166Ssbruno#define ivybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 679232366Sdavide#define sandybridge_aliases core2_aliases 680232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 681241738Ssbruno#define sandybridge_xeon_aliases core2_aliases 682241738Ssbruno#define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 683206089Sfabient#define westmere_aliases core2_aliases 684206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 685267062Skib#define westmere_ex_aliases core2_aliases 686267062Skib#define westmere_ex_aliases_without_iaf core2_aliases_without_iaf 687198433Sjkoshy 688185363Sjkoshy#define IAF_KW_OS "os" 689185363Sjkoshy#define IAF_KW_USR "usr" 690185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 691185363Sjkoshy 692185363Sjkoshy/* 693185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 694185363Sjkoshy */ 695185363Sjkoshystatic int 696185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 697185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 698185363Sjkoshy{ 699185363Sjkoshy char *p; 700185363Sjkoshy 701185363Sjkoshy (void) pe; 702185363Sjkoshy 703185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 704185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 705185363Sjkoshy 706185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 707185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 708185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 709185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 710185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 711185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 712185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 713185363Sjkoshy else 714185363Sjkoshy return (-1); 715185363Sjkoshy } 716185363Sjkoshy 717185363Sjkoshy return (0); 718185363Sjkoshy} 719185363Sjkoshy 720185363Sjkoshy/* 721185363Sjkoshy * Core/Core2 support. 722185363Sjkoshy */ 723185363Sjkoshy 724185363Sjkoshy#define IAP_KW_AGENT "agent" 725185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 726185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 727185363Sjkoshy#define IAP_KW_CMASK "cmask" 728185363Sjkoshy#define IAP_KW_CORE "core" 729185363Sjkoshy#define IAP_KW_EDGE "edge" 730185363Sjkoshy#define IAP_KW_INV "inv" 731185363Sjkoshy#define IAP_KW_OS "os" 732185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 733185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 734185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 735185363Sjkoshy#define IAP_KW_TRANSITION "trans" 736185363Sjkoshy#define IAP_KW_USR "usr" 737206089Sfabient#define IAP_KW_RSP "rsp" 738185363Sjkoshy 739185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 740185363Sjkoshy PMCMASK(all, (0x3 << 14)), 741185363Sjkoshy PMCMASK(this, (0x1 << 14)), 742185363Sjkoshy NULLMASK 743185363Sjkoshy}; 744185363Sjkoshy 745185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 746185363Sjkoshy PMCMASK(this, 0), 747185363Sjkoshy PMCMASK(any, (0x1 << 13)), 748185363Sjkoshy NULLMASK 749185363Sjkoshy}; 750185363Sjkoshy 751185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 752185363Sjkoshy PMCMASK(both, (0x3 << 12)), 753185363Sjkoshy PMCMASK(only, (0x1 << 12)), 754185363Sjkoshy PMCMASK(exclude, 0), 755185363Sjkoshy NULLMASK 756185363Sjkoshy}; 757185363Sjkoshy 758185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 759185363Sjkoshy PMCMASK(i, (1 << 8)), 760185363Sjkoshy PMCMASK(s, (1 << 9)), 761185363Sjkoshy PMCMASK(e, (1 << 10)), 762185363Sjkoshy PMCMASK(m, (1 << 11)), 763185363Sjkoshy NULLMASK 764185363Sjkoshy}; 765185363Sjkoshy 766185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 767185363Sjkoshy PMCMASK(clean, (1 << 8)), 768185363Sjkoshy PMCMASK(hit, (1 << 9)), 769185363Sjkoshy PMCMASK(hitm, (1 << 11)), 770185363Sjkoshy NULLMASK 771185363Sjkoshy}; 772185363Sjkoshy 773185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 774185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 775185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 776185363Sjkoshy NULLMASK 777185363Sjkoshy}; 778185363Sjkoshy 779185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 780185363Sjkoshy PMCMASK(any, 0x00), 781185363Sjkoshy PMCMASK(frequency, 0x10), 782185363Sjkoshy NULLMASK 783185363Sjkoshy}; 784185363Sjkoshy 785240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = { 786206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 787206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 788206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 789206089Sfabient PMCMASK(WB, (1 << 3)), 790206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 791206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 792206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 793206089Sfabient PMCMASK(OTHER, (1 << 7)), 794206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 795206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 796206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 797206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 798206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 799206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 800206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 801206089Sfabient NULLMASK 802206089Sfabient}; 803206089Sfabient 804241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { 805240164Sfabient PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 806240164Sfabient PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 807240164Sfabient PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 808240164Sfabient PMCMASK(REQ_WB, (1ULL << 3)), 809240164Sfabient PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 810240164Sfabient PMCMASK(REQ_PF_RFO, (1ULL << 5)), 811240164Sfabient PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 812240164Sfabient PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), 813240164Sfabient PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), 814240164Sfabient PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), 815240164Sfabient PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), 816240164Sfabient PMCMASK(REQ_STRM_ST, (1ULL << 11)), 817240164Sfabient PMCMASK(REQ_OTHER, (1ULL << 15)), 818240164Sfabient PMCMASK(RES_ANY, (1ULL << 16)), 819240164Sfabient PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 820240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 821240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 822240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 823240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 824240164Sfabient PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 825241974Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 826240164Sfabient PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 827240164Sfabient PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 828240164Sfabient PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 829240164Sfabient PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 830240164Sfabient PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 831240164Sfabient PMCMASK(RES_NON_DRAM, (1ULL << 37)), 832240164Sfabient NULLMASK 833240164Sfabient}; 834240164Sfabient 835248842Ssbrunostatic struct pmc_masks iap_rsp_mask_haswell[] = { 836248842Ssbruno PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 837248842Ssbruno PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 838248842Ssbruno PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 839248842Ssbruno PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 840248842Ssbruno PMCMASK(REQ_PF_RFO, (1ULL << 5)), 841248842Ssbruno PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 842248842Ssbruno PMCMASK(REQ_OTHER, (1ULL << 15)), 843248842Ssbruno PMCMASK(RES_ANY, (1ULL << 16)), 844248842Ssbruno PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 845248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 846248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 847248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 848248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 849248842Ssbruno PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 850248842Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 851248842Ssbruno PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 852248842Ssbruno PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 853248842Ssbruno PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 854248842Ssbruno PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 855248842Ssbruno PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 856248842Ssbruno PMCMASK(RES_NON_DRAM, (1ULL << 37)), 857248842Ssbruno NULLMASK 858248842Ssbruno}; 859248842Ssbruno 860185363Sjkoshystatic int 861185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 862185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 863185363Sjkoshy{ 864185363Sjkoshy char *e, *p, *q; 865240164Sfabient uint64_t cachestate, evmask, rsp; 866185363Sjkoshy int count, n; 867185363Sjkoshy 868185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 869185363Sjkoshy PMC_CAP_QUALIFIER); 870185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 871185363Sjkoshy 872206089Sfabient cachestate = evmask = rsp = 0; 873185363Sjkoshy 874185363Sjkoshy /* Parse additional modifiers if present */ 875185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 876185363Sjkoshy 877185363Sjkoshy n = 0; 878185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 879185363Sjkoshy q = strchr(p, '='); 880185363Sjkoshy if (*++q == '\0') /* skip '=' */ 881185363Sjkoshy return (-1); 882185363Sjkoshy count = strtol(q, &e, 0); 883185363Sjkoshy if (e == q || *e != '\0') 884185363Sjkoshy return (-1); 885185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 886185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 887185363Sjkoshy IAP_CMASK(count); 888185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 889185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 890185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 891185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 892185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 893185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 894185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 895185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 896185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 897185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 898193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 899185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 900185363Sjkoshy if (n != 1) 901185363Sjkoshy return (-1); 902193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 903185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 904185363Sjkoshy if (n != 1) 905185363Sjkoshy return (-1); 906193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 907185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 908185363Sjkoshy if (n != 1) 909185363Sjkoshy return (-1); 910193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 911185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 912185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 913193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 914185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 915185363Sjkoshy if (n != 1) 916185363Sjkoshy return (-1); 917185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 918263446Shiren cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT || 919185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 920206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 921193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 922185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 923185363Sjkoshy &evmask); 924193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 925185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 926185363Sjkoshy &evmask); 927185363Sjkoshy } else 928185363Sjkoshy return (-1); 929206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 930267062Skib cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE || 931267062Skib cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX || 932267062Skib cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) { 933206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 934240164Sfabient n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); 935206089Sfabient } else 936206089Sfabient return (-1); 937240164Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || 938241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || 939246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE || 940246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) { 941240164Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 942241738Ssbruno n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); 943240164Sfabient } else 944240164Sfabient return (-1); 945277177Srrs } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL || 946277177Srrs cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) { 947248842Ssbruno if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 948248842Ssbruno n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); 949248842Ssbruno } else 950248842Ssbruno return (-1); 951185363Sjkoshy } else 952185363Sjkoshy return (-1); 953185363Sjkoshy 954185363Sjkoshy if (n < 0) /* Parsing failed. */ 955185363Sjkoshy return (-1); 956185363Sjkoshy } 957185363Sjkoshy 958185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 959185363Sjkoshy 960185363Sjkoshy /* 961185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 962185363Sjkoshy * specified by the user, use a sensible default. 963185363Sjkoshy */ 964185363Sjkoshy switch (pe) { 965185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 966185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 967185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 968185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 969185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 970185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 971185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 972185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 973185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 974185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 975185363Sjkoshy if (cachestate == 0) 976185363Sjkoshy cachestate = (0xF << 8); 977207482Srstone break; 978207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 979207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 980207482Srstone * Atom processor 981207482Srstone */ 982207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 983207482Srstone cachestate = (0xF << 8); 984207482Srstone break; 985185363Sjkoshy default: 986185363Sjkoshy break; 987185363Sjkoshy } 988185363Sjkoshy 989185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 990206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 991185363Sjkoshy 992185363Sjkoshy return (0); 993185363Sjkoshy} 994185363Sjkoshy 995185363Sjkoshy/* 996206089Sfabient * Intel Uncore. 997206089Sfabient */ 998206089Sfabient 999206089Sfabientstatic int 1000206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 1001206089Sfabient struct pmc_op_pmcallocate *pmc_config) 1002206089Sfabient{ 1003206089Sfabient (void) pe; 1004206089Sfabient (void) ctrspec; 1005206089Sfabient 1006206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1007206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 1008206089Sfabient 1009206089Sfabient return (0); 1010206089Sfabient} 1011206089Sfabient 1012206089Sfabient#define UCP_KW_CMASK "cmask" 1013206089Sfabient#define UCP_KW_EDGE "edge" 1014206089Sfabient#define UCP_KW_INV "inv" 1015206089Sfabient 1016206089Sfabientstatic int 1017206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 1018206089Sfabient struct pmc_op_pmcallocate *pmc_config) 1019206089Sfabient{ 1020206089Sfabient char *e, *p, *q; 1021206089Sfabient int count, n; 1022206089Sfabient 1023206089Sfabient (void) pe; 1024206089Sfabient 1025206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 1026206089Sfabient PMC_CAP_QUALIFIER); 1027206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 1028206089Sfabient 1029206089Sfabient /* Parse additional modifiers if present */ 1030206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 1031206089Sfabient 1032206089Sfabient n = 0; 1033206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 1034206089Sfabient q = strchr(p, '='); 1035206089Sfabient if (*++q == '\0') /* skip '=' */ 1036206089Sfabient return (-1); 1037206089Sfabient count = strtol(q, &e, 0); 1038206089Sfabient if (e == q || *e != '\0') 1039206089Sfabient return (-1); 1040206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1041206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 1042206089Sfabient UCP_CMASK(count); 1043206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 1044206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 1045206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 1046206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 1047206089Sfabient } else 1048206089Sfabient return (-1); 1049206089Sfabient 1050206089Sfabient if (n < 0) /* Parsing failed. */ 1051206089Sfabient return (-1); 1052206089Sfabient } 1053206089Sfabient 1054206089Sfabient return (0); 1055206089Sfabient} 1056206089Sfabient 1057206089Sfabient/* 1058147191Sjkoshy * AMD K8 PMCs. 1059147191Sjkoshy * 1060147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 1061147191Sjkoshy * events. 1062147191Sjkoshy */ 1063147191Sjkoshy 1064147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 1065147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 1066147191Sjkoshy EV_ALIAS("branch-mispredicts", 1067147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 1068147191Sjkoshy EV_ALIAS("cycles", "tsc"), 1069147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 1070147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 1071183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 1072147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 1073155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 1074147191Sjkoshy EV_ALIAS(NULL, NULL) 1075147191Sjkoshy}; 1076147191Sjkoshy 1077147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 1078147191Sjkoshy 1079147191Sjkoshy/* 1080147191Sjkoshy * Parsing tables 1081147191Sjkoshy */ 1082147191Sjkoshy 1083147191Sjkoshy/* fp dispatched fpu ops */ 1084147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 1085147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 1086147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 1087147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 1088147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 1089147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 1090147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 1091147191Sjkoshy NULLMASK 1092147191Sjkoshy}; 1093147191Sjkoshy 1094147191Sjkoshy/* ls segment register loads */ 1095147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 1096147191Sjkoshy __K8MASK(es, 0), 1097147191Sjkoshy __K8MASK(cs, 1), 1098147191Sjkoshy __K8MASK(ss, 2), 1099147191Sjkoshy __K8MASK(ds, 3), 1100147191Sjkoshy __K8MASK(fs, 4), 1101147191Sjkoshy __K8MASK(gs, 5), 1102147191Sjkoshy __K8MASK(hs, 6), 1103147191Sjkoshy NULLMASK 1104147191Sjkoshy}; 1105147191Sjkoshy 1106147191Sjkoshy/* ls locked operation */ 1107147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 1108147191Sjkoshy __K8MASK(locked-instructions, 0), 1109147191Sjkoshy __K8MASK(cycles-in-request, 1), 1110147191Sjkoshy __K8MASK(cycles-to-complete, 2), 1111147191Sjkoshy NULLMASK 1112147191Sjkoshy}; 1113147191Sjkoshy 1114147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 1115147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 1116147191Sjkoshy __K8MASK(invalid, 0), 1117147191Sjkoshy __K8MASK(shared, 1), 1118147191Sjkoshy __K8MASK(exclusive, 2), 1119147191Sjkoshy __K8MASK(owner, 3), 1120147191Sjkoshy __K8MASK(modified, 4), 1121147191Sjkoshy NULLMASK 1122147191Sjkoshy}; 1123147191Sjkoshy 1124147191Sjkoshy/* dc one bit ecc error */ 1125147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 1126147191Sjkoshy __K8MASK(scrubber, 0), 1127147191Sjkoshy __K8MASK(piggyback, 1), 1128147191Sjkoshy NULLMASK 1129147191Sjkoshy}; 1130147191Sjkoshy 1131147191Sjkoshy/* dc dispatched prefetch instructions */ 1132147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 1133147191Sjkoshy __K8MASK(load, 0), 1134147191Sjkoshy __K8MASK(store, 1), 1135147191Sjkoshy __K8MASK(nta, 2), 1136147191Sjkoshy NULLMASK 1137147191Sjkoshy}; 1138147191Sjkoshy 1139147191Sjkoshy/* dc dcache accesses by locks */ 1140147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1141147191Sjkoshy __K8MASK(accesses, 0), 1142147191Sjkoshy __K8MASK(misses, 1), 1143147191Sjkoshy NULLMASK 1144147191Sjkoshy}; 1145147191Sjkoshy 1146147191Sjkoshy/* bu internal l2 request */ 1147147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1148147191Sjkoshy __K8MASK(ic-fill, 0), 1149147191Sjkoshy __K8MASK(dc-fill, 1), 1150147191Sjkoshy __K8MASK(tlb-reload, 2), 1151147191Sjkoshy __K8MASK(tag-snoop, 3), 1152147191Sjkoshy __K8MASK(cancelled, 4), 1153147191Sjkoshy NULLMASK 1154147191Sjkoshy}; 1155147191Sjkoshy 1156147191Sjkoshy/* bu fill request l2 miss */ 1157147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1158147191Sjkoshy __K8MASK(ic-fill, 0), 1159147191Sjkoshy __K8MASK(dc-fill, 1), 1160147191Sjkoshy __K8MASK(tlb-reload, 2), 1161147191Sjkoshy NULLMASK 1162147191Sjkoshy}; 1163147191Sjkoshy 1164147191Sjkoshy/* bu fill into l2 */ 1165147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1166147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 1167147191Sjkoshy __K8MASK(victim-from-l2, 1), 1168147191Sjkoshy NULLMASK 1169147191Sjkoshy}; 1170147191Sjkoshy 1171147191Sjkoshy/* fr retired fpu instructions */ 1172147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1173147191Sjkoshy __K8MASK(x87, 0), 1174147191Sjkoshy __K8MASK(mmx-3dnow, 1), 1175147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 1176147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1177147191Sjkoshy NULLMASK 1178147191Sjkoshy}; 1179147191Sjkoshy 1180147191Sjkoshy/* fr retired fastpath double op instructions */ 1181147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1182147191Sjkoshy __K8MASK(low-op-pos-0, 0), 1183147191Sjkoshy __K8MASK(low-op-pos-1, 1), 1184147191Sjkoshy __K8MASK(low-op-pos-2, 2), 1185147191Sjkoshy NULLMASK 1186147191Sjkoshy}; 1187147191Sjkoshy 1188147191Sjkoshy/* fr fpu exceptions */ 1189147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1190147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1191147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1192147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1193147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1194147191Sjkoshy NULLMASK 1195147191Sjkoshy}; 1196147191Sjkoshy 1197147191Sjkoshy/* nb memory controller page access event */ 1198147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1199147191Sjkoshy __K8MASK(page-hit, 0), 1200147191Sjkoshy __K8MASK(page-miss, 1), 1201147191Sjkoshy __K8MASK(page-conflict, 2), 1202147191Sjkoshy NULLMASK 1203147191Sjkoshy}; 1204147191Sjkoshy 1205147191Sjkoshy/* nb memory controller turnaround */ 1206147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1207147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1208147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1209147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1210147191Sjkoshy NULLMASK 1211147191Sjkoshy}; 1212147191Sjkoshy 1213147191Sjkoshy/* nb memory controller bypass saturation */ 1214147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1215147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1216147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1217147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1218147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1219147191Sjkoshy NULLMASK 1220147191Sjkoshy}; 1221147191Sjkoshy 1222147191Sjkoshy/* nb sized commands */ 1223147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1224147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1225147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1226147191Sjkoshy __K8MASK(postwrszbyte, 2), 1227147191Sjkoshy __K8MASK(postwrszdword, 3), 1228147191Sjkoshy __K8MASK(rdszbyte, 4), 1229147191Sjkoshy __K8MASK(rdszdword, 5), 1230147191Sjkoshy __K8MASK(rdmodwr, 6), 1231147191Sjkoshy NULLMASK 1232147191Sjkoshy}; 1233147191Sjkoshy 1234147191Sjkoshy/* nb probe result */ 1235147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1236147191Sjkoshy __K8MASK(probe-miss, 0), 1237147191Sjkoshy __K8MASK(probe-hit, 1), 1238147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1239147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1240147191Sjkoshy NULLMASK 1241147191Sjkoshy}; 1242147191Sjkoshy 1243147191Sjkoshy/* nb hypertransport bus bandwidth */ 1244147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1245147191Sjkoshy __K8MASK(command, 0), 1246183107Sjkoshy __K8MASK(data, 1), 1247147191Sjkoshy __K8MASK(buffer-release, 2), 1248147191Sjkoshy __K8MASK(nop, 3), 1249147191Sjkoshy NULLMASK 1250147191Sjkoshy}; 1251147191Sjkoshy 1252147191Sjkoshy#undef __K8MASK 1253147191Sjkoshy 1254147191Sjkoshy#define K8_KW_COUNT "count" 1255147191Sjkoshy#define K8_KW_EDGE "edge" 1256147191Sjkoshy#define K8_KW_INV "inv" 1257147191Sjkoshy#define K8_KW_MASK "mask" 1258147191Sjkoshy#define K8_KW_OS "os" 1259147191Sjkoshy#define K8_KW_USR "usr" 1260147191Sjkoshy 1261147191Sjkoshystatic int 1262147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1263147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1264147191Sjkoshy{ 1265183107Sjkoshy char *e, *p, *q; 1266183107Sjkoshy int n; 1267240164Sfabient uint32_t count; 1268240164Sfabient uint64_t evmask; 1269147191Sjkoshy const struct pmc_masks *pm, *pmask; 1270147191Sjkoshy 1271183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1272147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1273147191Sjkoshy 1274147191Sjkoshy pmask = NULL; 1275147191Sjkoshy evmask = 0; 1276147191Sjkoshy 1277147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1278147191Sjkoshy 1279147191Sjkoshy /* setup parsing tables */ 1280147191Sjkoshy switch (pe) { 1281147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1282147191Sjkoshy __K8SETMASK(fdfo); 1283147191Sjkoshy break; 1284147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1285147191Sjkoshy __K8SETMASK(lsrl); 1286147191Sjkoshy break; 1287147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1288147191Sjkoshy __K8SETMASK(llo); 1289147191Sjkoshy break; 1290147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1291147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1292147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1293147191Sjkoshy __K8SETMASK(dc); 1294147191Sjkoshy break; 1295147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1296147191Sjkoshy __K8SETMASK(dobee); 1297147191Sjkoshy break; 1298147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1299147191Sjkoshy __K8SETMASK(ddpi); 1300147191Sjkoshy break; 1301147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1302147191Sjkoshy __K8SETMASK(dabl); 1303147191Sjkoshy break; 1304147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1305147191Sjkoshy __K8SETMASK(bilr); 1306147191Sjkoshy break; 1307147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1308147191Sjkoshy __K8SETMASK(bfrlm); 1309147191Sjkoshy break; 1310147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1311147191Sjkoshy __K8SETMASK(bfil); 1312147191Sjkoshy break; 1313147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1314147191Sjkoshy __K8SETMASK(frfi); 1315147191Sjkoshy break; 1316147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1317147191Sjkoshy __K8SETMASK(frfdoi); 1318147191Sjkoshy break; 1319147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1320147191Sjkoshy __K8SETMASK(ffe); 1321147191Sjkoshy break; 1322147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1323147191Sjkoshy __K8SETMASK(nmcpae); 1324147191Sjkoshy break; 1325147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1326147191Sjkoshy __K8SETMASK(nmct); 1327147191Sjkoshy break; 1328147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1329147191Sjkoshy __K8SETMASK(nmcbs); 1330147191Sjkoshy break; 1331147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1332147191Sjkoshy __K8SETMASK(nsc); 1333147191Sjkoshy break; 1334147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1335147191Sjkoshy __K8SETMASK(npr); 1336147191Sjkoshy break; 1337147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1338147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1339147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1340147191Sjkoshy __K8SETMASK(nhbb); 1341147191Sjkoshy break; 1342147191Sjkoshy 1343147191Sjkoshy default: 1344147191Sjkoshy break; /* no options defined */ 1345147191Sjkoshy } 1346147191Sjkoshy 1347147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1348147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1349147191Sjkoshy q = strchr(p, '='); 1350147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1351174406Sjkoshy return (-1); 1352147191Sjkoshy 1353147191Sjkoshy count = strtol(q, &e, 0); 1354147191Sjkoshy if (e == q || *e != '\0') 1355174406Sjkoshy return (-1); 1356147191Sjkoshy 1357147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1358147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1359147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1360147191Sjkoshy 1361147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1362147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1363147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1364147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1365147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1366147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1367174406Sjkoshy return (-1); 1368147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1369147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1370147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1371147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1372147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1373147191Sjkoshy } else 1374174406Sjkoshy return (-1); 1375147191Sjkoshy } 1376147191Sjkoshy 1377147191Sjkoshy /* other post processing */ 1378147191Sjkoshy switch (pe) { 1379147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1380147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1381147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1382147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1383147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1384147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1385147191Sjkoshy /* XXX only available in rev B and later */ 1386147191Sjkoshy break; 1387147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1388147191Sjkoshy /* XXX only available in rev C and later */ 1389147191Sjkoshy break; 1390147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1391147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1392147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1393174406Sjkoshy return (-1); 1394147191Sjkoshy if (evmask == 0) { 1395147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1396147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1397147191Sjkoshy } 1398147191Sjkoshy break; 1399147191Sjkoshy default: 1400147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1401147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1402147191Sjkoshy evmask |= pm->pm_value; 1403147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1404147191Sjkoshy } 1405147191Sjkoshy } 1406147191Sjkoshy 1407147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1408147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1409147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1410147191Sjkoshy 1411174406Sjkoshy return (0); 1412147191Sjkoshy} 1413147191Sjkoshy 1414147191Sjkoshy#endif 1415147191Sjkoshy 1416147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1417147191Sjkoshy 1418147191Sjkoshy/* 1419145256Sjkoshy * Intel P4 PMCs 1420145256Sjkoshy */ 1421145256Sjkoshy 1422145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1423145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1424145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1425145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1426145351Sjkoshy EV_ALIAS("instructions", 1427145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1428155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1429145256Sjkoshy EV_ALIAS(NULL, NULL) 1430145256Sjkoshy}; 1431145256Sjkoshy 1432145256Sjkoshy#define P4_KW_ACTIVE "active" 1433145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1434145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1435145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1436145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1437145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1438145256Sjkoshy#define P4_KW_CASCADE "cascade" 1439145256Sjkoshy#define P4_KW_EDGE "edge" 1440145256Sjkoshy#define P4_KW_INV "complement" 1441145256Sjkoshy#define P4_KW_OS "os" 1442145256Sjkoshy#define P4_KW_MASK "mask" 1443145256Sjkoshy#define P4_KW_PRECISE "precise" 1444145256Sjkoshy#define P4_KW_TAG "tag" 1445145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1446145256Sjkoshy#define P4_KW_USR "usr" 1447145256Sjkoshy 1448145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1449145256Sjkoshy 1450145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1451145256Sjkoshy __P4MASK(dd, 0), 1452145256Sjkoshy __P4MASK(db, 1), 1453145256Sjkoshy __P4MASK(di, 2), 1454145256Sjkoshy __P4MASK(bd, 3), 1455145256Sjkoshy __P4MASK(bb, 4), 1456145256Sjkoshy __P4MASK(bi, 5), 1457145256Sjkoshy __P4MASK(id, 6), 1458145256Sjkoshy __P4MASK(ib, 7), 1459145256Sjkoshy NULLMASK 1460145256Sjkoshy}; 1461145256Sjkoshy 1462145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1463145256Sjkoshy __P4MASK(tcmiss, 0), 1464145256Sjkoshy NULLMASK, 1465145256Sjkoshy}; 1466145256Sjkoshy 1467145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1468145256Sjkoshy __P4MASK(hit, 0), 1469145256Sjkoshy __P4MASK(miss, 1), 1470145256Sjkoshy __P4MASK(hit-uc, 2), 1471145256Sjkoshy NULLMASK 1472145256Sjkoshy}; 1473145256Sjkoshy 1474145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1475145256Sjkoshy __P4MASK(st-rb-full, 2), 1476145256Sjkoshy __P4MASK(64k-conf, 3), 1477145256Sjkoshy NULLMASK 1478145256Sjkoshy}; 1479145256Sjkoshy 1480145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1481145256Sjkoshy __P4MASK(lsc, 0), 1482145256Sjkoshy __P4MASK(ssc, 1), 1483145256Sjkoshy NULLMASK 1484145256Sjkoshy}; 1485145256Sjkoshy 1486145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1487145256Sjkoshy __P4MASK(split-ld, 1), 1488145256Sjkoshy NULLMASK 1489145256Sjkoshy}; 1490145256Sjkoshy 1491145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1492145256Sjkoshy __P4MASK(split-st, 1), 1493145256Sjkoshy NULLMASK 1494145256Sjkoshy}; 1495145256Sjkoshy 1496145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1497145256Sjkoshy __P4MASK(no-sta, 1), 1498145256Sjkoshy __P4MASK(no-std, 3), 1499145256Sjkoshy __P4MASK(partial-data, 4), 1500145256Sjkoshy __P4MASK(unalgn-addr, 5), 1501145256Sjkoshy NULLMASK 1502145256Sjkoshy}; 1503145256Sjkoshy 1504145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1505145256Sjkoshy __P4MASK(dtmiss, 0), 1506145256Sjkoshy __P4MASK(itmiss, 1), 1507145256Sjkoshy NULLMASK 1508145256Sjkoshy}; 1509145256Sjkoshy 1510145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1511145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1512145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1513145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1514145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1515145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1516145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1517145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1518145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1519145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1520145256Sjkoshy NULLMASK 1521145256Sjkoshy}; 1522145256Sjkoshy 1523145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1524145256Sjkoshy __P4MASK(all-read, 5), 1525145256Sjkoshy __P4MASK(all-write, 6), 1526145256Sjkoshy __P4MASK(mem-uc, 7), 1527145256Sjkoshy __P4MASK(mem-wc, 8), 1528145256Sjkoshy __P4MASK(mem-wt, 9), 1529145256Sjkoshy __P4MASK(mem-wp, 10), 1530145256Sjkoshy __P4MASK(mem-wb, 11), 1531145256Sjkoshy __P4MASK(own, 13), 1532145256Sjkoshy __P4MASK(other, 14), 1533145256Sjkoshy __P4MASK(prefetch, 15), 1534145256Sjkoshy NULLMASK 1535145256Sjkoshy}; 1536145256Sjkoshy 1537145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1538145256Sjkoshy __P4MASK(all-read, 5), 1539145256Sjkoshy __P4MASK(all-write, 6), 1540145256Sjkoshy __P4MASK(mem-uc, 7), 1541145256Sjkoshy __P4MASK(mem-wc, 8), 1542145256Sjkoshy __P4MASK(mem-wt, 9), 1543145256Sjkoshy __P4MASK(mem-wp, 10), 1544145256Sjkoshy __P4MASK(mem-wb, 11), 1545145256Sjkoshy __P4MASK(own, 13), 1546145256Sjkoshy __P4MASK(other, 14), 1547145256Sjkoshy __P4MASK(prefetch, 15), 1548145256Sjkoshy NULLMASK 1549145256Sjkoshy}; 1550145256Sjkoshy 1551145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1552145256Sjkoshy __P4MASK(drdy-drv, 0), 1553145256Sjkoshy __P4MASK(drdy-own, 1), 1554145256Sjkoshy __P4MASK(drdy-other, 2), 1555145256Sjkoshy __P4MASK(dbsy-drv, 3), 1556145256Sjkoshy __P4MASK(dbsy-own, 4), 1557145256Sjkoshy __P4MASK(dbsy-other, 5), 1558145256Sjkoshy NULLMASK 1559145256Sjkoshy}; 1560145256Sjkoshy 1561145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1562145256Sjkoshy __P4MASK(req-type0, 0), 1563145256Sjkoshy __P4MASK(req-type1, 1), 1564145256Sjkoshy __P4MASK(req-len0, 2), 1565145256Sjkoshy __P4MASK(req-len1, 3), 1566145256Sjkoshy __P4MASK(req-io-type, 5), 1567145256Sjkoshy __P4MASK(req-lock-type, 6), 1568145256Sjkoshy __P4MASK(req-cache-type, 7), 1569145256Sjkoshy __P4MASK(req-split-type, 8), 1570145256Sjkoshy __P4MASK(req-dem-type, 9), 1571145256Sjkoshy __P4MASK(req-ord-type, 10), 1572145256Sjkoshy __P4MASK(mem-type0, 11), 1573145256Sjkoshy __P4MASK(mem-type1, 12), 1574145256Sjkoshy __P4MASK(mem-type2, 13), 1575145256Sjkoshy NULLMASK 1576145256Sjkoshy}; 1577145256Sjkoshy 1578145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1579145256Sjkoshy __P4MASK(all, 15), 1580145256Sjkoshy NULLMASK 1581145256Sjkoshy}; 1582145256Sjkoshy 1583145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1584145256Sjkoshy __P4MASK(all, 15), 1585145256Sjkoshy NULLMASK 1586145256Sjkoshy}; 1587145256Sjkoshy 1588145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1589145256Sjkoshy __P4MASK(all, 15), 1590145256Sjkoshy NULLMASK 1591145256Sjkoshy}; 1592145256Sjkoshy 1593145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1594145256Sjkoshy __P4MASK(all, 15), 1595145256Sjkoshy NULLMASK 1596145256Sjkoshy}; 1597145256Sjkoshy 1598145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1599145256Sjkoshy __P4MASK(all, 15), 1600145256Sjkoshy NULLMASK 1601145256Sjkoshy}; 1602145256Sjkoshy 1603145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1604145256Sjkoshy __P4MASK(all, 15), 1605145256Sjkoshy NULLMASK 1606145256Sjkoshy}; 1607145256Sjkoshy 1608145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1609145256Sjkoshy __P4MASK(all, 15), 1610145256Sjkoshy NULLMASK 1611145256Sjkoshy}; 1612145256Sjkoshy 1613145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1614145256Sjkoshy __P4MASK(all, 15), 1615145256Sjkoshy NULLMASK 1616145256Sjkoshy}; 1617145256Sjkoshy 1618145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1619145256Sjkoshy __P4MASK(allp0, 3), 1620145256Sjkoshy __P4MASK(allp2, 4), 1621145256Sjkoshy NULLMASK 1622145256Sjkoshy}; 1623145256Sjkoshy 1624145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1625145256Sjkoshy __P4MASK(running, 0), 1626145256Sjkoshy NULLMASK 1627145256Sjkoshy}; 1628145256Sjkoshy 1629145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1630145256Sjkoshy __P4MASK(cisc, 0), 1631145256Sjkoshy NULLMASK 1632145256Sjkoshy}; 1633145256Sjkoshy 1634145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1635145256Sjkoshy __P4MASK(from-tc-build, 0), 1636145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1637145256Sjkoshy __P4MASK(from-rom, 2), 1638145256Sjkoshy NULLMASK 1639145256Sjkoshy}; 1640145256Sjkoshy 1641145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1642145351Sjkoshy /* retired mispred branch type */ 1643145256Sjkoshy __P4MASK(conditional, 1), 1644145256Sjkoshy __P4MASK(call, 2), 1645145256Sjkoshy __P4MASK(return, 3), 1646145256Sjkoshy __P4MASK(indirect, 4), 1647145256Sjkoshy NULLMASK 1648145256Sjkoshy}; 1649145256Sjkoshy 1650145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1651145256Sjkoshy __P4MASK(conditional, 1), 1652145256Sjkoshy __P4MASK(call, 2), 1653145256Sjkoshy __P4MASK(retired, 3), 1654145256Sjkoshy __P4MASK(indirect, 4), 1655145256Sjkoshy NULLMASK 1656145256Sjkoshy}; 1657145256Sjkoshy 1658145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1659145256Sjkoshy __P4MASK(sbfull, 5), 1660145256Sjkoshy NULLMASK 1661145256Sjkoshy}; 1662145256Sjkoshy 1663145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1664145256Sjkoshy __P4MASK(wcb-evicts, 0), 1665145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1666145256Sjkoshy NULLMASK 1667145256Sjkoshy}; 1668145256Sjkoshy 1669145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1670145256Sjkoshy __P4MASK(nbogus, 0), 1671145256Sjkoshy __P4MASK(bogus, 1), 1672145256Sjkoshy NULLMASK 1673145256Sjkoshy}; 1674145256Sjkoshy 1675145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1676145256Sjkoshy __P4MASK(nbogus0, 0), 1677145256Sjkoshy __P4MASK(nbogus1, 1), 1678145256Sjkoshy __P4MASK(nbogus2, 2), 1679145256Sjkoshy __P4MASK(nbogus3, 3), 1680145256Sjkoshy __P4MASK(bogus0, 4), 1681145256Sjkoshy __P4MASK(bogus1, 5), 1682145256Sjkoshy __P4MASK(bogus2, 6), 1683145256Sjkoshy __P4MASK(bogus3, 7), 1684145256Sjkoshy NULLMASK 1685145256Sjkoshy}; 1686145256Sjkoshy 1687145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1688145256Sjkoshy __P4MASK(nbogus, 0), 1689145256Sjkoshy __P4MASK(bogus, 1), 1690145256Sjkoshy NULLMASK 1691145256Sjkoshy}; 1692145256Sjkoshy 1693145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1694145256Sjkoshy __P4MASK(nbogusntag, 0), 1695145256Sjkoshy __P4MASK(nbogustag, 1), 1696145256Sjkoshy __P4MASK(bogusntag, 2), 1697145256Sjkoshy __P4MASK(bogustag, 3), 1698145256Sjkoshy NULLMASK 1699145256Sjkoshy}; 1700145256Sjkoshy 1701145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1702145256Sjkoshy __P4MASK(nbogus, 0), 1703145256Sjkoshy __P4MASK(bogus, 1), 1704145256Sjkoshy NULLMASK 1705145256Sjkoshy}; 1706145256Sjkoshy 1707145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1708145256Sjkoshy __P4MASK(tagloads, 1), 1709145256Sjkoshy __P4MASK(tagstores, 2), 1710145256Sjkoshy NULLMASK 1711145256Sjkoshy}; 1712145256Sjkoshy 1713145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1714145256Sjkoshy __P4MASK(mmnp, 0), 1715145256Sjkoshy __P4MASK(mmnm, 1), 1716145256Sjkoshy __P4MASK(mmtp, 2), 1717145256Sjkoshy __P4MASK(mmtm, 3), 1718145256Sjkoshy NULLMASK 1719145256Sjkoshy}; 1720145256Sjkoshy 1721145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1722145256Sjkoshy __P4MASK(nbogus, 0), 1723145256Sjkoshy NULLMASK 1724145256Sjkoshy}; 1725145256Sjkoshy 1726145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1727145256Sjkoshy __P4MASK(fpsu, 0), 1728145256Sjkoshy __P4MASK(fpso, 1), 1729145256Sjkoshy __P4MASK(poao, 2), 1730145256Sjkoshy __P4MASK(poau, 3), 1731145256Sjkoshy __P4MASK(prea, 4), 1732145256Sjkoshy NULLMASK 1733145256Sjkoshy}; 1734145256Sjkoshy 1735145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1736145256Sjkoshy __P4MASK(clear, 0), 1737145256Sjkoshy __P4MASK(moclear, 2), 1738145256Sjkoshy __P4MASK(smclear, 3), 1739145256Sjkoshy NULLMASK 1740145256Sjkoshy}; 1741145256Sjkoshy 1742145256Sjkoshy/* P4 event parser */ 1743145256Sjkoshystatic int 1744145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1745145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1746145256Sjkoshy{ 1747145256Sjkoshy 1748145256Sjkoshy char *e, *p, *q; 1749145256Sjkoshy int count, has_tag, has_busreqtype, n; 1750240164Sfabient uint32_t cccractivemask; 1751240164Sfabient uint64_t evmask; 1752145256Sjkoshy const struct pmc_masks *pm, *pmask; 1753145256Sjkoshy 1754183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1755147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1756147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1757145256Sjkoshy 1758145256Sjkoshy pmask = NULL; 1759145256Sjkoshy evmask = 0; 1760145256Sjkoshy cccractivemask = 0x3; 1761145256Sjkoshy has_tag = has_busreqtype = 0; 1762145256Sjkoshy 1763145256Sjkoshy#define __P4SETMASK(M) do { \ 1764183107Sjkoshy pmask = p4_mask_##M; \ 1765145256Sjkoshy} while (0) 1766145256Sjkoshy 1767145256Sjkoshy switch (pe) { 1768145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1769145256Sjkoshy __P4SETMASK(tcdm); 1770145256Sjkoshy break; 1771145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1772145256Sjkoshy __P4SETMASK(bfr); 1773145256Sjkoshy break; 1774145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1775145256Sjkoshy __P4SETMASK(ir); 1776145256Sjkoshy break; 1777145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1778145256Sjkoshy __P4SETMASK(memcan); 1779145256Sjkoshy break; 1780145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1781145256Sjkoshy __P4SETMASK(memcomp); 1782145256Sjkoshy break; 1783145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1784145256Sjkoshy __P4SETMASK(lpr); 1785145256Sjkoshy break; 1786145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1787145256Sjkoshy __P4SETMASK(spr); 1788145256Sjkoshy break; 1789145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1790145256Sjkoshy __P4SETMASK(mlr); 1791145256Sjkoshy break; 1792145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1793145256Sjkoshy __P4SETMASK(pwt); 1794145256Sjkoshy break; 1795145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1796145256Sjkoshy __P4SETMASK(bcr); 1797145256Sjkoshy break; 1798145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1799145256Sjkoshy __P4SETMASK(ia); 1800145256Sjkoshy has_busreqtype = 1; 1801145256Sjkoshy break; 1802145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1803145256Sjkoshy __P4SETMASK(iae); 1804145256Sjkoshy has_busreqtype = 1; 1805145256Sjkoshy break; 1806145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1807145256Sjkoshy __P4SETMASK(fda); 1808145256Sjkoshy break; 1809145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1810145256Sjkoshy __P4SETMASK(ba); 1811145256Sjkoshy break; 1812145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1813145256Sjkoshy __P4SETMASK(sia); 1814145256Sjkoshy break; 1815145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1816145256Sjkoshy __P4SETMASK(psu); 1817145256Sjkoshy break; 1818145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1819145256Sjkoshy __P4SETMASK(pdu); 1820145256Sjkoshy break; 1821145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1822145256Sjkoshy __P4SETMASK(ssu); 1823145256Sjkoshy break; 1824145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1825145256Sjkoshy __P4SETMASK(sdu); 1826145256Sjkoshy break; 1827145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1828145256Sjkoshy __P4SETMASK(64bmu); 1829145256Sjkoshy break; 1830145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1831145256Sjkoshy __P4SETMASK(128bmu); 1832145256Sjkoshy break; 1833145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1834145256Sjkoshy __P4SETMASK(xfu); 1835145256Sjkoshy break; 1836145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1837145256Sjkoshy __P4SETMASK(xsmu); 1838145256Sjkoshy break; 1839145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1840145256Sjkoshy __P4SETMASK(gpe); 1841145256Sjkoshy break; 1842145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1843145256Sjkoshy __P4SETMASK(tmx); 1844145256Sjkoshy break; 1845145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1846145256Sjkoshy __P4SETMASK(uqw); 1847145256Sjkoshy break; 1848145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1849145256Sjkoshy __P4SETMASK(rmbt); 1850145256Sjkoshy break; 1851145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1852145256Sjkoshy __P4SETMASK(rbt); 1853145256Sjkoshy break; 1854145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1855145256Sjkoshy __P4SETMASK(rs); 1856145256Sjkoshy break; 1857145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1858145256Sjkoshy __P4SETMASK(wb); 1859145256Sjkoshy break; 1860145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1861145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1862145256Sjkoshy case PMC_EV_P4_BNR: 1863145256Sjkoshy case PMC_EV_P4_SNOOP: 1864145256Sjkoshy case PMC_EV_P4_RESPONSE: 1865145256Sjkoshy break; 1866145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1867145256Sjkoshy __P4SETMASK(fee); 1868145256Sjkoshy break; 1869145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1870145256Sjkoshy __P4SETMASK(ee); 1871145256Sjkoshy break; 1872145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1873145256Sjkoshy __P4SETMASK(re); 1874145256Sjkoshy break; 1875145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1876145256Sjkoshy __P4SETMASK(insret); 1877145256Sjkoshy break; 1878145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1879145256Sjkoshy __P4SETMASK(ur); 1880145256Sjkoshy break; 1881145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1882145256Sjkoshy __P4SETMASK(ut); 1883145256Sjkoshy break; 1884145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1885145256Sjkoshy __P4SETMASK(br); 1886145256Sjkoshy break; 1887145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1888145256Sjkoshy __P4SETMASK(mbr); 1889145256Sjkoshy break; 1890145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1891145256Sjkoshy __P4SETMASK(xa); 1892145256Sjkoshy break; 1893145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1894145256Sjkoshy __P4SETMASK(machclr); 1895145256Sjkoshy break; 1896145256Sjkoshy default: 1897174406Sjkoshy return (-1); 1898145256Sjkoshy } 1899145256Sjkoshy 1900145256Sjkoshy /* process additional flags */ 1901145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1902145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1903145256Sjkoshy q = strchr(p, '='); 1904145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1905174406Sjkoshy return (-1); 1906145256Sjkoshy 1907183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1908145256Sjkoshy cccractivemask = 0x0; 1909183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1910145256Sjkoshy cccractivemask = 0x1; 1911183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1912145256Sjkoshy cccractivemask = 0x2; 1913183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1914145256Sjkoshy cccractivemask = 0x3; 1915145256Sjkoshy else 1916174406Sjkoshy return (-1); 1917145256Sjkoshy 1918145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1919145256Sjkoshy if (has_busreqtype == 0) 1920174406Sjkoshy return (-1); 1921145256Sjkoshy 1922145256Sjkoshy q = strchr(p, '='); 1923145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1924174406Sjkoshy return (-1); 1925145256Sjkoshy 1926145256Sjkoshy count = strtol(q, &e, 0); 1927145256Sjkoshy if (e == q || *e != '\0') 1928174406Sjkoshy return (-1); 1929145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1930145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1931145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1932145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1933145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1934145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1935145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1936145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1937145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1938174406Sjkoshy return (-1); 1939145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1940145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1941145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1942145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1943145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1944145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1945145256Sjkoshy if (has_tag == 0) 1946174406Sjkoshy return (-1); 1947145256Sjkoshy 1948145256Sjkoshy q = strchr(p, '='); 1949145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1950174406Sjkoshy return (-1); 1951145256Sjkoshy 1952145256Sjkoshy count = strtol(q, &e, 0); 1953145256Sjkoshy if (e == q || *e != '\0') 1954174406Sjkoshy return (-1); 1955145256Sjkoshy 1956145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1957147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1958145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1959145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1960145256Sjkoshy q = strchr(p, '='); 1961145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1962174406Sjkoshy return (-1); 1963145256Sjkoshy 1964145256Sjkoshy count = strtol(q, &e, 0); 1965145256Sjkoshy if (e == q || *e != '\0') 1966174406Sjkoshy return (-1); 1967145256Sjkoshy 1968145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1969147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1970147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1971147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1972147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1973145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1974145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1975145256Sjkoshy else 1976174406Sjkoshy return (-1); 1977145256Sjkoshy } 1978145256Sjkoshy 1979145256Sjkoshy /* other post processing */ 1980145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1981145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1982145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1983145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1984145256Sjkoshy 1985145256Sjkoshy /* fill in thread activity mask */ 1986147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1987145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1988145256Sjkoshy 1989145256Sjkoshy if (evmask) 1990145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1991145256Sjkoshy 1992145256Sjkoshy switch (pe) { 1993145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1994145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1995145256Sjkoshy (evmask & 0x18) == 0x18) 1996174406Sjkoshy return (-1); /* can't have own+other bits together */ 1997145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1998145256Sjkoshy evmask = 0x1D; 1999145256Sjkoshy break; 2000145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 2001145256Sjkoshy /* only one bit is allowed to be set */ 2002145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 2003174406Sjkoshy return (-1); 2004145256Sjkoshy if (evmask == 0) { 2005183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 2006145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2007145256Sjkoshy } 2008145256Sjkoshy break; 2009145256Sjkoshy default: 2010145256Sjkoshy if (evmask == 0 && pmask) { 2011145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2012145256Sjkoshy evmask |= pm->pm_value; 2013145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2014145256Sjkoshy } 2015145256Sjkoshy } 2016145256Sjkoshy 2017147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 2018147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 2019145256Sjkoshy 2020174406Sjkoshy return (0); 2021145256Sjkoshy} 2022145256Sjkoshy 2023147759Sjkoshy#endif 2024147759Sjkoshy 2025147759Sjkoshy#if defined(__i386__) 2026147759Sjkoshy 2027145256Sjkoshy/* 2028147191Sjkoshy * Pentium style PMCs 2029147191Sjkoshy */ 2030147191Sjkoshy 2031147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 2032183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 2033183105Sjkoshy EV_ALIAS("cycles", "tsc"), 2034183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 2035183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 2036183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 2037183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 2038183105Sjkoshy EV_ALIAS("unhalted-cycles", 2039183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 2040147191Sjkoshy EV_ALIAS(NULL, NULL) 2041147191Sjkoshy}; 2042147191Sjkoshy 2043147191Sjkoshystatic int 2044147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 2045147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2046147191Sjkoshy{ 2047174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 2048147191Sjkoshy} 2049147191Sjkoshy 2050147191Sjkoshy/* 2051145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 2052145256Sjkoshy * and Pentium M CPUs. 2053145256Sjkoshy */ 2054145256Sjkoshy 2055145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 2056145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 2057145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 2058145351Sjkoshy EV_ALIAS("cycles", "tsc"), 2059145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 2060168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 2061145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 2062145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 2063155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 2064145351Sjkoshy EV_ALIAS(NULL, NULL) 2065145256Sjkoshy}; 2066145256Sjkoshy 2067145256Sjkoshy#define P6_KW_CMASK "cmask" 2068145256Sjkoshy#define P6_KW_EDGE "edge" 2069145256Sjkoshy#define P6_KW_INV "inv" 2070145256Sjkoshy#define P6_KW_OS "os" 2071145256Sjkoshy#define P6_KW_UMASK "umask" 2072145256Sjkoshy#define P6_KW_USR "usr" 2073145256Sjkoshy 2074145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 2075145256Sjkoshy PMCMASK(m, 0x01), 2076145256Sjkoshy PMCMASK(e, 0x02), 2077145256Sjkoshy PMCMASK(s, 0x04), 2078145256Sjkoshy PMCMASK(i, 0x08), 2079145256Sjkoshy NULLMASK 2080145256Sjkoshy}; 2081145256Sjkoshy 2082145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 2083145256Sjkoshy PMCMASK(m, 0x01), 2084145256Sjkoshy PMCMASK(e, 0x02), 2085145256Sjkoshy PMCMASK(s, 0x04), 2086145256Sjkoshy PMCMASK(i, 0x08), 2087145256Sjkoshy PMCMASK(nonhw, 0x00), 2088145256Sjkoshy PMCMASK(hw, 0x10), 2089145256Sjkoshy PMCMASK(both, 0x30), 2090145256Sjkoshy NULLMASK 2091145256Sjkoshy}; 2092145256Sjkoshy 2093145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 2094145256Sjkoshy PMCMASK(nonhw, 0x00), 2095145256Sjkoshy PMCMASK(hw, 0x10), 2096145256Sjkoshy PMCMASK(both, 0x30), 2097145256Sjkoshy NULLMASK 2098145256Sjkoshy}; 2099145256Sjkoshy 2100145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 2101145256Sjkoshy PMCMASK(self, 0x00), 2102145256Sjkoshy PMCMASK(any, 0x20), 2103145256Sjkoshy NULLMASK 2104145256Sjkoshy}; 2105145256Sjkoshy 2106145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 2107145256Sjkoshy PMCMASK(nta, 0x00), 2108145256Sjkoshy PMCMASK(t1, 0x01), 2109145256Sjkoshy PMCMASK(t2, 0x02), 2110145256Sjkoshy PMCMASK(wos, 0x03), 2111145256Sjkoshy NULLMASK 2112145256Sjkoshy}; 2113145256Sjkoshy 2114145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 2115145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 2116145256Sjkoshy PMCMASK(scalar, 0x01), 2117145256Sjkoshy NULLMASK 2118145256Sjkoshy}; 2119145256Sjkoshy 2120145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 2121145256Sjkoshy PMCMASK(packed-multiply, 0x01), 2122145256Sjkoshy PMCMASK(packed-shift, 0x02), 2123145256Sjkoshy PMCMASK(pack, 0x04), 2124145256Sjkoshy PMCMASK(unpack, 0x08), 2125145256Sjkoshy PMCMASK(packed-logical, 0x10), 2126145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 2127145256Sjkoshy NULLMASK 2128145256Sjkoshy}; 2129145256Sjkoshy 2130145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 2131145256Sjkoshy PMCMASK(mmxtofp, 0x00), 2132145256Sjkoshy PMCMASK(fptommx, 0x01), 2133145256Sjkoshy NULLMASK 2134145256Sjkoshy}; 2135145256Sjkoshy 2136145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 2137145256Sjkoshy PMCMASK(es, 0x01), 2138145256Sjkoshy PMCMASK(ds, 0x02), 2139145256Sjkoshy PMCMASK(fs, 0x04), 2140145256Sjkoshy PMCMASK(gs, 0x08), 2141145256Sjkoshy NULLMASK 2142145256Sjkoshy}; 2143145256Sjkoshy 2144145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 2145145256Sjkoshy PMCMASK(all, 0x00), 2146145256Sjkoshy PMCMASK(freq, 0x02), 2147145256Sjkoshy NULLMASK 2148145256Sjkoshy}; 2149145256Sjkoshy 2150145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 2151145256Sjkoshy PMCMASK(all, 0x00), 2152145256Sjkoshy PMCMASK(loadop, 0x01), 2153145256Sjkoshy PMCMASK(stdsta, 0x02), 2154145256Sjkoshy NULLMASK 2155145256Sjkoshy}; 2156145256Sjkoshy 2157145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 2158145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2159145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 2160145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2161145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2162145256Sjkoshy NULLMASK 2163145256Sjkoshy}; 2164145256Sjkoshy 2165145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 2166145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2167145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 2168145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2169145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2170145256Sjkoshy NULLMASK 2171145256Sjkoshy}; 2172145256Sjkoshy 2173145256Sjkoshy/* P6 event parser */ 2174145256Sjkoshystatic int 2175145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 2176145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2177145256Sjkoshy{ 2178145256Sjkoshy char *e, *p, *q; 2179240164Sfabient uint64_t evmask; 2180145256Sjkoshy int count, n; 2181145256Sjkoshy const struct pmc_masks *pm, *pmask; 2182145256Sjkoshy 2183183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2184147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 2185145256Sjkoshy 2186145256Sjkoshy evmask = 0; 2187145256Sjkoshy 2188145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 2189145256Sjkoshy 2190145256Sjkoshy switch(pe) { 2191183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 2192145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 2193145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2194145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2195145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2196145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2197145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2198145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2199145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2200145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2201145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2202145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2203145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2204145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2205145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2206145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2207145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2208145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2209145256Sjkoshy P6MASKSET(any); break; 2210145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2211145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2212145256Sjkoshy P6MASKSET(ekp); break; 2213145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2214145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2215145256Sjkoshy P6MASKSET(pps); break; 2216145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2217145256Sjkoshy P6MASKSET(mite); break; 2218145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2219145256Sjkoshy P6MASKSET(fmt); break; 2220145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2221145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2222145256Sjkoshy P6MASKSET(sr); break; 2223145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2224145256Sjkoshy P6MASKSET(eet); break; 2225145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2226145256Sjkoshy P6MASKSET(efur); break; 2227145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2228145256Sjkoshy P6MASKSET(essir); break; 2229145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2230145256Sjkoshy P6MASKSET(esscir); break; 2231145256Sjkoshy default: 2232145256Sjkoshy pmask = NULL; 2233145256Sjkoshy break; 2234145256Sjkoshy } 2235145256Sjkoshy 2236145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2237145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2238145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2239145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2240145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2241145256Sjkoshy P6MASKSET(mesihw); 2242145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2243145256Sjkoshy P6MASKSET(hw); 2244145256Sjkoshy } 2245145256Sjkoshy 2246145256Sjkoshy /* Parse additional modifiers if present */ 2247145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2248145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2249145256Sjkoshy q = strchr(p, '='); 2250145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2251174406Sjkoshy return (-1); 2252145256Sjkoshy count = strtol(q, &e, 0); 2253145256Sjkoshy if (e == q || *e != '\0') 2254174406Sjkoshy return (-1); 2255145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2256147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2257147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2258145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2259145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2260145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2261145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2262145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2263145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2264145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2265145256Sjkoshy evmask = 0; 2266145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2267174406Sjkoshy return (-1); 2268145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2269145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2270145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2271145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2272145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2273145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2274145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2275145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2276145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2277145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2278145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2279145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2280145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2281145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2282145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2283145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2284145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2285145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2286145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2287145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2288145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2289145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2290145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2291174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2292174406Sjkoshy return (-1); 2293145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2294145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2295145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2296145256Sjkoshy } else 2297174406Sjkoshy return (-1); 2298145256Sjkoshy } 2299145256Sjkoshy 2300145256Sjkoshy /* post processing */ 2301145256Sjkoshy switch (pe) { 2302145256Sjkoshy 2303145256Sjkoshy /* 2304145256Sjkoshy * The following events default to an evmask of 0 2305145256Sjkoshy */ 2306145256Sjkoshy 2307145256Sjkoshy /* default => 'self' */ 2308145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2309145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2310145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2311145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2312145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2313145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2314145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2315145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2316145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2317145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2318145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2319145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2320145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2321145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2322145256Sjkoshy 2323145256Sjkoshy /* default => 'nta' */ 2324145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2325145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2326145256Sjkoshy 2327145256Sjkoshy /* default => 'packed and scalar' */ 2328145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2329145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2330145256Sjkoshy 2331145256Sjkoshy /* default => 'mmx to fp transitions' */ 2332145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2333145256Sjkoshy 2334145256Sjkoshy /* default => 'SSE Packed Single' */ 2335145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2336145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2337145256Sjkoshy 2338145256Sjkoshy /* default => 'all fused micro-ops' */ 2339145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2340145256Sjkoshy 2341145256Sjkoshy /* default => 'all transitions' */ 2342145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2343145256Sjkoshy break; 2344145256Sjkoshy 2345145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2346145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2347145256Sjkoshy break; 2348145256Sjkoshy 2349145256Sjkoshy default: 2350145256Sjkoshy /* 2351145256Sjkoshy * For all other events, set the default event mask 2352145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2353145256Sjkoshy */ 2354145256Sjkoshy if (evmask == 0 && pmask) { 2355145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2356145256Sjkoshy evmask |= pm->pm_value; 2357145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2358145256Sjkoshy } 2359145256Sjkoshy 2360145256Sjkoshy break; 2361145256Sjkoshy } 2362145256Sjkoshy 2363145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2364147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2365147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2366145256Sjkoshy 2367174406Sjkoshy return (0); 2368145256Sjkoshy} 2369145256Sjkoshy 2370147191Sjkoshy#endif 2371147191Sjkoshy 2372183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2373183725Sjkoshystatic int 2374183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2375183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2376183725Sjkoshy{ 2377183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2378183725Sjkoshy return (-1); 2379183725Sjkoshy 2380183725Sjkoshy /* TSC events must be unqualified. */ 2381183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2382183725Sjkoshy return (-1); 2383183725Sjkoshy 2384183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2385183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2386183725Sjkoshy 2387183725Sjkoshy return (0); 2388183725Sjkoshy} 2389183725Sjkoshy#endif 2390183725Sjkoshy 2391233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2392233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2393233628Sfabient EV_ALIAS(NULL, NULL) 2394233628Sfabient}; 2395233628Sfabient 2396233628Sfabientstatic int 2397233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2398233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2399233628Sfabient{ 2400233628Sfabient (void)ctrspec; 2401233628Sfabient (void)pmc_config; 2402233628Sfabient 2403242622Sdim if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST) 2404233628Sfabient return (-1); 2405233628Sfabient 2406233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2407233628Sfabient return (0); 2408233628Sfabient} 2409233628Sfabient 2410277835Sbr#if defined(__arm__) 2411200928Srpaulo#if defined(__XSCALE__) 2412200928Srpaulo 2413200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2414200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2415200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2416200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2417200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2418200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2419200928Srpaulo EV_ALIAS(NULL, NULL) 2420200928Srpaulo}; 2421200928Srpaulostatic int 2422200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2423200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2424200928Srpaulo{ 2425200928Srpaulo switch (pe) { 2426200928Srpaulo default: 2427200928Srpaulo break; 2428200928Srpaulo } 2429200928Srpaulo 2430200928Srpaulo return (0); 2431200928Srpaulo} 2432200928Srpaulo#endif 2433200928Srpaulo 2434277835Sbrstatic struct pmc_event_alias armv7_aliases[] = { 2435277835Sbr EV_ALIAS("dc-misses", "L1_DCACHE_REFILL"), 2436277835Sbr EV_ALIAS("ic-misses", "L1_ICACHE_REFILL"), 2437277835Sbr EV_ALIAS("instructions", "INSTR_EXECUTED"), 2438277835Sbr EV_ALIAS(NULL, NULL) 2439277835Sbr}; 2440277835Sbrstatic int 2441277835Sbrarmv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2442277835Sbr struct pmc_op_pmcallocate *pmc_config __unused) 2443277835Sbr{ 2444277835Sbr switch (pe) { 2445277835Sbr default: 2446277835Sbr break; 2447277835Sbr } 2448277835Sbr 2449277835Sbr return (0); 2450277835Sbr} 2451277835Sbr#endif 2452277835Sbr 2453283112Sbr#if defined(__aarch64__) 2454283112Sbrstatic struct pmc_event_alias cortex_a53_aliases[] = { 2455283112Sbr EV_ALIAS(NULL, NULL) 2456283112Sbr}; 2457283112Sbrstatic struct pmc_event_alias cortex_a57_aliases[] = { 2458283112Sbr EV_ALIAS(NULL, NULL) 2459283112Sbr}; 2460283112Sbrstatic int 2461283112Sbrarm64_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2462283112Sbr struct pmc_op_pmcallocate *pmc_config __unused) 2463283112Sbr{ 2464283112Sbr switch (pe) { 2465283112Sbr default: 2466283112Sbr break; 2467283112Sbr } 2468283112Sbr 2469283112Sbr return (0); 2470283112Sbr} 2471283112Sbr#endif 2472283112Sbr 2473204635Sgnn#if defined(__mips__) 2474204635Sgnn 2475204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2476204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2477204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2478204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2479204635Sgnn EV_ALIAS(NULL, NULL) 2480204635Sgnn}; 2481204635Sgnn 2482281098Sadrianstatic struct pmc_event_alias mips74k_aliases[] = { 2483281098Sadrian EV_ALIAS("instructions", "INSTR_EXECUTED"), 2484281098Sadrian EV_ALIAS("branches", "BRANCH_INSNS"), 2485281098Sadrian EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCH_INSNS"), 2486281098Sadrian EV_ALIAS(NULL, NULL) 2487281098Sadrian}; 2488281098Sadrian 2489233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2490233335Sgonzo EV_ALIAS("instructions", "RET"), 2491233335Sgonzo EV_ALIAS("branches", "BR"), 2492233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2493233335Sgonzo EV_ALIAS(NULL, NULL) 2494233335Sgonzo}; 2495233335Sgonzo 2496233320Sgonzo#define MIPS_KW_OS "os" 2497233320Sgonzo#define MIPS_KW_USR "usr" 2498233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2499204635Sgnn 2500204635Sgnnstatic int 2501233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2502204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2503204635Sgnn{ 2504204635Sgnn char *p; 2505204635Sgnn 2506204635Sgnn (void) pe; 2507204635Sgnn 2508204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2509204635Sgnn 2510204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2511233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2512204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2513233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2514204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2515233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2516204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2517204635Sgnn else 2518204635Sgnn return (-1); 2519204635Sgnn } 2520204635Sgnn 2521204635Sgnn return (0); 2522204635Sgnn} 2523233320Sgonzo 2524204635Sgnn#endif /* __mips__ */ 2525204635Sgnn 2526228869Sjhibbits#if defined(__powerpc__) 2527204635Sgnn 2528228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2529228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2530228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2531228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2532228869Sjhibbits EV_ALIAS(NULL, NULL) 2533228869Sjhibbits}; 2534228869Sjhibbits 2535261342Sjhibbitsstatic struct pmc_event_alias ppc970_aliases[] = { 2536261342Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2537261342Sjhibbits EV_ALIAS("cycles", "CYCLES"), 2538261342Sjhibbits EV_ALIAS(NULL, NULL) 2539261342Sjhibbits}; 2540228869Sjhibbits 2541281713Sjhibbitsstatic struct pmc_event_alias e500_aliases[] = { 2542281713Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2543281713Sjhibbits EV_ALIAS("cycles", "CYCLES"), 2544281713Sjhibbits EV_ALIAS(NULL, NULL) 2545281713Sjhibbits}; 2546281713Sjhibbits 2547261342Sjhibbits#define POWERPC_KW_OS "os" 2548261342Sjhibbits#define POWERPC_KW_USR "usr" 2549261342Sjhibbits#define POWERPC_KW_ANYTHREAD "anythread" 2550261342Sjhibbits 2551228869Sjhibbitsstatic int 2552261342Sjhibbitspowerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2553261342Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2554228869Sjhibbits{ 2555228869Sjhibbits char *p; 2556228869Sjhibbits 2557228869Sjhibbits (void) pe; 2558228869Sjhibbits 2559228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2560228869Sjhibbits 2561228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2562261342Sjhibbits if (KWMATCH(p, POWERPC_KW_OS)) 2563228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2564261342Sjhibbits else if (KWMATCH(p, POWERPC_KW_USR)) 2565228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2566261342Sjhibbits else if (KWMATCH(p, POWERPC_KW_ANYTHREAD)) 2567228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2568228869Sjhibbits else 2569228869Sjhibbits return (-1); 2570228869Sjhibbits } 2571228869Sjhibbits 2572228869Sjhibbits return (0); 2573228869Sjhibbits} 2574261342Sjhibbits 2575228869Sjhibbits#endif /* __powerpc__ */ 2576228869Sjhibbits 2577228869Sjhibbits 2578145256Sjkoshy/* 2579183725Sjkoshy * Match an event name `name' with its canonical form. 2580183725Sjkoshy * 2581185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2582185363Sjkoshy * hyphen characters are considered to match each other. 2583185363Sjkoshy * 2584183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2585183725Sjkoshy */ 2586183725Sjkoshy 2587183725Sjkoshystatic int 2588183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2589183725Sjkoshy{ 2590183725Sjkoshy int cc, nc; 2591183725Sjkoshy const unsigned char *c, *n; 2592183725Sjkoshy 2593183725Sjkoshy c = (const unsigned char *) canonicalname; 2594183725Sjkoshy n = (const unsigned char *) name; 2595183725Sjkoshy 2596183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2597183725Sjkoshy 2598185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2599185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2600183725Sjkoshy continue; 2601183725Sjkoshy 2602185363Sjkoshy if (toupper(nc) == toupper(cc)) 2603183725Sjkoshy continue; 2604183725Sjkoshy 2605185363Sjkoshy 2606183725Sjkoshy return (0); 2607183725Sjkoshy } 2608183725Sjkoshy 2609183725Sjkoshy if (*n == '\0' && *c == '\0') 2610183725Sjkoshy return (1); 2611183725Sjkoshy 2612183725Sjkoshy return (0); 2613183725Sjkoshy} 2614183725Sjkoshy 2615183725Sjkoshy/* 2616183725Sjkoshy * Match an event name against all the event named supported by a 2617183725Sjkoshy * PMC class. 2618183725Sjkoshy * 2619183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2620183725Sjkoshy */ 2621183725Sjkoshystatic const struct pmc_event_descr * 2622183725Sjkoshypmc_match_event_class(const char *name, 2623183725Sjkoshy const struct pmc_class_descr *pcd) 2624183725Sjkoshy{ 2625183725Sjkoshy size_t n; 2626183725Sjkoshy const struct pmc_event_descr *ev; 2627185363Sjkoshy 2628183725Sjkoshy ev = pcd->pm_evc_event_table; 2629183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2630183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2631183725Sjkoshy return (ev); 2632183725Sjkoshy 2633183725Sjkoshy return (NULL); 2634183725Sjkoshy} 2635183725Sjkoshy 2636183725Sjkoshystatic int 2637183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2638183725Sjkoshy{ 2639183725Sjkoshy size_t n; 2640183725Sjkoshy 2641183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2642183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2643183725Sjkoshy return (1); 2644183725Sjkoshy return (0); 2645183725Sjkoshy} 2646183725Sjkoshy 2647183725Sjkoshy/* 2648147191Sjkoshy * API entry points 2649145256Sjkoshy */ 2650145256Sjkoshy 2651147191Sjkoshyint 2652147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2653147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2654145256Sjkoshy{ 2655183725Sjkoshy size_t n; 2656147191Sjkoshy int retval; 2657147191Sjkoshy char *r, *spec_copy; 2658147191Sjkoshy const char *ctrname; 2659183725Sjkoshy const struct pmc_event_descr *ev; 2660183725Sjkoshy const struct pmc_event_alias *alias; 2661147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2662183725Sjkoshy const struct pmc_class_descr *pcd; 2663145256Sjkoshy 2664147191Sjkoshy spec_copy = NULL; 2665147191Sjkoshy retval = -1; 2666145256Sjkoshy 2667147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2668147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2669147191Sjkoshy errno = EINVAL; 2670147191Sjkoshy goto out; 2671147191Sjkoshy } 2672145256Sjkoshy 2673147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2674147191Sjkoshy if (pmc_mdep_event_aliases) 2675183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2676183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2677183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2678147191Sjkoshy break; 2679147191Sjkoshy } 2680145256Sjkoshy 2681147191Sjkoshy if (spec_copy == NULL) 2682147191Sjkoshy spec_copy = strdup(ctrspec); 2683145256Sjkoshy 2684147191Sjkoshy r = spec_copy; 2685147191Sjkoshy ctrname = strsep(&r, ","); 2686145256Sjkoshy 2687183725Sjkoshy /* 2688183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2689183725Sjkoshy * search for the event to the specified PMC class. 2690183725Sjkoshy */ 2691183725Sjkoshy ev = NULL; 2692185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2693185363Sjkoshy pcd = pmc_class_table[n]; 2694183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2695183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2696183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2697183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2698183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2699183725Sjkoshy errno = EINVAL; 2700183725Sjkoshy goto out; 2701183725Sjkoshy } 2702147191Sjkoshy break; 2703183725Sjkoshy } 2704183725Sjkoshy } 2705145256Sjkoshy 2706183725Sjkoshy /* 2707183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2708183725Sjkoshy * classes. 2709183725Sjkoshy */ 2710185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2711185363Sjkoshy pcd = pmc_class_table[n]; 2712183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2713183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2714183725Sjkoshy } 2715183725Sjkoshy 2716183725Sjkoshy if (ev == NULL) { 2717147191Sjkoshy errno = EINVAL; 2718147191Sjkoshy goto out; 2719147191Sjkoshy } 2720145256Sjkoshy 2721147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2722183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2723183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2724147191Sjkoshy pmc_config.pm_cpu = cpu; 2725147191Sjkoshy pmc_config.pm_mode = mode; 2726147191Sjkoshy pmc_config.pm_flags = flags; 2727145256Sjkoshy 2728147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2729147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2730145256Sjkoshy 2731183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2732147191Sjkoshy errno = EINVAL; 2733147191Sjkoshy goto out; 2734147191Sjkoshy } 2735145256Sjkoshy 2736147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2737147191Sjkoshy goto out; 2738145256Sjkoshy 2739147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2740145256Sjkoshy 2741147191Sjkoshy retval = 0; 2742145256Sjkoshy 2743147191Sjkoshy out: 2744147191Sjkoshy if (spec_copy) 2745147191Sjkoshy free(spec_copy); 2746145256Sjkoshy 2747174406Sjkoshy return (retval); 2748147191Sjkoshy} 2749145256Sjkoshy 2750147191Sjkoshyint 2751147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2752147191Sjkoshy{ 2753147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2754145256Sjkoshy 2755147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2756147191Sjkoshy pmc_attach_args.pm_pid = pid; 2757145256Sjkoshy 2758174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2759147191Sjkoshy} 2760145256Sjkoshy 2761147191Sjkoshyint 2762147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2763147191Sjkoshy{ 2764147191Sjkoshy unsigned int i; 2765147191Sjkoshy enum pmc_class cl; 2766145256Sjkoshy 2767147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2768147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2769147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2770147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2771174406Sjkoshy return (0); 2772147191Sjkoshy } 2773177107Sjkoshy errno = EINVAL; 2774177107Sjkoshy return (-1); 2775147191Sjkoshy} 2776145256Sjkoshy 2777147191Sjkoshyint 2778147191Sjkoshypmc_configure_logfile(int fd) 2779147191Sjkoshy{ 2780147191Sjkoshy struct pmc_op_configurelog cla; 2781145256Sjkoshy 2782147191Sjkoshy cla.pm_logfd = fd; 2783147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2784174406Sjkoshy return (-1); 2785174406Sjkoshy return (0); 2786147191Sjkoshy} 2787145256Sjkoshy 2788147191Sjkoshyint 2789147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2790147191Sjkoshy{ 2791147191Sjkoshy if (pmc_syscall == -1) { 2792147191Sjkoshy errno = ENXIO; 2793174406Sjkoshy return (-1); 2794147191Sjkoshy } 2795145256Sjkoshy 2796147219Sjkoshy *pci = &cpu_info; 2797174406Sjkoshy return (0); 2798147191Sjkoshy} 2799145256Sjkoshy 2800147191Sjkoshyint 2801147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2802147191Sjkoshy{ 2803147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2804145256Sjkoshy 2805147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2806147191Sjkoshy pmc_detach_args.pm_pid = pid; 2807174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2808147191Sjkoshy} 2809147191Sjkoshy 2810147191Sjkoshyint 2811147191Sjkoshypmc_disable(int cpu, int pmc) 2812145256Sjkoshy{ 2813147191Sjkoshy struct pmc_op_pmcadmin ssa; 2814145256Sjkoshy 2815147191Sjkoshy ssa.pm_cpu = cpu; 2816147191Sjkoshy ssa.pm_pmc = pmc; 2817147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2818174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2819147191Sjkoshy} 2820145256Sjkoshy 2821147191Sjkoshyint 2822147191Sjkoshypmc_enable(int cpu, int pmc) 2823147191Sjkoshy{ 2824147191Sjkoshy struct pmc_op_pmcadmin ssa; 2825145256Sjkoshy 2826147191Sjkoshy ssa.pm_cpu = cpu; 2827147191Sjkoshy ssa.pm_pmc = pmc; 2828147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2829174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2830147191Sjkoshy} 2831145256Sjkoshy 2832147191Sjkoshy/* 2833147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2834147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2835147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2836147191Sjkoshy * the number of event name pointers returned. 2837147191Sjkoshy * 2838147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2839147191Sjkoshy * is responsible for freeing this space when done. 2840147191Sjkoshy */ 2841147191Sjkoshyint 2842147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2843147191Sjkoshy int *nevents) 2844147191Sjkoshy{ 2845147191Sjkoshy int count; 2846147191Sjkoshy const char **names; 2847147191Sjkoshy const struct pmc_event_descr *ev; 2848147191Sjkoshy 2849147191Sjkoshy switch (cl) 2850147191Sjkoshy { 2851185363Sjkoshy case PMC_CLASS_IAF: 2852185363Sjkoshy ev = iaf_event_table; 2853185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2854185363Sjkoshy break; 2855185363Sjkoshy case PMC_CLASS_IAP: 2856185363Sjkoshy /* 2857185363Sjkoshy * Return the most appropriate set of event name 2858185363Sjkoshy * spellings for the current CPU. 2859185363Sjkoshy */ 2860185363Sjkoshy switch (cpu_info.pm_cputype) { 2861185363Sjkoshy default: 2862185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2863185363Sjkoshy ev = atom_event_table; 2864185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2865185363Sjkoshy break; 2866263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 2867263446Shiren ev = atom_silvermont_event_table; 2868263446Shiren count = PMC_EVENT_TABLE_SIZE(atom_silvermont); 2869263446Shiren break; 2870185363Sjkoshy case PMC_CPU_INTEL_CORE: 2871185363Sjkoshy ev = core_event_table; 2872185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2873185363Sjkoshy break; 2874185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2875185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2876185363Sjkoshy ev = core2_event_table; 2877185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2878185363Sjkoshy break; 2879187761Sjeff case PMC_CPU_INTEL_COREI7: 2880187761Sjeff ev = corei7_event_table; 2881187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2882187761Sjeff break; 2883267062Skib case PMC_CPU_INTEL_NEHALEM_EX: 2884267062Skib ev = nehalem_ex_event_table; 2885267062Skib count = PMC_EVENT_TABLE_SIZE(nehalem_ex); 2886267062Skib break; 2887248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2888248842Ssbruno ev = haswell_event_table; 2889248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswell); 2890248842Ssbruno break; 2891277177Srrs case PMC_CPU_INTEL_HASWELL_XEON: 2892277177Srrs ev = haswell_xeon_event_table; 2893277177Srrs count = PMC_EVENT_TABLE_SIZE(haswell_xeon); 2894277177Srrs break; 2895240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2896240164Sfabient ev = ivybridge_event_table; 2897240164Sfabient count = PMC_EVENT_TABLE_SIZE(ivybridge); 2898240164Sfabient break; 2899246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 2900246166Ssbruno ev = ivybridge_xeon_event_table; 2901246166Ssbruno count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 2902246166Ssbruno break; 2903232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2904232366Sdavide ev = sandybridge_event_table; 2905232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2906232366Sdavide break; 2907241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2908241738Ssbruno ev = sandybridge_xeon_event_table; 2909241738Ssbruno count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 2910241738Ssbruno break; 2911206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2912206089Sfabient ev = westmere_event_table; 2913206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2914206089Sfabient break; 2915267062Skib case PMC_CPU_INTEL_WESTMERE_EX: 2916267062Skib ev = westmere_ex_event_table; 2917267062Skib count = PMC_EVENT_TABLE_SIZE(westmere_ex); 2918267062Skib break; 2919185363Sjkoshy } 2920185363Sjkoshy break; 2921206089Sfabient case PMC_CLASS_UCF: 2922206089Sfabient ev = ucf_event_table; 2923206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2924206089Sfabient break; 2925206089Sfabient case PMC_CLASS_UCP: 2926206089Sfabient /* 2927206089Sfabient * Return the most appropriate set of event name 2928206089Sfabient * spellings for the current CPU. 2929206089Sfabient */ 2930206089Sfabient switch (cpu_info.pm_cputype) { 2931206089Sfabient default: 2932206089Sfabient case PMC_CPU_INTEL_COREI7: 2933206089Sfabient ev = corei7uc_event_table; 2934206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2935206089Sfabient break; 2936248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2937248842Ssbruno ev = haswelluc_event_table; 2938248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswelluc); 2939248842Ssbruno break; 2940232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2941232366Sdavide ev = sandybridgeuc_event_table; 2942232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2943232366Sdavide break; 2944206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2945206089Sfabient ev = westmereuc_event_table; 2946206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2947206089Sfabient break; 2948206089Sfabient } 2949206089Sfabient break; 2950147191Sjkoshy case PMC_CLASS_TSC: 2951183725Sjkoshy ev = tsc_event_table; 2952183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2953145256Sjkoshy break; 2954147191Sjkoshy case PMC_CLASS_K7: 2955183725Sjkoshy ev = k7_event_table; 2956183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2957145256Sjkoshy break; 2958147191Sjkoshy case PMC_CLASS_K8: 2959183725Sjkoshy ev = k8_event_table; 2960183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2961145256Sjkoshy break; 2962183725Sjkoshy case PMC_CLASS_P4: 2963183725Sjkoshy ev = p4_event_table; 2964183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2965183725Sjkoshy break; 2966147191Sjkoshy case PMC_CLASS_P5: 2967183725Sjkoshy ev = p5_event_table; 2968183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2969145256Sjkoshy break; 2970147191Sjkoshy case PMC_CLASS_P6: 2971183725Sjkoshy ev = p6_event_table; 2972183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2973145256Sjkoshy break; 2974200928Srpaulo case PMC_CLASS_XSCALE: 2975200928Srpaulo ev = xscale_event_table; 2976200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2977200928Srpaulo break; 2978277835Sbr case PMC_CLASS_ARMV7: 2979277835Sbr ev = armv7_event_table; 2980277835Sbr count = PMC_EVENT_TABLE_SIZE(armv7); 2981277835Sbr break; 2982283112Sbr case PMC_CLASS_ARMV8: 2983283112Sbr switch (cpu_info.pm_cputype) { 2984283112Sbr default: 2985283112Sbr case PMC_CPU_ARMV8_CORTEX_A53: 2986283112Sbr ev = cortex_a53_event_table; 2987283112Sbr count = PMC_EVENT_TABLE_SIZE(cortex_a53); 2988283112Sbr break; 2989283112Sbr case PMC_CPU_ARMV8_CORTEX_A57: 2990283112Sbr ev = cortex_a57_event_table; 2991283112Sbr count = PMC_EVENT_TABLE_SIZE(cortex_a57); 2992283112Sbr break; 2993283112Sbr } 2994283112Sbr break; 2995204635Sgnn case PMC_CLASS_MIPS24K: 2996204635Sgnn ev = mips24k_event_table; 2997204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2998204635Sgnn break; 2999281098Sadrian case PMC_CLASS_MIPS74K: 3000281098Sadrian ev = mips74k_event_table; 3001281098Sadrian count = PMC_EVENT_TABLE_SIZE(mips74k); 3002281098Sadrian break; 3003233335Sgonzo case PMC_CLASS_OCTEON: 3004233335Sgonzo ev = octeon_event_table; 3005233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 3006233335Sgonzo break; 3007228869Sjhibbits case PMC_CLASS_PPC7450: 3008228869Sjhibbits ev = ppc7450_event_table; 3009228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 3010228869Sjhibbits break; 3011261342Sjhibbits case PMC_CLASS_PPC970: 3012261342Sjhibbits ev = ppc970_event_table; 3013261342Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc970); 3014261342Sjhibbits break; 3015281713Sjhibbits case PMC_CLASS_E500: 3016281713Sjhibbits ev = e500_event_table; 3017281713Sjhibbits count = PMC_EVENT_TABLE_SIZE(e500); 3018281713Sjhibbits break; 3019233628Sfabient case PMC_CLASS_SOFT: 3020233628Sfabient ev = soft_event_table; 3021233628Sfabient count = soft_event_info.pm_nevent; 3022233628Sfabient break; 3023145256Sjkoshy default: 3024147191Sjkoshy errno = EINVAL; 3025174406Sjkoshy return (-1); 3026145256Sjkoshy } 3027145256Sjkoshy 3028147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 3029174406Sjkoshy return (-1); 3030145256Sjkoshy 3031147191Sjkoshy *eventnames = names; 3032147191Sjkoshy *nevents = count; 3033145256Sjkoshy 3034147191Sjkoshy for (;count--; ev++, names++) 3035147191Sjkoshy *names = ev->pm_ev_name; 3036233628Sfabient 3037174406Sjkoshy return (0); 3038147191Sjkoshy} 3039145256Sjkoshy 3040147191Sjkoshyint 3041147191Sjkoshypmc_flush_logfile(void) 3042147191Sjkoshy{ 3043174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 3044147191Sjkoshy} 3045145256Sjkoshy 3046147191Sjkoshyint 3047226514Sfabientpmc_close_logfile(void) 3048226514Sfabient{ 3049226514Sfabient return (PMC_CALL(CLOSELOG,0)); 3050226514Sfabient} 3051226514Sfabient 3052226514Sfabientint 3053147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 3054147191Sjkoshy{ 3055147191Sjkoshy struct pmc_op_getdriverstats gms; 3056145256Sjkoshy 3057147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 3058174406Sjkoshy return (-1); 3059145256Sjkoshy 3060147191Sjkoshy /* copy out fields in the current userland<->library interface */ 3061147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 3062147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 3063147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 3064147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 3065147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 3066147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 3067147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 3068147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 3069174406Sjkoshy return (0); 3070147191Sjkoshy} 3071145256Sjkoshy 3072147191Sjkoshyint 3073147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 3074147191Sjkoshy{ 3075147191Sjkoshy struct pmc_op_getmsr gm; 3076147191Sjkoshy 3077147191Sjkoshy gm.pm_pmcid = pmc; 3078147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 3079174406Sjkoshy return (-1); 3080147191Sjkoshy *msr = gm.pm_msr; 3081174406Sjkoshy return (0); 3082145256Sjkoshy} 3083145256Sjkoshy 3084145256Sjkoshyint 3085145256Sjkoshypmc_init(void) 3086145256Sjkoshy{ 3087145256Sjkoshy int error, pmc_mod_id; 3088147219Sjkoshy unsigned int n; 3089145256Sjkoshy uint32_t abi_version; 3090145256Sjkoshy struct module_stat pmc_modstat; 3091147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 3092198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 3093198433Sjkoshy int cpu_has_iaf_counters; 3094198433Sjkoshy unsigned int t; 3095198433Sjkoshy#endif 3096145256Sjkoshy 3097145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 3098174406Sjkoshy return (0); 3099145256Sjkoshy 3100145256Sjkoshy /* retrieve the system call number from the KLD */ 3101145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 3102174406Sjkoshy return (-1); 3103145256Sjkoshy 3104145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 3105145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 3106174406Sjkoshy return (-1); 3107145256Sjkoshy 3108145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 3109145256Sjkoshy 3110147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 3111147191Sjkoshy abi_version = PMC_VERSION; 3112145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 3113145256Sjkoshy return (pmc_syscall = -1); 3114145256Sjkoshy 3115147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 3116147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 3117145256Sjkoshy errno = EPROGMISMATCH; 3118145256Sjkoshy return (pmc_syscall = -1); 3119145256Sjkoshy } 3120145256Sjkoshy 3121147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 3122145256Sjkoshy return (pmc_syscall = -1); 3123145256Sjkoshy 3124147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 3125147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 3126147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 3127147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 3128147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 3129147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 3130147219Sjkoshy 3131185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 3132185363Sjkoshy sizeof(struct pmc_class_descr *)); 3133185363Sjkoshy 3134185363Sjkoshy if (pmc_class_table == NULL) 3135185363Sjkoshy return (-1); 3136185363Sjkoshy 3137198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 3138198433Sjkoshy pmc_class_table[n] = NULL; 3139185363Sjkoshy 3140185363Sjkoshy /* 3141233628Sfabient * Get soft events list. 3142233628Sfabient */ 3143233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 3144233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 3145233628Sfabient return (pmc_syscall = -1); 3146233628Sfabient 3147233628Sfabient /* Map soft events to static list. */ 3148233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 3149233628Sfabient soft_event_table[n].pm_ev_name = 3150233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 3151233628Sfabient soft_event_table[n].pm_ev_code = 3152233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 3153233628Sfabient } 3154233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 3155233628Sfabient soft_event_info.pm_nevent; 3156233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 3157233628Sfabient soft_event_table; 3158233628Sfabient 3159233628Sfabient /* 3160185363Sjkoshy * Fill in the class table. 3161185363Sjkoshy */ 3162185363Sjkoshy n = 0; 3163233628Sfabient 3164233628Sfabient /* Fill soft events information. */ 3165233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 3166185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 3167233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 3168233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 3169198433Sjkoshy 3170198433Sjkoshy /* 3171198433Sjkoshy * Check if this CPU has fixed function counters. 3172198433Sjkoshy */ 3173198433Sjkoshy cpu_has_iaf_counters = 0; 3174198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 3175212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 3176212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 3177198433Sjkoshy cpu_has_iaf_counters = 1; 3178185363Sjkoshy#endif 3179185363Sjkoshy 3180183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 3181183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 3182183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 3183183725Sjkoshy pmc_mdep_class_list_size = \ 3184183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 3185183725Sjkoshy } while (0) 3186183725Sjkoshy 3187198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 3188198433Sjkoshy PMC_MDEP_INIT(C); \ 3189212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 3190212224Sfabient if (!cpu_has_iaf_counters) \ 3191198433Sjkoshy pmc_mdep_event_aliases = \ 3192198433Sjkoshy C##_aliases_without_iaf; \ 3193198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 3194198433Sjkoshy } while (0) 3195198433Sjkoshy 3196183725Sjkoshy /* Configure the event name parser. */ 3197145256Sjkoshy switch (cpu_info.pm_cputype) { 3198145340Smarcel#if defined(__i386__) 3199145256Sjkoshy case PMC_CPU_AMD_K7: 3200183725Sjkoshy PMC_MDEP_INIT(k7); 3201185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 3202145256Sjkoshy break; 3203145256Sjkoshy case PMC_CPU_INTEL_P5: 3204183725Sjkoshy PMC_MDEP_INIT(p5); 3205185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 3206145256Sjkoshy break; 3207145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 3208145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 3209145256Sjkoshy case PMC_CPU_INTEL_PIII: 3210145256Sjkoshy case PMC_CPU_INTEL_PM: 3211183725Sjkoshy PMC_MDEP_INIT(p6); 3212185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 3213145256Sjkoshy break; 3214147759Sjkoshy#endif 3215147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 3216183725Sjkoshy case PMC_CPU_AMD_K8: 3217183725Sjkoshy PMC_MDEP_INIT(k8); 3218185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 3219183725Sjkoshy break; 3220185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3221198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 3222185363Sjkoshy break; 3223263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3224263446Shiren PMC_MDEP_INIT_INTEL_V2(atom_silvermont); 3225263446Shiren break; 3226185363Sjkoshy case PMC_CPU_INTEL_CORE: 3227185363Sjkoshy PMC_MDEP_INIT(core); 3228202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 3229185363Sjkoshy break; 3230185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3231185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3232198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 3233185363Sjkoshy break; 3234187761Sjeff case PMC_CPU_INTEL_COREI7: 3235206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3236206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 3237198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 3238187761Sjeff break; 3239267062Skib case PMC_CPU_INTEL_NEHALEM_EX: 3240267062Skib PMC_MDEP_INIT_INTEL_V2(nehalem_ex); 3241267062Skib break; 3242248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3243248842Ssbruno pmc_class_table[n++] = &ucf_class_table_descr; 3244248842Ssbruno pmc_class_table[n++] = &haswelluc_class_table_descr; 3245248842Ssbruno PMC_MDEP_INIT_INTEL_V2(haswell); 3246248842Ssbruno break; 3247277177Srrs case PMC_CPU_INTEL_HASWELL_XEON: 3248277177Srrs PMC_MDEP_INIT_INTEL_V2(haswell_xeon); 3249277177Srrs break; 3250240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3251240164Sfabient PMC_MDEP_INIT_INTEL_V2(ivybridge); 3252240164Sfabient break; 3253246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3254246166Ssbruno PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon); 3255246166Ssbruno break; 3256232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3257232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 3258232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 3259232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 3260232366Sdavide break; 3261241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3262241738Ssbruno PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); 3263241738Ssbruno break; 3264206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3265206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3266206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 3267206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 3268206089Sfabient break; 3269267062Skib case PMC_CPU_INTEL_WESTMERE_EX: 3270267062Skib PMC_MDEP_INIT_INTEL_V2(westmere_ex); 3271267062Skib break; 3272145256Sjkoshy case PMC_CPU_INTEL_PIV: 3273183725Sjkoshy PMC_MDEP_INIT(p4); 3274185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 3275145256Sjkoshy break; 3276145256Sjkoshy#endif 3277233628Sfabient case PMC_CPU_GENERIC: 3278233628Sfabient PMC_MDEP_INIT(generic); 3279233628Sfabient break; 3280277835Sbr#if defined(__arm__) 3281200928Srpaulo#if defined(__XSCALE__) 3282200928Srpaulo case PMC_CPU_INTEL_XSCALE: 3283200928Srpaulo PMC_MDEP_INIT(xscale); 3284200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 3285200928Srpaulo break; 3286200928Srpaulo#endif 3287277835Sbr case PMC_CPU_ARMV7: 3288277835Sbr PMC_MDEP_INIT(armv7); 3289277835Sbr pmc_class_table[n] = &armv7_class_table_descr; 3290277835Sbr break; 3291277835Sbr#endif 3292283112Sbr#if defined(__aarch64__) 3293283112Sbr case PMC_CPU_ARMV8_CORTEX_A53: 3294283112Sbr PMC_MDEP_INIT(cortex_a53); 3295283112Sbr pmc_class_table[n] = &cortex_a53_class_table_descr; 3296283112Sbr break; 3297283112Sbr case PMC_CPU_ARMV8_CORTEX_A57: 3298283112Sbr PMC_MDEP_INIT(cortex_a57); 3299283112Sbr pmc_class_table[n] = &cortex_a57_class_table_descr; 3300283112Sbr break; 3301283112Sbr#endif 3302204635Sgnn#if defined(__mips__) 3303204635Sgnn case PMC_CPU_MIPS_24K: 3304204635Sgnn PMC_MDEP_INIT(mips24k); 3305204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 3306204635Sgnn break; 3307281098Sadrian case PMC_CPU_MIPS_74K: 3308281098Sadrian PMC_MDEP_INIT(mips74k); 3309281098Sadrian pmc_class_table[n] = &mips74k_class_table_descr; 3310281098Sadrian break; 3311233335Sgonzo case PMC_CPU_MIPS_OCTEON: 3312233335Sgonzo PMC_MDEP_INIT(octeon); 3313233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 3314233335Sgonzo break; 3315204635Sgnn#endif /* __mips__ */ 3316228869Sjhibbits#if defined(__powerpc__) 3317228869Sjhibbits case PMC_CPU_PPC_7450: 3318228869Sjhibbits PMC_MDEP_INIT(ppc7450); 3319228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 3320228869Sjhibbits break; 3321261342Sjhibbits case PMC_CPU_PPC_970: 3322261342Sjhibbits PMC_MDEP_INIT(ppc970); 3323261342Sjhibbits pmc_class_table[n] = &ppc970_class_table_descr; 3324261342Sjhibbits break; 3325281713Sjhibbits case PMC_CPU_PPC_E500: 3326281713Sjhibbits PMC_MDEP_INIT(e500); 3327281713Sjhibbits pmc_class_table[n] = &e500_class_table_descr; 3328281713Sjhibbits break; 3329228869Sjhibbits#endif 3330145256Sjkoshy default: 3331145256Sjkoshy /* 3332145256Sjkoshy * Some kind of CPU this version of the library knows nothing 3333145256Sjkoshy * about. This shouldn't happen since the abi version check 3334145256Sjkoshy * should have caught this. 3335145256Sjkoshy */ 3336145256Sjkoshy errno = ENXIO; 3337145256Sjkoshy return (pmc_syscall = -1); 3338145256Sjkoshy } 3339145256Sjkoshy 3340174406Sjkoshy return (0); 3341145256Sjkoshy} 3342145256Sjkoshy 3343147191Sjkoshyconst char * 3344147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 3345145256Sjkoshy{ 3346147191Sjkoshy int i; 3347145256Sjkoshy 3348147191Sjkoshy /* 3349147191Sjkoshy * 'cap' should have a single bit set and should be in 3350147191Sjkoshy * range. 3351147191Sjkoshy */ 3352147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 3353147191Sjkoshy cap > PMC_CAP_LAST) { 3354145256Sjkoshy errno = EINVAL; 3355174406Sjkoshy return (NULL); 3356145256Sjkoshy } 3357145256Sjkoshy 3358147191Sjkoshy i = ffs(cap); 3359174406Sjkoshy return (pmc_capability_names[i - 1]); 3360147191Sjkoshy} 3361145256Sjkoshy 3362147191Sjkoshyconst char * 3363147191Sjkoshypmc_name_of_class(enum pmc_class pc) 3364147191Sjkoshy{ 3365147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 3366147191Sjkoshy pc <= PMC_CLASS_LAST) 3367174406Sjkoshy return (pmc_class_names[pc]); 3368145256Sjkoshy 3369147191Sjkoshy errno = EINVAL; 3370174406Sjkoshy return (NULL); 3371147191Sjkoshy} 3372145256Sjkoshy 3373147191Sjkoshyconst char * 3374147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3375147191Sjkoshy{ 3376183725Sjkoshy size_t n; 3377183725Sjkoshy 3378183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3379183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3380183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3381183725Sjkoshy 3382147191Sjkoshy errno = EINVAL; 3383174406Sjkoshy return (NULL); 3384147191Sjkoshy} 3385145256Sjkoshy 3386147191Sjkoshyconst char * 3387147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3388147191Sjkoshy{ 3389147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3390147191Sjkoshy pd <= PMC_DISP_LAST) 3391174406Sjkoshy return (pmc_disposition_names[pd]); 3392145256Sjkoshy 3393147191Sjkoshy errno = EINVAL; 3394174406Sjkoshy return (NULL); 3395147191Sjkoshy} 3396145256Sjkoshy 3397147191Sjkoshyconst char * 3398185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3399147191Sjkoshy{ 3400183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3401145256Sjkoshy 3402183725Sjkoshy ev = evfence = NULL; 3403185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3404185363Sjkoshy ev = iaf_event_table; 3405185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3406185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3407185363Sjkoshy switch (cpu) { 3408185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3409185363Sjkoshy ev = atom_event_table; 3410185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3411185363Sjkoshy break; 3412263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3413263446Shiren ev = atom_silvermont_event_table; 3414263446Shiren evfence = atom_silvermont_event_table + 3415263446Shiren PMC_EVENT_TABLE_SIZE(atom_silvermont); 3416263446Shiren break; 3417185363Sjkoshy case PMC_CPU_INTEL_CORE: 3418185363Sjkoshy ev = core_event_table; 3419185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3420185363Sjkoshy break; 3421185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3422185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3423185363Sjkoshy ev = core2_event_table; 3424185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3425185363Sjkoshy break; 3426187761Sjeff case PMC_CPU_INTEL_COREI7: 3427187761Sjeff ev = corei7_event_table; 3428187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3429187761Sjeff break; 3430267062Skib case PMC_CPU_INTEL_NEHALEM_EX: 3431267062Skib ev = nehalem_ex_event_table; 3432267062Skib evfence = nehalem_ex_event_table + 3433267062Skib PMC_EVENT_TABLE_SIZE(nehalem_ex); 3434267062Skib break; 3435248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3436248842Ssbruno ev = haswell_event_table; 3437248842Ssbruno evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell); 3438248842Ssbruno break; 3439277177Srrs case PMC_CPU_INTEL_HASWELL_XEON: 3440277177Srrs ev = haswell_xeon_event_table; 3441277177Srrs evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon); 3442277177Srrs break; 3443277177Srrs 3444240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3445240164Sfabient ev = ivybridge_event_table; 3446240164Sfabient evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); 3447240164Sfabient break; 3448246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3449246166Ssbruno ev = ivybridge_xeon_event_table; 3450246166Ssbruno evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 3451246166Ssbruno break; 3452232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3453232366Sdavide ev = sandybridge_event_table; 3454232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3455232366Sdavide break; 3456241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3457241738Ssbruno ev = sandybridge_xeon_event_table; 3458241738Ssbruno evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 3459241738Ssbruno break; 3460206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3461206089Sfabient ev = westmere_event_table; 3462206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3463206089Sfabient break; 3464267062Skib case PMC_CPU_INTEL_WESTMERE_EX: 3465267062Skib ev = westmere_ex_event_table; 3466267062Skib evfence = westmere_ex_event_table + 3467267062Skib PMC_EVENT_TABLE_SIZE(westmere_ex); 3468267062Skib break; 3469185363Sjkoshy default: /* Unknown CPU type. */ 3470185363Sjkoshy break; 3471185363Sjkoshy } 3472206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3473206089Sfabient ev = ucf_event_table; 3474206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3475206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3476206089Sfabient switch (cpu) { 3477206089Sfabient case PMC_CPU_INTEL_COREI7: 3478206089Sfabient ev = corei7uc_event_table; 3479206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3480206089Sfabient break; 3481232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3482232366Sdavide ev = sandybridgeuc_event_table; 3483232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3484232366Sdavide break; 3485206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3486206089Sfabient ev = westmereuc_event_table; 3487206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3488206089Sfabient break; 3489206089Sfabient default: /* Unknown CPU type. */ 3490206089Sfabient break; 3491206089Sfabient } 3492206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3493183725Sjkoshy ev = k7_event_table; 3494183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3495183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3496183725Sjkoshy ev = k8_event_table; 3497183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3498183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3499183725Sjkoshy ev = p4_event_table; 3500183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3501183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3502183725Sjkoshy ev = p5_event_table; 3503183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3504183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3505183725Sjkoshy ev = p6_event_table; 3506183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3507200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3508200928Srpaulo ev = xscale_event_table; 3509200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3510277835Sbr } else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) { 3511277835Sbr ev = armv7_event_table; 3512277835Sbr evfence = armv7_event_table + PMC_EVENT_TABLE_SIZE(armv7); 3513283112Sbr } else if (pe >= PMC_EV_ARMV8_FIRST && pe <= PMC_EV_ARMV8_LAST) { 3514283112Sbr switch (cpu) { 3515283112Sbr case PMC_CPU_ARMV8_CORTEX_A53: 3516283112Sbr ev = cortex_a53_event_table; 3517283112Sbr evfence = cortex_a53_event_table + PMC_EVENT_TABLE_SIZE(cortex_a53); 3518283112Sbr break; 3519283112Sbr case PMC_CPU_ARMV8_CORTEX_A57: 3520283112Sbr ev = cortex_a57_event_table; 3521283112Sbr evfence = cortex_a57_event_table + PMC_EVENT_TABLE_SIZE(cortex_a57); 3522283112Sbr break; 3523283112Sbr default: /* Unknown CPU type. */ 3524283112Sbr break; 3525283112Sbr } 3526204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3527204635Sgnn ev = mips24k_event_table; 3528233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3529281098Sadrian } else if (pe >= PMC_EV_MIPS74K_FIRST && pe <= PMC_EV_MIPS74K_LAST) { 3530281098Sadrian ev = mips74k_event_table; 3531281098Sadrian evfence = mips74k_event_table + PMC_EVENT_TABLE_SIZE(mips74k); 3532233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3533233335Sgonzo ev = octeon_event_table; 3534233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3535228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3536228869Sjhibbits ev = ppc7450_event_table; 3537233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3538261342Sjhibbits } else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) { 3539261342Sjhibbits ev = ppc970_event_table; 3540261342Sjhibbits evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970); 3541281713Sjhibbits } else if (pe >= PMC_EV_E500_FIRST && pe <= PMC_EV_E500_LAST) { 3542281713Sjhibbits ev = e500_event_table; 3543281713Sjhibbits evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500); 3544183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3545183725Sjkoshy ev = tsc_event_table; 3546183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3547242622Sdim } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { 3548233628Sfabient ev = soft_event_table; 3549233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3550183725Sjkoshy } 3551183725Sjkoshy 3552183725Sjkoshy for (; ev != evfence; ev++) 3553183725Sjkoshy if (pe == ev->pm_ev_code) 3554183725Sjkoshy return (ev->pm_ev_name); 3555183725Sjkoshy 3556185363Sjkoshy return (NULL); 3557185363Sjkoshy} 3558185363Sjkoshy 3559185363Sjkoshyconst char * 3560185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3561185363Sjkoshy{ 3562185363Sjkoshy const char *n; 3563185363Sjkoshy 3564185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3565185363Sjkoshy return (n); 3566185363Sjkoshy 3567147191Sjkoshy errno = EINVAL; 3568174406Sjkoshy return (NULL); 3569147191Sjkoshy} 3570145256Sjkoshy 3571147191Sjkoshyconst char * 3572147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3573147191Sjkoshy{ 3574147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3575147191Sjkoshy pm <= PMC_MODE_LAST) 3576174406Sjkoshy return (pmc_mode_names[pm]); 3577145256Sjkoshy 3578147191Sjkoshy errno = EINVAL; 3579174406Sjkoshy return (NULL); 3580147191Sjkoshy} 3581145256Sjkoshy 3582147191Sjkoshyconst char * 3583147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3584147191Sjkoshy{ 3585147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3586147191Sjkoshy ps <= PMC_STATE_LAST) 3587174406Sjkoshy return (pmc_state_names[ps]); 3588145256Sjkoshy 3589147191Sjkoshy errno = EINVAL; 3590174406Sjkoshy return (NULL); 3591145256Sjkoshy} 3592145256Sjkoshy 3593145256Sjkoshyint 3594147191Sjkoshypmc_ncpu(void) 3595145256Sjkoshy{ 3596147191Sjkoshy if (pmc_syscall == -1) { 3597147191Sjkoshy errno = ENXIO; 3598174406Sjkoshy return (-1); 3599147191Sjkoshy } 3600145256Sjkoshy 3601174406Sjkoshy return (cpu_info.pm_ncpu); 3602145256Sjkoshy} 3603145256Sjkoshy 3604145256Sjkoshyint 3605147191Sjkoshypmc_npmc(int cpu) 3606145256Sjkoshy{ 3607147191Sjkoshy if (pmc_syscall == -1) { 3608147191Sjkoshy errno = ENXIO; 3609174406Sjkoshy return (-1); 3610147191Sjkoshy } 3611145256Sjkoshy 3612147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3613147191Sjkoshy errno = EINVAL; 3614174406Sjkoshy return (-1); 3615147191Sjkoshy } 3616145256Sjkoshy 3617174406Sjkoshy return (cpu_info.pm_npmc); 3618145256Sjkoshy} 3619145256Sjkoshy 3620145256Sjkoshyint 3621147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3622145256Sjkoshy{ 3623147191Sjkoshy int nbytes, npmc; 3624147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3625145256Sjkoshy 3626147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3627174406Sjkoshy return (-1); 3628145256Sjkoshy 3629147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3630147191Sjkoshy npmc * sizeof(struct pmc_info); 3631145256Sjkoshy 3632147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3633174406Sjkoshy return (-1); 3634145256Sjkoshy 3635147191Sjkoshy pmci->pm_cpu = cpu; 3636145256Sjkoshy 3637147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3638147191Sjkoshy free(pmci); 3639174406Sjkoshy return (-1); 3640147191Sjkoshy } 3641145256Sjkoshy 3642147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3643147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3644174406Sjkoshy return (0); 3645145256Sjkoshy} 3646145256Sjkoshy 3647145256Sjkoshyint 3648145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3649145256Sjkoshy{ 3650145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3651145256Sjkoshy 3652145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3653145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3654145256Sjkoshy pmc_read_op.pm_value = -1; 3655145256Sjkoshy 3656145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3657174406Sjkoshy return (-1); 3658145256Sjkoshy 3659145256Sjkoshy *value = pmc_read_op.pm_value; 3660174406Sjkoshy return (0); 3661145256Sjkoshy} 3662145256Sjkoshy 3663145256Sjkoshyint 3664147191Sjkoshypmc_release(pmc_id_t pmc) 3665145256Sjkoshy{ 3666147191Sjkoshy struct pmc_op_simple pmc_release_args; 3667145256Sjkoshy 3668147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3669174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3670145256Sjkoshy} 3671145256Sjkoshy 3672145256Sjkoshyint 3673145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3674145256Sjkoshy{ 3675145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3676145256Sjkoshy 3677145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3678145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3679145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3680145256Sjkoshy 3681145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3682174406Sjkoshy return (-1); 3683145256Sjkoshy 3684145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3685174406Sjkoshy return (0); 3686145256Sjkoshy} 3687145256Sjkoshy 3688145256Sjkoshyint 3689145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3690145256Sjkoshy{ 3691145256Sjkoshy struct pmc_op_pmcsetcount sc; 3692145256Sjkoshy 3693145256Sjkoshy sc.pm_pmcid = pmc; 3694145256Sjkoshy sc.pm_count = value; 3695145256Sjkoshy 3696145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3697174406Sjkoshy return (-1); 3698174406Sjkoshy return (0); 3699145256Sjkoshy} 3700145256Sjkoshy 3701145256Sjkoshyint 3702147191Sjkoshypmc_start(pmc_id_t pmc) 3703145256Sjkoshy{ 3704147191Sjkoshy struct pmc_op_simple pmc_start_args; 3705145256Sjkoshy 3706147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3707174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3708145256Sjkoshy} 3709145256Sjkoshy 3710145256Sjkoshyint 3711147191Sjkoshypmc_stop(pmc_id_t pmc) 3712145256Sjkoshy{ 3713147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3714145256Sjkoshy 3715147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3716174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3717145256Sjkoshy} 3718145256Sjkoshy 3719145256Sjkoshyint 3720145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3721145774Sjkoshy{ 3722145774Sjkoshy unsigned int i; 3723145774Sjkoshy enum pmc_class cl; 3724145774Sjkoshy 3725145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3726145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3727145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3728145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3729174406Sjkoshy return (0); 3730145774Sjkoshy } 3731177107Sjkoshy errno = EINVAL; 3732177107Sjkoshy return (-1); 3733145774Sjkoshy} 3734145774Sjkoshy 3735145774Sjkoshyint 3736147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3737145774Sjkoshy{ 3738147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3739145774Sjkoshy 3740147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3741147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3742147191Sjkoshy pmc_write_op.pm_value = value; 3743174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3744145256Sjkoshy} 3745145256Sjkoshy 3746145256Sjkoshyint 3747147191Sjkoshypmc_writelog(uint32_t userdata) 3748145256Sjkoshy{ 3749147191Sjkoshy struct pmc_op_writelog wl; 3750145256Sjkoshy 3751147191Sjkoshy wl.pm_userdata = userdata; 3752174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3753145256Sjkoshy} 3754