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: stable/10/lib/libpmc/libpmc.c 320137 2017-06-20 08:01:13Z avg $"); 29145256Sjkoshy 30145256Sjkoshy#include <sys/types.h> 31263122Sjhibbits#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 77200928Srpaulo#if defined(__XSCALE__) 78200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 79200928Srpaulo struct pmc_op_pmcallocate *_pmc_config); 80200928Srpaulo#endif 81204635Sgnn#if defined(__mips__) 82233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 83204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 84204635Sgnn#endif /* __mips__ */ 85233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 86233628Sfabient struct pmc_op_pmcallocate *_pmc_config); 87204635Sgnn 88228869Sjhibbits#if defined(__powerpc__) 89263122Sjhibbitsstatic int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec, 90228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 91228869Sjhibbits#endif /* __powerpc__ */ 92204635Sgnn 93145256Sjkoshy#define PMC_CALL(cmd, params) \ 94145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 95145256Sjkoshy 96145256Sjkoshy/* 97145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 98145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 99145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 100145256Sjkoshy * lookup table. 101145256Sjkoshy */ 102145256Sjkoshystruct pmc_event_alias { 103145256Sjkoshy const char *pm_alias; 104145256Sjkoshy const char *pm_spec; 105145256Sjkoshy}; 106145256Sjkoshy 107145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 108145256Sjkoshy 109145256Sjkoshy/* 110183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 111145256Sjkoshy * to integer codes used by the PMC KLD. 112145256Sjkoshy */ 113145256Sjkoshystruct pmc_event_descr { 114145256Sjkoshy const char *pm_ev_name; 115145256Sjkoshy enum pmc_event pm_ev_code; 116145256Sjkoshy}; 117145256Sjkoshy 118183725Sjkoshy/* 119183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 120183725Sjkoshy * event names to event tables and other PMC class data. 121183725Sjkoshy */ 122183725Sjkoshystruct pmc_class_descr { 123183725Sjkoshy const char *pm_evc_name; 124183725Sjkoshy size_t pm_evc_name_size; 125183725Sjkoshy enum pmc_class pm_evc_class; 126183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 127183725Sjkoshy size_t pm_evc_event_table_size; 128183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 129183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 130183725Sjkoshy}; 131183725Sjkoshy 132183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 133183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 134183725Sjkoshy 135183725Sjkoshy#undef __PMC_EV 136183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 137183725Sjkoshy 138183725Sjkoshy/* 139185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 140183725Sjkoshy * 141185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 142183725Sjkoshy */ 143185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 144183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 145183725Sjkoshy { \ 146183725Sjkoshy __PMC_EV_##C() \ 147185363Sjkoshy } 148185363Sjkoshy 149185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 150185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 151185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 152185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 153185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 154185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 155200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 156204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 157233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON); 158206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 159228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 160263122SjhibbitsPMC_CLASSDEP_TABLE(ppc970, PPC970); 161185363Sjkoshy 162233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; 163233628Sfabient 164185363Sjkoshy#undef __PMC_EV_ALIAS 165185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 166185363Sjkoshy 167185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 168185363Sjkoshy{ 169185363Sjkoshy __PMC_EV_ALIAS_ATOM() 170185363Sjkoshy}; 171185363Sjkoshy 172266911Shirenstatic const struct pmc_event_descr atom_silvermont_event_table[] = 173266911Shiren{ 174266911Shiren __PMC_EV_ALIAS_ATOM_SILVERMONT() 175266911Shiren}; 176266911Shiren 177185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 178185363Sjkoshy{ 179185363Sjkoshy __PMC_EV_ALIAS_CORE() 180185363Sjkoshy}; 181185363Sjkoshy 182185363Sjkoshy 183185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 184185363Sjkoshy{ 185185363Sjkoshy __PMC_EV_ALIAS_CORE2() 186185363Sjkoshy}; 187185363Sjkoshy 188187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 189187761Sjeff{ 190187761Sjeff __PMC_EV_ALIAS_COREI7() 191187761Sjeff}; 192187761Sjeff 193267602Skibstatic const struct pmc_event_descr nehalem_ex_event_table[] = 194267602Skib{ 195267602Skib __PMC_EV_ALIAS_COREI7() 196267602Skib}; 197267602Skib 198248842Ssbrunostatic const struct pmc_event_descr haswell_event_table[] = 199248842Ssbruno{ 200248842Ssbruno __PMC_EV_ALIAS_HASWELL() 201248842Ssbruno}; 202248842Ssbruno 203280455Srrsstatic const struct pmc_event_descr haswell_xeon_event_table[] = 204280455Srrs{ 205280455Srrs __PMC_EV_ALIAS_HASWELL_XEON() 206280455Srrs}; 207280455Srrs 208320113Savgstatic const struct pmc_event_descr broadwell_event_table[] = 209320113Savg{ 210320113Savg __PMC_EV_ALIAS_BROADWELL() 211320113Savg}; 212280455Srrs 213320113Savgstatic const struct pmc_event_descr broadwell_xeon_event_table[] = 214320113Savg{ 215320113Savg __PMC_EV_ALIAS_BROADWELL_XEON() 216320113Savg}; 217320113Savg 218320113Savgstatic const struct pmc_event_descr skylake_event_table[] = 219320113Savg{ 220320113Savg __PMC_EV_ALIAS_SKYLAKE() 221320113Savg}; 222320113Savg 223240164Sfabientstatic const struct pmc_event_descr ivybridge_event_table[] = 224240164Sfabient{ 225240164Sfabient __PMC_EV_ALIAS_IVYBRIDGE() 226240164Sfabient}; 227240164Sfabient 228246166Ssbrunostatic const struct pmc_event_descr ivybridge_xeon_event_table[] = 229246166Ssbruno{ 230246166Ssbruno __PMC_EV_ALIAS_IVYBRIDGE_XEON() 231246166Ssbruno}; 232246166Ssbruno 233232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 234232366Sdavide{ 235232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 236232366Sdavide}; 237232366Sdavide 238241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] = 239241738Ssbruno{ 240241738Ssbruno __PMC_EV_ALIAS_SANDYBRIDGE_XEON() 241241738Ssbruno}; 242241738Ssbruno 243206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 244206089Sfabient{ 245206089Sfabient __PMC_EV_ALIAS_WESTMERE() 246206089Sfabient}; 247206089Sfabient 248267602Skibstatic const struct pmc_event_descr westmere_ex_event_table[] = 249267602Skib{ 250267602Skib __PMC_EV_ALIAS_WESTMERE() 251267602Skib}; 252267602Skib 253206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 254206089Sfabient{ 255206089Sfabient __PMC_EV_ALIAS_COREI7UC() 256206089Sfabient}; 257206089Sfabient 258248842Ssbrunostatic const struct pmc_event_descr haswelluc_event_table[] = 259248842Ssbruno{ 260248842Ssbruno __PMC_EV_ALIAS_HASWELLUC() 261248842Ssbruno}; 262248842Ssbruno 263320113Savgstatic const struct pmc_event_descr broadwelluc_event_table[] = 264320113Savg{ 265320113Savg __PMC_EV_ALIAS_BROADWELLUC() 266320113Savg}; 267320113Savg 268232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 269232366Sdavide{ 270232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 271232366Sdavide}; 272232366Sdavide 273206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 274206089Sfabient{ 275206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 276206089Sfabient}; 277206089Sfabient 278185363Sjkoshy/* 279185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 280185363Sjkoshy * 281185363Sjkoshy * Map a CPU to the PMC classes it supports. 282185363Sjkoshy */ 283185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 284183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 285183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 286183725Sjkoshy } 287183725Sjkoshy 288233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 289266911ShirenPMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 290233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 291233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 292233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 293267602SkibPMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 294248842SsbrunoPMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 295280455SrrsPMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 296320113SavgPMC_MDEP_TABLE(broadwell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 297320113SavgPMC_MDEP_TABLE(broadwell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 298320113SavgPMC_MDEP_TABLE(skylake, 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); 304267602SkibPMC_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); 311233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 312233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 313233628SfabientPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450); 314263122SjhibbitsPMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970); 315233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 316183725Sjkoshy 317183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 318145256Sjkoshy{ 319183725Sjkoshy __PMC_EV_TSC() 320145256Sjkoshy}; 321145256Sjkoshy 322183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 323185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 324185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 325185363Sjkoshy { \ 326185363Sjkoshy .pm_evc_name = #CLASS "-", \ 327185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 328185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 329185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 330183725Sjkoshy .pm_evc_event_table_size = \ 331185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 332185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 333183725Sjkoshy } 334183725Sjkoshy 335185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 336185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 337185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 338266911ShirenPMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap); 339185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 340185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 341187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 342267602SkibPMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap); 343248842SsbrunoPMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap); 344320137SavgPMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell_xeon, iap); 345320113SavgPMC_CLASS_TABLE_DESC(broadwell, IAP, broadwell, iap); 346320113SavgPMC_CLASS_TABLE_DESC(broadwell_xeon, IAP, broadwell_xeon, iap); 347320113SavgPMC_CLASS_TABLE_DESC(skylake, IAP, skylake, iap); 348240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); 349246166SsbrunoPMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap); 350232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 351241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); 352206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 353267602SkibPMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap); 354206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 355206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 356248842SsbrunoPMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp); 357320113SavgPMC_CLASS_TABLE_DESC(broadwelluc, UCP, broadwelluc, ucp); 358232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 359206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 360185363Sjkoshy#endif 361183725Sjkoshy#if defined(__i386__) 362185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 363183725Sjkoshy#endif 364183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 365185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 366185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 367183725Sjkoshy#endif 368183725Sjkoshy#if defined(__i386__) 369185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 370185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 371183725Sjkoshy#endif 372183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 373185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 374183725Sjkoshy#endif 375200928Srpaulo#if defined(__XSCALE__) 376200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 377200928Srpaulo#endif 378204635Sgnn#if defined(__mips__) 379233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 380233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 381204635Sgnn#endif /* __mips__ */ 382228869Sjhibbits#if defined(__powerpc__) 383263122SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc); 384263122SjhibbitsPMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc); 385228869Sjhibbits#endif 386228869Sjhibbits 387233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 388233628Sfabient{ 389233628Sfabient .pm_evc_name = "SOFT-", 390233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 391233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 392233628Sfabient .pm_evc_event_table = NULL, 393233628Sfabient .pm_evc_event_table_size = 0, 394233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 395233628Sfabient}; 396233628Sfabient 397183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 398183725Sjkoshy 399185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 400185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 401185363Sjkoshy 402183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 403183725Sjkoshystatic size_t pmc_mdep_class_list_size; 404183725Sjkoshy 405145256Sjkoshy/* 406145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 407145256Sjkoshy * strings. 408145256Sjkoshy */ 409145256Sjkoshy 410145256Sjkoshystatic const char * pmc_capability_names[] = { 411145256Sjkoshy#undef __PMC_CAP 412145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 413145256Sjkoshy __PMC_CAPS() 414145256Sjkoshy}; 415145256Sjkoshy 416145256Sjkoshystatic const char * pmc_class_names[] = { 417145256Sjkoshy#undef __PMC_CLASS 418145256Sjkoshy#define __PMC_CLASS(C) #C , 419145256Sjkoshy __PMC_CLASSES() 420145256Sjkoshy}; 421145256Sjkoshy 422183725Sjkoshystruct pmc_cputype_map { 423228557Sdim enum pmc_cputype pm_cputype; 424183725Sjkoshy const char *pm_name; 425183725Sjkoshy}; 426183725Sjkoshy 427183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 428145256Sjkoshy#undef __PMC_CPU 429183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 430145256Sjkoshy __PMC_CPUS() 431145256Sjkoshy}; 432145256Sjkoshy 433145256Sjkoshystatic const char * pmc_disposition_names[] = { 434145256Sjkoshy#undef __PMC_DISP 435145256Sjkoshy#define __PMC_DISP(D) #D , 436145256Sjkoshy __PMC_DISPOSITIONS() 437145256Sjkoshy}; 438145256Sjkoshy 439145256Sjkoshystatic const char * pmc_mode_names[] = { 440145256Sjkoshy#undef __PMC_MODE 441145256Sjkoshy#define __PMC_MODE(M,N) #M , 442145256Sjkoshy __PMC_MODES() 443145256Sjkoshy}; 444145256Sjkoshy 445145256Sjkoshystatic const char * pmc_state_names[] = { 446145256Sjkoshy#undef __PMC_STATE 447145256Sjkoshy#define __PMC_STATE(S) #S , 448145256Sjkoshy __PMC_STATES() 449145256Sjkoshy}; 450145256Sjkoshy 451233628Sfabient/* 452233628Sfabient * Filled in by pmc_init(). 453233628Sfabient */ 454233628Sfabientstatic int pmc_syscall = -1; 455233628Sfabientstatic struct pmc_cpuinfo cpu_info; 456233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 457145256Sjkoshy 458145256Sjkoshy/* Event masks for events */ 459145256Sjkoshystruct pmc_masks { 460145256Sjkoshy const char *pm_name; 461240164Sfabient const uint64_t pm_value; 462145256Sjkoshy}; 463145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 464206089Sfabient#define NULLMASK { .pm_name = NULL } 465145256Sjkoshy 466147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 467145256Sjkoshystatic int 468240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) 469145256Sjkoshy{ 470145256Sjkoshy const struct pmc_masks *pm; 471145256Sjkoshy char *q, *r; 472145256Sjkoshy int c; 473145256Sjkoshy 474145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 475174406Sjkoshy return (-1); 476183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 477145256Sjkoshy if (*++q == '\0') /* no more data */ 478174406Sjkoshy return (-1); 479145256Sjkoshy c = 0; /* count of mask keywords seen */ 480145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 481183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 482183725Sjkoshy pm++) 483145256Sjkoshy ; 484145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 485174406Sjkoshy return (-1); 486145256Sjkoshy *evmask |= pm->pm_value; 487145256Sjkoshy c++; 488145256Sjkoshy } 489174406Sjkoshy return (c); 490145256Sjkoshy} 491145340Smarcel#endif 492145256Sjkoshy 493145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 494145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 495145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 496145256Sjkoshy 497145340Smarcel#if defined(__i386__) 498145256Sjkoshy 499145256Sjkoshy/* 500145256Sjkoshy * AMD K7 (Athlon) CPUs. 501145256Sjkoshy */ 502145256Sjkoshy 503145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 504145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 505145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 506145351Sjkoshy EV_ALIAS("cycles", "tsc"), 507183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 508145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 509145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 510145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 511145351Sjkoshy EV_ALIAS(NULL, NULL) 512145256Sjkoshy}; 513145256Sjkoshy 514145256Sjkoshy#define K7_KW_COUNT "count" 515145256Sjkoshy#define K7_KW_EDGE "edge" 516145256Sjkoshy#define K7_KW_INV "inv" 517145256Sjkoshy#define K7_KW_OS "os" 518145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 519145256Sjkoshy#define K7_KW_USR "usr" 520145256Sjkoshy 521145256Sjkoshystatic int 522145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 523145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 524145256Sjkoshy{ 525183107Sjkoshy char *e, *p, *q; 526183107Sjkoshy int c, has_unitmask; 527145256Sjkoshy uint32_t count, unitmask; 528145256Sjkoshy 529147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 530183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 531145256Sjkoshy 532145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 533145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 534145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 535145256Sjkoshy has_unitmask = 1; 536147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 537145256Sjkoshy } else 538145256Sjkoshy unitmask = has_unitmask = 0; 539145256Sjkoshy 540145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 541145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 542145256Sjkoshy q = strchr(p, '='); 543145256Sjkoshy if (*++q == '\0') /* skip '=' */ 544174406Sjkoshy return (-1); 545145256Sjkoshy 546145256Sjkoshy count = strtol(q, &e, 0); 547145256Sjkoshy if (e == q || *e != '\0') 548174406Sjkoshy return (-1); 549145256Sjkoshy 550145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 551147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 552147191Sjkoshy AMD_PMC_TO_COUNTER(count); 553145256Sjkoshy 554145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 555145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 556145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 557145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 558145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 559145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 560145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 561145256Sjkoshy if (has_unitmask == 0) 562174406Sjkoshy return (-1); 563145256Sjkoshy unitmask = 0; 564145256Sjkoshy q = strchr(p, '='); 565145256Sjkoshy if (*++q == '\0') /* skip '=' */ 566174406Sjkoshy return (-1); 567145256Sjkoshy 568145256Sjkoshy while ((c = tolower(*q++)) != 0) 569145256Sjkoshy if (c == 'm') 570147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 571145256Sjkoshy else if (c == 'o') 572147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 573145256Sjkoshy else if (c == 'e') 574147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 575145256Sjkoshy else if (c == 's') 576147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 577145256Sjkoshy else if (c == 'i') 578147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 579145256Sjkoshy else if (c == '+') 580145256Sjkoshy continue; 581145256Sjkoshy else 582174406Sjkoshy return (-1); 583145256Sjkoshy 584145256Sjkoshy if (unitmask == 0) 585174406Sjkoshy return (-1); 586145256Sjkoshy 587145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 588145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 589145256Sjkoshy } else 590174406Sjkoshy return (-1); 591145256Sjkoshy } 592145256Sjkoshy 593145256Sjkoshy if (has_unitmask) { 594145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 595147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 596147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 597145256Sjkoshy } 598145256Sjkoshy 599174406Sjkoshy return (0); 600145256Sjkoshy 601145256Sjkoshy} 602145256Sjkoshy 603147191Sjkoshy#endif 604147191Sjkoshy 605147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 606147191Sjkoshy 607145256Sjkoshy/* 608185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 609185363Sjkoshy */ 610185363Sjkoshy 611185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 612185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 613185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 614185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 615185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 616185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 617185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 618185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 619185363Sjkoshy EV_ALIAS(NULL, NULL) 620185363Sjkoshy}; 621185363Sjkoshy 622185363Sjkoshy/* 623185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 624185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 625198433Sjkoshy * 626198433Sjkoshy * We map aliases to events on the fixed-function counters if these 627198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 628198433Sjkoshy * counters. 629185363Sjkoshy */ 630185363Sjkoshy 631185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 632185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 633185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 634185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 635185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 636185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 637185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 638185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 639185363Sjkoshy EV_ALIAS(NULL, NULL) 640185363Sjkoshy}; 641185363Sjkoshy 642198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 643198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 644198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 645198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 646198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 647198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 648198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 649198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 650198433Sjkoshy EV_ALIAS(NULL, NULL) 651198433Sjkoshy}; 652198433Sjkoshy 653198433Sjkoshy#define atom_aliases core2_aliases 654198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 655266911Shiren#define atom_silvermont_aliases core2_aliases 656266911Shiren#define atom_silvermont_aliases_without_iaf core2_aliases_without_iaf 657198433Sjkoshy#define corei7_aliases core2_aliases 658198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 659267602Skib#define nehalem_ex_aliases core2_aliases 660267602Skib#define nehalem_ex_aliases_without_iaf core2_aliases_without_iaf 661248842Ssbruno#define haswell_aliases core2_aliases 662248842Ssbruno#define haswell_aliases_without_iaf core2_aliases_without_iaf 663280455Srrs#define haswell_xeon_aliases core2_aliases 664280455Srrs#define haswell_xeon_aliases_without_iaf core2_aliases_without_iaf 665320113Savg#define broadwell_aliases core2_aliases 666320113Savg#define broadwell_aliases_without_iaf core2_aliases_without_iaf 667320113Savg#define broadwell_xeon_aliases core2_aliases 668320113Savg#define broadwell_xeon_aliases_without_iaf core2_aliases_without_iaf 669320113Savg#define skylake_aliases core2_aliases 670320113Savg#define skylake_aliases_without_iaf core2_aliases_without_iaf 671240164Sfabient#define ivybridge_aliases core2_aliases 672240164Sfabient#define ivybridge_aliases_without_iaf core2_aliases_without_iaf 673246166Ssbruno#define ivybridge_xeon_aliases core2_aliases 674246166Ssbruno#define ivybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 675232366Sdavide#define sandybridge_aliases core2_aliases 676232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 677241738Ssbruno#define sandybridge_xeon_aliases core2_aliases 678241738Ssbruno#define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 679206089Sfabient#define westmere_aliases core2_aliases 680206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 681267602Skib#define westmere_ex_aliases core2_aliases 682267602Skib#define westmere_ex_aliases_without_iaf core2_aliases_without_iaf 683198433Sjkoshy 684185363Sjkoshy#define IAF_KW_OS "os" 685185363Sjkoshy#define IAF_KW_USR "usr" 686185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 687185363Sjkoshy 688185363Sjkoshy/* 689185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 690185363Sjkoshy */ 691185363Sjkoshystatic int 692185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 693185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 694185363Sjkoshy{ 695185363Sjkoshy char *p; 696185363Sjkoshy 697185363Sjkoshy (void) pe; 698185363Sjkoshy 699185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 700185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 701185363Sjkoshy 702185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 703185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 704185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 705185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 706185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 707185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 708185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 709185363Sjkoshy else 710185363Sjkoshy return (-1); 711185363Sjkoshy } 712185363Sjkoshy 713185363Sjkoshy return (0); 714185363Sjkoshy} 715185363Sjkoshy 716185363Sjkoshy/* 717185363Sjkoshy * Core/Core2 support. 718185363Sjkoshy */ 719185363Sjkoshy 720185363Sjkoshy#define IAP_KW_AGENT "agent" 721185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 722185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 723185363Sjkoshy#define IAP_KW_CMASK "cmask" 724185363Sjkoshy#define IAP_KW_CORE "core" 725185363Sjkoshy#define IAP_KW_EDGE "edge" 726185363Sjkoshy#define IAP_KW_INV "inv" 727185363Sjkoshy#define IAP_KW_OS "os" 728185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 729185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 730185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 731185363Sjkoshy#define IAP_KW_TRANSITION "trans" 732185363Sjkoshy#define IAP_KW_USR "usr" 733206089Sfabient#define IAP_KW_RSP "rsp" 734185363Sjkoshy 735185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 736185363Sjkoshy PMCMASK(all, (0x3 << 14)), 737185363Sjkoshy PMCMASK(this, (0x1 << 14)), 738185363Sjkoshy NULLMASK 739185363Sjkoshy}; 740185363Sjkoshy 741185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 742185363Sjkoshy PMCMASK(this, 0), 743185363Sjkoshy PMCMASK(any, (0x1 << 13)), 744185363Sjkoshy NULLMASK 745185363Sjkoshy}; 746185363Sjkoshy 747185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 748185363Sjkoshy PMCMASK(both, (0x3 << 12)), 749185363Sjkoshy PMCMASK(only, (0x1 << 12)), 750185363Sjkoshy PMCMASK(exclude, 0), 751185363Sjkoshy NULLMASK 752185363Sjkoshy}; 753185363Sjkoshy 754185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 755185363Sjkoshy PMCMASK(i, (1 << 8)), 756185363Sjkoshy PMCMASK(s, (1 << 9)), 757185363Sjkoshy PMCMASK(e, (1 << 10)), 758185363Sjkoshy PMCMASK(m, (1 << 11)), 759185363Sjkoshy NULLMASK 760185363Sjkoshy}; 761185363Sjkoshy 762185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 763185363Sjkoshy PMCMASK(clean, (1 << 8)), 764185363Sjkoshy PMCMASK(hit, (1 << 9)), 765185363Sjkoshy PMCMASK(hitm, (1 << 11)), 766185363Sjkoshy NULLMASK 767185363Sjkoshy}; 768185363Sjkoshy 769185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 770185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 771185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 772185363Sjkoshy NULLMASK 773185363Sjkoshy}; 774185363Sjkoshy 775185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 776185363Sjkoshy PMCMASK(any, 0x00), 777185363Sjkoshy PMCMASK(frequency, 0x10), 778185363Sjkoshy NULLMASK 779185363Sjkoshy}; 780185363Sjkoshy 781240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = { 782206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 783206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 784206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 785206089Sfabient PMCMASK(WB, (1 << 3)), 786206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 787206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 788206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 789206089Sfabient PMCMASK(OTHER, (1 << 7)), 790206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 791206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 792206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 793206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 794206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 795206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 796206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 797206089Sfabient NULLMASK 798206089Sfabient}; 799206089Sfabient 800241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { 801240164Sfabient PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 802240164Sfabient PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 803240164Sfabient PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 804240164Sfabient PMCMASK(REQ_WB, (1ULL << 3)), 805240164Sfabient PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 806240164Sfabient PMCMASK(REQ_PF_RFO, (1ULL << 5)), 807240164Sfabient PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 808240164Sfabient PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), 809240164Sfabient PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), 810240164Sfabient PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), 811240164Sfabient PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), 812240164Sfabient PMCMASK(REQ_STRM_ST, (1ULL << 11)), 813240164Sfabient PMCMASK(REQ_OTHER, (1ULL << 15)), 814240164Sfabient PMCMASK(RES_ANY, (1ULL << 16)), 815240164Sfabient PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 816240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 817240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 818240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 819240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 820240164Sfabient PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 821241974Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 822240164Sfabient PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 823240164Sfabient PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 824240164Sfabient PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 825240164Sfabient PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 826240164Sfabient PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 827240164Sfabient PMCMASK(RES_NON_DRAM, (1ULL << 37)), 828240164Sfabient NULLMASK 829240164Sfabient}; 830240164Sfabient 831320113Savg/* Broadwell is defined to use the same mask as Haswell */ 832248842Ssbrunostatic struct pmc_masks iap_rsp_mask_haswell[] = { 833248842Ssbruno PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 834248842Ssbruno PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 835248842Ssbruno PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 836248842Ssbruno PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 837248842Ssbruno PMCMASK(REQ_PF_RFO, (1ULL << 5)), 838248842Ssbruno PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 839248842Ssbruno PMCMASK(REQ_OTHER, (1ULL << 15)), 840248842Ssbruno PMCMASK(RES_ANY, (1ULL << 16)), 841248842Ssbruno PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 842248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 843248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 844248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 845248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 846248842Ssbruno PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 847320113Savg /* 848320113Savg * For processor type 06_45H 22 is L4_HIT_LOCAL_L4 849320113Savg * and 23, 24 and 25 are also defined. 850320113Savg */ 851248842Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 852248842Ssbruno PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 853248842Ssbruno PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 854248842Ssbruno PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 855248842Ssbruno PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 856248842Ssbruno PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 857248842Ssbruno PMCMASK(RES_NON_DRAM, (1ULL << 37)), 858248842Ssbruno NULLMASK 859248842Ssbruno}; 860248842Ssbruno 861320113Savgstatic struct pmc_masks iap_rsp_mask_skylake[] = { 862320113Savg PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 863320113Savg PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 864320113Savg PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 865320113Savg PMCMASK(REQ_PF_DATA_RD, (1ULL << 7)), 866320113Savg PMCMASK(REQ_PF_RFO, (1ULL << 8)), 867320113Savg PMCMASK(REQ_STRM_ST, (1ULL << 11)), 868320113Savg PMCMASK(REQ_OTHER, (1ULL << 15)), 869320113Savg PMCMASK(RES_ANY, (1ULL << 16)), 870320113Savg PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 871320113Savg PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 872320113Savg PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 873320113Savg PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 874320113Savg PMCMASK(RES_SUPPLIER_L4_HIT, (1ULL << 22)), 875320113Savg PMCMASK(RES_SUPPLIER_DRAM, (1ULL << 26)), 876320113Savg PMCMASK(RES_SUPPLIER_SPL_HIT, (1ULL << 30)), 877320113Savg PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 878320113Savg PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 879320113Savg PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 880320113Savg PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 881320113Savg PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 882320113Savg PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 883320113Savg PMCMASK(RES_NON_DRAM, (1ULL << 37)), 884320113Savg NULLMASK 885320113Savg}; 886320113Savg 887320113Savg 888185363Sjkoshystatic int 889185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 890185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 891185363Sjkoshy{ 892185363Sjkoshy char *e, *p, *q; 893240164Sfabient uint64_t cachestate, evmask, rsp; 894185363Sjkoshy int count, n; 895185363Sjkoshy 896185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 897185363Sjkoshy PMC_CAP_QUALIFIER); 898185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 899185363Sjkoshy 900206089Sfabient cachestate = evmask = rsp = 0; 901185363Sjkoshy 902185363Sjkoshy /* Parse additional modifiers if present */ 903185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 904185363Sjkoshy 905185363Sjkoshy n = 0; 906185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 907185363Sjkoshy q = strchr(p, '='); 908185363Sjkoshy if (*++q == '\0') /* skip '=' */ 909185363Sjkoshy return (-1); 910185363Sjkoshy count = strtol(q, &e, 0); 911185363Sjkoshy if (e == q || *e != '\0') 912185363Sjkoshy return (-1); 913185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 914185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 915185363Sjkoshy IAP_CMASK(count); 916185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 917185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 918185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 919185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 920185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 921185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 922185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 923185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 924185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 925185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 926193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 927185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 928185363Sjkoshy if (n != 1) 929185363Sjkoshy return (-1); 930193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 931185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 932185363Sjkoshy if (n != 1) 933185363Sjkoshy return (-1); 934193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 935185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 936185363Sjkoshy if (n != 1) 937185363Sjkoshy return (-1); 938193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 939185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 940185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 941193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 942185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 943185363Sjkoshy if (n != 1) 944185363Sjkoshy return (-1); 945185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 946266911Shiren cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT || 947185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 948206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 949193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 950185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 951185363Sjkoshy &evmask); 952193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 953185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 954185363Sjkoshy &evmask); 955185363Sjkoshy } else 956185363Sjkoshy return (-1); 957206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 958267602Skib cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE || 959267602Skib cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX || 960267602Skib cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) { 961206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 962240164Sfabient n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); 963206089Sfabient } else 964206089Sfabient return (-1); 965240164Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || 966241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || 967246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE || 968246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) { 969240164Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 970241738Ssbruno n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); 971240164Sfabient } else 972240164Sfabient return (-1); 973280455Srrs } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL || 974280455Srrs cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) { 975248842Ssbruno if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 976248842Ssbruno n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); 977248842Ssbruno } else 978248842Ssbruno return (-1); 979320113Savg } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL || 980320113Savg cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL_XEON) { 981320113Savg /* Broadwell is defined to use same mask as haswell */ 982320113Savg if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 983320113Savg n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); 984320113Savg } else 985320113Savg return (-1); 986320113Savg 987320113Savg } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE) { 988320113Savg if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 989320113Savg n = pmc_parse_mask(iap_rsp_mask_skylake, p, &rsp); 990320113Savg } else 991320113Savg return (-1); 992320113Savg 993185363Sjkoshy } else 994185363Sjkoshy return (-1); 995185363Sjkoshy 996185363Sjkoshy if (n < 0) /* Parsing failed. */ 997185363Sjkoshy return (-1); 998185363Sjkoshy } 999185363Sjkoshy 1000185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 1001185363Sjkoshy 1002185363Sjkoshy /* 1003185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 1004185363Sjkoshy * specified by the user, use a sensible default. 1005185363Sjkoshy */ 1006185363Sjkoshy switch (pe) { 1007185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 1008185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 1009185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 1010185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 1011185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 1012185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 1013185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 1014185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 1015185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 1016185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 1017185363Sjkoshy if (cachestate == 0) 1018185363Sjkoshy cachestate = (0xF << 8); 1019207482Srstone break; 1020207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 1021207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 1022207482Srstone * Atom processor 1023207482Srstone */ 1024207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 1025207482Srstone cachestate = (0xF << 8); 1026207482Srstone break; 1027185363Sjkoshy default: 1028185363Sjkoshy break; 1029185363Sjkoshy } 1030185363Sjkoshy 1031185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 1032206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 1033185363Sjkoshy 1034185363Sjkoshy return (0); 1035185363Sjkoshy} 1036185363Sjkoshy 1037185363Sjkoshy/* 1038206089Sfabient * Intel Uncore. 1039206089Sfabient */ 1040206089Sfabient 1041206089Sfabientstatic int 1042206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 1043206089Sfabient struct pmc_op_pmcallocate *pmc_config) 1044206089Sfabient{ 1045206089Sfabient (void) pe; 1046206089Sfabient (void) ctrspec; 1047206089Sfabient 1048206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1049206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 1050206089Sfabient 1051206089Sfabient return (0); 1052206089Sfabient} 1053206089Sfabient 1054206089Sfabient#define UCP_KW_CMASK "cmask" 1055206089Sfabient#define UCP_KW_EDGE "edge" 1056206089Sfabient#define UCP_KW_INV "inv" 1057206089Sfabient 1058206089Sfabientstatic int 1059206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 1060206089Sfabient struct pmc_op_pmcallocate *pmc_config) 1061206089Sfabient{ 1062206089Sfabient char *e, *p, *q; 1063206089Sfabient int count, n; 1064206089Sfabient 1065206089Sfabient (void) pe; 1066206089Sfabient 1067206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 1068206089Sfabient PMC_CAP_QUALIFIER); 1069206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 1070206089Sfabient 1071206089Sfabient /* Parse additional modifiers if present */ 1072206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 1073206089Sfabient 1074206089Sfabient n = 0; 1075206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 1076206089Sfabient q = strchr(p, '='); 1077206089Sfabient if (*++q == '\0') /* skip '=' */ 1078206089Sfabient return (-1); 1079206089Sfabient count = strtol(q, &e, 0); 1080206089Sfabient if (e == q || *e != '\0') 1081206089Sfabient return (-1); 1082206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1083206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 1084206089Sfabient UCP_CMASK(count); 1085206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 1086206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 1087206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 1088206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 1089206089Sfabient } else 1090206089Sfabient return (-1); 1091206089Sfabient 1092206089Sfabient if (n < 0) /* Parsing failed. */ 1093206089Sfabient return (-1); 1094206089Sfabient } 1095206089Sfabient 1096206089Sfabient return (0); 1097206089Sfabient} 1098206089Sfabient 1099206089Sfabient/* 1100147191Sjkoshy * AMD K8 PMCs. 1101147191Sjkoshy * 1102147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 1103147191Sjkoshy * events. 1104147191Sjkoshy */ 1105147191Sjkoshy 1106147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 1107147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 1108147191Sjkoshy EV_ALIAS("branch-mispredicts", 1109147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 1110147191Sjkoshy EV_ALIAS("cycles", "tsc"), 1111147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 1112147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 1113183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 1114147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 1115155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 1116147191Sjkoshy EV_ALIAS(NULL, NULL) 1117147191Sjkoshy}; 1118147191Sjkoshy 1119147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 1120147191Sjkoshy 1121147191Sjkoshy/* 1122147191Sjkoshy * Parsing tables 1123147191Sjkoshy */ 1124147191Sjkoshy 1125147191Sjkoshy/* fp dispatched fpu ops */ 1126147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 1127147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 1128147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 1129147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 1130147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 1131147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 1132147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 1133147191Sjkoshy NULLMASK 1134147191Sjkoshy}; 1135147191Sjkoshy 1136147191Sjkoshy/* ls segment register loads */ 1137147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 1138147191Sjkoshy __K8MASK(es, 0), 1139147191Sjkoshy __K8MASK(cs, 1), 1140147191Sjkoshy __K8MASK(ss, 2), 1141147191Sjkoshy __K8MASK(ds, 3), 1142147191Sjkoshy __K8MASK(fs, 4), 1143147191Sjkoshy __K8MASK(gs, 5), 1144147191Sjkoshy __K8MASK(hs, 6), 1145147191Sjkoshy NULLMASK 1146147191Sjkoshy}; 1147147191Sjkoshy 1148147191Sjkoshy/* ls locked operation */ 1149147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 1150147191Sjkoshy __K8MASK(locked-instructions, 0), 1151147191Sjkoshy __K8MASK(cycles-in-request, 1), 1152147191Sjkoshy __K8MASK(cycles-to-complete, 2), 1153147191Sjkoshy NULLMASK 1154147191Sjkoshy}; 1155147191Sjkoshy 1156147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 1157147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 1158147191Sjkoshy __K8MASK(invalid, 0), 1159147191Sjkoshy __K8MASK(shared, 1), 1160147191Sjkoshy __K8MASK(exclusive, 2), 1161147191Sjkoshy __K8MASK(owner, 3), 1162147191Sjkoshy __K8MASK(modified, 4), 1163147191Sjkoshy NULLMASK 1164147191Sjkoshy}; 1165147191Sjkoshy 1166147191Sjkoshy/* dc one bit ecc error */ 1167147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 1168147191Sjkoshy __K8MASK(scrubber, 0), 1169147191Sjkoshy __K8MASK(piggyback, 1), 1170147191Sjkoshy NULLMASK 1171147191Sjkoshy}; 1172147191Sjkoshy 1173147191Sjkoshy/* dc dispatched prefetch instructions */ 1174147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 1175147191Sjkoshy __K8MASK(load, 0), 1176147191Sjkoshy __K8MASK(store, 1), 1177147191Sjkoshy __K8MASK(nta, 2), 1178147191Sjkoshy NULLMASK 1179147191Sjkoshy}; 1180147191Sjkoshy 1181147191Sjkoshy/* dc dcache accesses by locks */ 1182147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1183147191Sjkoshy __K8MASK(accesses, 0), 1184147191Sjkoshy __K8MASK(misses, 1), 1185147191Sjkoshy NULLMASK 1186147191Sjkoshy}; 1187147191Sjkoshy 1188147191Sjkoshy/* bu internal l2 request */ 1189147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1190147191Sjkoshy __K8MASK(ic-fill, 0), 1191147191Sjkoshy __K8MASK(dc-fill, 1), 1192147191Sjkoshy __K8MASK(tlb-reload, 2), 1193147191Sjkoshy __K8MASK(tag-snoop, 3), 1194147191Sjkoshy __K8MASK(cancelled, 4), 1195147191Sjkoshy NULLMASK 1196147191Sjkoshy}; 1197147191Sjkoshy 1198147191Sjkoshy/* bu fill request l2 miss */ 1199147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1200147191Sjkoshy __K8MASK(ic-fill, 0), 1201147191Sjkoshy __K8MASK(dc-fill, 1), 1202147191Sjkoshy __K8MASK(tlb-reload, 2), 1203147191Sjkoshy NULLMASK 1204147191Sjkoshy}; 1205147191Sjkoshy 1206147191Sjkoshy/* bu fill into l2 */ 1207147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1208147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 1209147191Sjkoshy __K8MASK(victim-from-l2, 1), 1210147191Sjkoshy NULLMASK 1211147191Sjkoshy}; 1212147191Sjkoshy 1213147191Sjkoshy/* fr retired fpu instructions */ 1214147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1215147191Sjkoshy __K8MASK(x87, 0), 1216147191Sjkoshy __K8MASK(mmx-3dnow, 1), 1217147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 1218147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1219147191Sjkoshy NULLMASK 1220147191Sjkoshy}; 1221147191Sjkoshy 1222147191Sjkoshy/* fr retired fastpath double op instructions */ 1223147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1224147191Sjkoshy __K8MASK(low-op-pos-0, 0), 1225147191Sjkoshy __K8MASK(low-op-pos-1, 1), 1226147191Sjkoshy __K8MASK(low-op-pos-2, 2), 1227147191Sjkoshy NULLMASK 1228147191Sjkoshy}; 1229147191Sjkoshy 1230147191Sjkoshy/* fr fpu exceptions */ 1231147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1232147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1233147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1234147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1235147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1236147191Sjkoshy NULLMASK 1237147191Sjkoshy}; 1238147191Sjkoshy 1239147191Sjkoshy/* nb memory controller page access event */ 1240147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1241147191Sjkoshy __K8MASK(page-hit, 0), 1242147191Sjkoshy __K8MASK(page-miss, 1), 1243147191Sjkoshy __K8MASK(page-conflict, 2), 1244147191Sjkoshy NULLMASK 1245147191Sjkoshy}; 1246147191Sjkoshy 1247147191Sjkoshy/* nb memory controller turnaround */ 1248147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1249147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1250147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1251147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1252147191Sjkoshy NULLMASK 1253147191Sjkoshy}; 1254147191Sjkoshy 1255147191Sjkoshy/* nb memory controller bypass saturation */ 1256147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1257147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1258147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1259147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1260147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1261147191Sjkoshy NULLMASK 1262147191Sjkoshy}; 1263147191Sjkoshy 1264147191Sjkoshy/* nb sized commands */ 1265147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1266147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1267147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1268147191Sjkoshy __K8MASK(postwrszbyte, 2), 1269147191Sjkoshy __K8MASK(postwrszdword, 3), 1270147191Sjkoshy __K8MASK(rdszbyte, 4), 1271147191Sjkoshy __K8MASK(rdszdword, 5), 1272147191Sjkoshy __K8MASK(rdmodwr, 6), 1273147191Sjkoshy NULLMASK 1274147191Sjkoshy}; 1275147191Sjkoshy 1276147191Sjkoshy/* nb probe result */ 1277147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1278147191Sjkoshy __K8MASK(probe-miss, 0), 1279147191Sjkoshy __K8MASK(probe-hit, 1), 1280147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1281147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1282147191Sjkoshy NULLMASK 1283147191Sjkoshy}; 1284147191Sjkoshy 1285147191Sjkoshy/* nb hypertransport bus bandwidth */ 1286147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1287147191Sjkoshy __K8MASK(command, 0), 1288183107Sjkoshy __K8MASK(data, 1), 1289147191Sjkoshy __K8MASK(buffer-release, 2), 1290147191Sjkoshy __K8MASK(nop, 3), 1291147191Sjkoshy NULLMASK 1292147191Sjkoshy}; 1293147191Sjkoshy 1294147191Sjkoshy#undef __K8MASK 1295147191Sjkoshy 1296147191Sjkoshy#define K8_KW_COUNT "count" 1297147191Sjkoshy#define K8_KW_EDGE "edge" 1298147191Sjkoshy#define K8_KW_INV "inv" 1299147191Sjkoshy#define K8_KW_MASK "mask" 1300147191Sjkoshy#define K8_KW_OS "os" 1301147191Sjkoshy#define K8_KW_USR "usr" 1302147191Sjkoshy 1303147191Sjkoshystatic int 1304147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1305147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1306147191Sjkoshy{ 1307183107Sjkoshy char *e, *p, *q; 1308183107Sjkoshy int n; 1309240164Sfabient uint32_t count; 1310240164Sfabient uint64_t evmask; 1311147191Sjkoshy const struct pmc_masks *pm, *pmask; 1312147191Sjkoshy 1313183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1314147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1315147191Sjkoshy 1316147191Sjkoshy pmask = NULL; 1317147191Sjkoshy evmask = 0; 1318147191Sjkoshy 1319147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1320147191Sjkoshy 1321147191Sjkoshy /* setup parsing tables */ 1322147191Sjkoshy switch (pe) { 1323147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1324147191Sjkoshy __K8SETMASK(fdfo); 1325147191Sjkoshy break; 1326147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1327147191Sjkoshy __K8SETMASK(lsrl); 1328147191Sjkoshy break; 1329147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1330147191Sjkoshy __K8SETMASK(llo); 1331147191Sjkoshy break; 1332147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1333147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1334147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1335147191Sjkoshy __K8SETMASK(dc); 1336147191Sjkoshy break; 1337147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1338147191Sjkoshy __K8SETMASK(dobee); 1339147191Sjkoshy break; 1340147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1341147191Sjkoshy __K8SETMASK(ddpi); 1342147191Sjkoshy break; 1343147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1344147191Sjkoshy __K8SETMASK(dabl); 1345147191Sjkoshy break; 1346147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1347147191Sjkoshy __K8SETMASK(bilr); 1348147191Sjkoshy break; 1349147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1350147191Sjkoshy __K8SETMASK(bfrlm); 1351147191Sjkoshy break; 1352147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1353147191Sjkoshy __K8SETMASK(bfil); 1354147191Sjkoshy break; 1355147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1356147191Sjkoshy __K8SETMASK(frfi); 1357147191Sjkoshy break; 1358147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1359147191Sjkoshy __K8SETMASK(frfdoi); 1360147191Sjkoshy break; 1361147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1362147191Sjkoshy __K8SETMASK(ffe); 1363147191Sjkoshy break; 1364147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1365147191Sjkoshy __K8SETMASK(nmcpae); 1366147191Sjkoshy break; 1367147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1368147191Sjkoshy __K8SETMASK(nmct); 1369147191Sjkoshy break; 1370147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1371147191Sjkoshy __K8SETMASK(nmcbs); 1372147191Sjkoshy break; 1373147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1374147191Sjkoshy __K8SETMASK(nsc); 1375147191Sjkoshy break; 1376147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1377147191Sjkoshy __K8SETMASK(npr); 1378147191Sjkoshy break; 1379147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1380147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1381147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1382147191Sjkoshy __K8SETMASK(nhbb); 1383147191Sjkoshy break; 1384147191Sjkoshy 1385147191Sjkoshy default: 1386147191Sjkoshy break; /* no options defined */ 1387147191Sjkoshy } 1388147191Sjkoshy 1389147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1390147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1391147191Sjkoshy q = strchr(p, '='); 1392147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1393174406Sjkoshy return (-1); 1394147191Sjkoshy 1395147191Sjkoshy count = strtol(q, &e, 0); 1396147191Sjkoshy if (e == q || *e != '\0') 1397174406Sjkoshy return (-1); 1398147191Sjkoshy 1399147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1400147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1401147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1402147191Sjkoshy 1403147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1404147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1405147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1406147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1407147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1408147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1409174406Sjkoshy return (-1); 1410147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1411147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1412147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1413147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1414147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1415147191Sjkoshy } else 1416174406Sjkoshy return (-1); 1417147191Sjkoshy } 1418147191Sjkoshy 1419147191Sjkoshy /* other post processing */ 1420147191Sjkoshy switch (pe) { 1421147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1422147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1423147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1424147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1425147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1426147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1427147191Sjkoshy /* XXX only available in rev B and later */ 1428147191Sjkoshy break; 1429147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1430147191Sjkoshy /* XXX only available in rev C and later */ 1431147191Sjkoshy break; 1432147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1433147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1434147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1435174406Sjkoshy return (-1); 1436147191Sjkoshy if (evmask == 0) { 1437147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1438147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1439147191Sjkoshy } 1440147191Sjkoshy break; 1441147191Sjkoshy default: 1442147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1443147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1444147191Sjkoshy evmask |= pm->pm_value; 1445147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1446147191Sjkoshy } 1447147191Sjkoshy } 1448147191Sjkoshy 1449147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1450147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1451147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1452147191Sjkoshy 1453174406Sjkoshy return (0); 1454147191Sjkoshy} 1455147191Sjkoshy 1456147191Sjkoshy#endif 1457147191Sjkoshy 1458147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1459147191Sjkoshy 1460147191Sjkoshy/* 1461145256Sjkoshy * Intel P4 PMCs 1462145256Sjkoshy */ 1463145256Sjkoshy 1464145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1465145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1466145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1467145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1468145351Sjkoshy EV_ALIAS("instructions", 1469145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1470155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1471145256Sjkoshy EV_ALIAS(NULL, NULL) 1472145256Sjkoshy}; 1473145256Sjkoshy 1474145256Sjkoshy#define P4_KW_ACTIVE "active" 1475145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1476145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1477145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1478145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1479145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1480145256Sjkoshy#define P4_KW_CASCADE "cascade" 1481145256Sjkoshy#define P4_KW_EDGE "edge" 1482145256Sjkoshy#define P4_KW_INV "complement" 1483145256Sjkoshy#define P4_KW_OS "os" 1484145256Sjkoshy#define P4_KW_MASK "mask" 1485145256Sjkoshy#define P4_KW_PRECISE "precise" 1486145256Sjkoshy#define P4_KW_TAG "tag" 1487145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1488145256Sjkoshy#define P4_KW_USR "usr" 1489145256Sjkoshy 1490145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1491145256Sjkoshy 1492145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1493145256Sjkoshy __P4MASK(dd, 0), 1494145256Sjkoshy __P4MASK(db, 1), 1495145256Sjkoshy __P4MASK(di, 2), 1496145256Sjkoshy __P4MASK(bd, 3), 1497145256Sjkoshy __P4MASK(bb, 4), 1498145256Sjkoshy __P4MASK(bi, 5), 1499145256Sjkoshy __P4MASK(id, 6), 1500145256Sjkoshy __P4MASK(ib, 7), 1501145256Sjkoshy NULLMASK 1502145256Sjkoshy}; 1503145256Sjkoshy 1504145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1505145256Sjkoshy __P4MASK(tcmiss, 0), 1506145256Sjkoshy NULLMASK, 1507145256Sjkoshy}; 1508145256Sjkoshy 1509145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1510145256Sjkoshy __P4MASK(hit, 0), 1511145256Sjkoshy __P4MASK(miss, 1), 1512145256Sjkoshy __P4MASK(hit-uc, 2), 1513145256Sjkoshy NULLMASK 1514145256Sjkoshy}; 1515145256Sjkoshy 1516145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1517145256Sjkoshy __P4MASK(st-rb-full, 2), 1518145256Sjkoshy __P4MASK(64k-conf, 3), 1519145256Sjkoshy NULLMASK 1520145256Sjkoshy}; 1521145256Sjkoshy 1522145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1523145256Sjkoshy __P4MASK(lsc, 0), 1524145256Sjkoshy __P4MASK(ssc, 1), 1525145256Sjkoshy NULLMASK 1526145256Sjkoshy}; 1527145256Sjkoshy 1528145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1529145256Sjkoshy __P4MASK(split-ld, 1), 1530145256Sjkoshy NULLMASK 1531145256Sjkoshy}; 1532145256Sjkoshy 1533145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1534145256Sjkoshy __P4MASK(split-st, 1), 1535145256Sjkoshy NULLMASK 1536145256Sjkoshy}; 1537145256Sjkoshy 1538145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1539145256Sjkoshy __P4MASK(no-sta, 1), 1540145256Sjkoshy __P4MASK(no-std, 3), 1541145256Sjkoshy __P4MASK(partial-data, 4), 1542145256Sjkoshy __P4MASK(unalgn-addr, 5), 1543145256Sjkoshy NULLMASK 1544145256Sjkoshy}; 1545145256Sjkoshy 1546145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1547145256Sjkoshy __P4MASK(dtmiss, 0), 1548145256Sjkoshy __P4MASK(itmiss, 1), 1549145256Sjkoshy NULLMASK 1550145256Sjkoshy}; 1551145256Sjkoshy 1552145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1553145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1554145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1555145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1556145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1557145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1558145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1559145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1560145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1561145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1562145256Sjkoshy NULLMASK 1563145256Sjkoshy}; 1564145256Sjkoshy 1565145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1566145256Sjkoshy __P4MASK(all-read, 5), 1567145256Sjkoshy __P4MASK(all-write, 6), 1568145256Sjkoshy __P4MASK(mem-uc, 7), 1569145256Sjkoshy __P4MASK(mem-wc, 8), 1570145256Sjkoshy __P4MASK(mem-wt, 9), 1571145256Sjkoshy __P4MASK(mem-wp, 10), 1572145256Sjkoshy __P4MASK(mem-wb, 11), 1573145256Sjkoshy __P4MASK(own, 13), 1574145256Sjkoshy __P4MASK(other, 14), 1575145256Sjkoshy __P4MASK(prefetch, 15), 1576145256Sjkoshy NULLMASK 1577145256Sjkoshy}; 1578145256Sjkoshy 1579145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1580145256Sjkoshy __P4MASK(all-read, 5), 1581145256Sjkoshy __P4MASK(all-write, 6), 1582145256Sjkoshy __P4MASK(mem-uc, 7), 1583145256Sjkoshy __P4MASK(mem-wc, 8), 1584145256Sjkoshy __P4MASK(mem-wt, 9), 1585145256Sjkoshy __P4MASK(mem-wp, 10), 1586145256Sjkoshy __P4MASK(mem-wb, 11), 1587145256Sjkoshy __P4MASK(own, 13), 1588145256Sjkoshy __P4MASK(other, 14), 1589145256Sjkoshy __P4MASK(prefetch, 15), 1590145256Sjkoshy NULLMASK 1591145256Sjkoshy}; 1592145256Sjkoshy 1593145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1594145256Sjkoshy __P4MASK(drdy-drv, 0), 1595145256Sjkoshy __P4MASK(drdy-own, 1), 1596145256Sjkoshy __P4MASK(drdy-other, 2), 1597145256Sjkoshy __P4MASK(dbsy-drv, 3), 1598145256Sjkoshy __P4MASK(dbsy-own, 4), 1599145256Sjkoshy __P4MASK(dbsy-other, 5), 1600145256Sjkoshy NULLMASK 1601145256Sjkoshy}; 1602145256Sjkoshy 1603145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1604145256Sjkoshy __P4MASK(req-type0, 0), 1605145256Sjkoshy __P4MASK(req-type1, 1), 1606145256Sjkoshy __P4MASK(req-len0, 2), 1607145256Sjkoshy __P4MASK(req-len1, 3), 1608145256Sjkoshy __P4MASK(req-io-type, 5), 1609145256Sjkoshy __P4MASK(req-lock-type, 6), 1610145256Sjkoshy __P4MASK(req-cache-type, 7), 1611145256Sjkoshy __P4MASK(req-split-type, 8), 1612145256Sjkoshy __P4MASK(req-dem-type, 9), 1613145256Sjkoshy __P4MASK(req-ord-type, 10), 1614145256Sjkoshy __P4MASK(mem-type0, 11), 1615145256Sjkoshy __P4MASK(mem-type1, 12), 1616145256Sjkoshy __P4MASK(mem-type2, 13), 1617145256Sjkoshy NULLMASK 1618145256Sjkoshy}; 1619145256Sjkoshy 1620145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1621145256Sjkoshy __P4MASK(all, 15), 1622145256Sjkoshy NULLMASK 1623145256Sjkoshy}; 1624145256Sjkoshy 1625145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1626145256Sjkoshy __P4MASK(all, 15), 1627145256Sjkoshy NULLMASK 1628145256Sjkoshy}; 1629145256Sjkoshy 1630145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1631145256Sjkoshy __P4MASK(all, 15), 1632145256Sjkoshy NULLMASK 1633145256Sjkoshy}; 1634145256Sjkoshy 1635145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1636145256Sjkoshy __P4MASK(all, 15), 1637145256Sjkoshy NULLMASK 1638145256Sjkoshy}; 1639145256Sjkoshy 1640145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1641145256Sjkoshy __P4MASK(all, 15), 1642145256Sjkoshy NULLMASK 1643145256Sjkoshy}; 1644145256Sjkoshy 1645145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1646145256Sjkoshy __P4MASK(all, 15), 1647145256Sjkoshy NULLMASK 1648145256Sjkoshy}; 1649145256Sjkoshy 1650145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1651145256Sjkoshy __P4MASK(all, 15), 1652145256Sjkoshy NULLMASK 1653145256Sjkoshy}; 1654145256Sjkoshy 1655145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1656145256Sjkoshy __P4MASK(all, 15), 1657145256Sjkoshy NULLMASK 1658145256Sjkoshy}; 1659145256Sjkoshy 1660145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1661145256Sjkoshy __P4MASK(allp0, 3), 1662145256Sjkoshy __P4MASK(allp2, 4), 1663145256Sjkoshy NULLMASK 1664145256Sjkoshy}; 1665145256Sjkoshy 1666145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1667145256Sjkoshy __P4MASK(running, 0), 1668145256Sjkoshy NULLMASK 1669145256Sjkoshy}; 1670145256Sjkoshy 1671145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1672145256Sjkoshy __P4MASK(cisc, 0), 1673145256Sjkoshy NULLMASK 1674145256Sjkoshy}; 1675145256Sjkoshy 1676145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1677145256Sjkoshy __P4MASK(from-tc-build, 0), 1678145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1679145256Sjkoshy __P4MASK(from-rom, 2), 1680145256Sjkoshy NULLMASK 1681145256Sjkoshy}; 1682145256Sjkoshy 1683145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1684145351Sjkoshy /* retired mispred branch type */ 1685145256Sjkoshy __P4MASK(conditional, 1), 1686145256Sjkoshy __P4MASK(call, 2), 1687145256Sjkoshy __P4MASK(return, 3), 1688145256Sjkoshy __P4MASK(indirect, 4), 1689145256Sjkoshy NULLMASK 1690145256Sjkoshy}; 1691145256Sjkoshy 1692145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1693145256Sjkoshy __P4MASK(conditional, 1), 1694145256Sjkoshy __P4MASK(call, 2), 1695145256Sjkoshy __P4MASK(retired, 3), 1696145256Sjkoshy __P4MASK(indirect, 4), 1697145256Sjkoshy NULLMASK 1698145256Sjkoshy}; 1699145256Sjkoshy 1700145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1701145256Sjkoshy __P4MASK(sbfull, 5), 1702145256Sjkoshy NULLMASK 1703145256Sjkoshy}; 1704145256Sjkoshy 1705145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1706145256Sjkoshy __P4MASK(wcb-evicts, 0), 1707145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1708145256Sjkoshy NULLMASK 1709145256Sjkoshy}; 1710145256Sjkoshy 1711145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1712145256Sjkoshy __P4MASK(nbogus, 0), 1713145256Sjkoshy __P4MASK(bogus, 1), 1714145256Sjkoshy NULLMASK 1715145256Sjkoshy}; 1716145256Sjkoshy 1717145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1718145256Sjkoshy __P4MASK(nbogus0, 0), 1719145256Sjkoshy __P4MASK(nbogus1, 1), 1720145256Sjkoshy __P4MASK(nbogus2, 2), 1721145256Sjkoshy __P4MASK(nbogus3, 3), 1722145256Sjkoshy __P4MASK(bogus0, 4), 1723145256Sjkoshy __P4MASK(bogus1, 5), 1724145256Sjkoshy __P4MASK(bogus2, 6), 1725145256Sjkoshy __P4MASK(bogus3, 7), 1726145256Sjkoshy NULLMASK 1727145256Sjkoshy}; 1728145256Sjkoshy 1729145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1730145256Sjkoshy __P4MASK(nbogus, 0), 1731145256Sjkoshy __P4MASK(bogus, 1), 1732145256Sjkoshy NULLMASK 1733145256Sjkoshy}; 1734145256Sjkoshy 1735145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1736145256Sjkoshy __P4MASK(nbogusntag, 0), 1737145256Sjkoshy __P4MASK(nbogustag, 1), 1738145256Sjkoshy __P4MASK(bogusntag, 2), 1739145256Sjkoshy __P4MASK(bogustag, 3), 1740145256Sjkoshy NULLMASK 1741145256Sjkoshy}; 1742145256Sjkoshy 1743145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1744145256Sjkoshy __P4MASK(nbogus, 0), 1745145256Sjkoshy __P4MASK(bogus, 1), 1746145256Sjkoshy NULLMASK 1747145256Sjkoshy}; 1748145256Sjkoshy 1749145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1750145256Sjkoshy __P4MASK(tagloads, 1), 1751145256Sjkoshy __P4MASK(tagstores, 2), 1752145256Sjkoshy NULLMASK 1753145256Sjkoshy}; 1754145256Sjkoshy 1755145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1756145256Sjkoshy __P4MASK(mmnp, 0), 1757145256Sjkoshy __P4MASK(mmnm, 1), 1758145256Sjkoshy __P4MASK(mmtp, 2), 1759145256Sjkoshy __P4MASK(mmtm, 3), 1760145256Sjkoshy NULLMASK 1761145256Sjkoshy}; 1762145256Sjkoshy 1763145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1764145256Sjkoshy __P4MASK(nbogus, 0), 1765145256Sjkoshy NULLMASK 1766145256Sjkoshy}; 1767145256Sjkoshy 1768145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1769145256Sjkoshy __P4MASK(fpsu, 0), 1770145256Sjkoshy __P4MASK(fpso, 1), 1771145256Sjkoshy __P4MASK(poao, 2), 1772145256Sjkoshy __P4MASK(poau, 3), 1773145256Sjkoshy __P4MASK(prea, 4), 1774145256Sjkoshy NULLMASK 1775145256Sjkoshy}; 1776145256Sjkoshy 1777145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1778145256Sjkoshy __P4MASK(clear, 0), 1779145256Sjkoshy __P4MASK(moclear, 2), 1780145256Sjkoshy __P4MASK(smclear, 3), 1781145256Sjkoshy NULLMASK 1782145256Sjkoshy}; 1783145256Sjkoshy 1784145256Sjkoshy/* P4 event parser */ 1785145256Sjkoshystatic int 1786145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1787145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1788145256Sjkoshy{ 1789145256Sjkoshy 1790145256Sjkoshy char *e, *p, *q; 1791145256Sjkoshy int count, has_tag, has_busreqtype, n; 1792240164Sfabient uint32_t cccractivemask; 1793240164Sfabient uint64_t evmask; 1794145256Sjkoshy const struct pmc_masks *pm, *pmask; 1795145256Sjkoshy 1796183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1797147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1798147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1799145256Sjkoshy 1800145256Sjkoshy pmask = NULL; 1801145256Sjkoshy evmask = 0; 1802145256Sjkoshy cccractivemask = 0x3; 1803145256Sjkoshy has_tag = has_busreqtype = 0; 1804145256Sjkoshy 1805145256Sjkoshy#define __P4SETMASK(M) do { \ 1806183107Sjkoshy pmask = p4_mask_##M; \ 1807145256Sjkoshy} while (0) 1808145256Sjkoshy 1809145256Sjkoshy switch (pe) { 1810145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1811145256Sjkoshy __P4SETMASK(tcdm); 1812145256Sjkoshy break; 1813145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1814145256Sjkoshy __P4SETMASK(bfr); 1815145256Sjkoshy break; 1816145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1817145256Sjkoshy __P4SETMASK(ir); 1818145256Sjkoshy break; 1819145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1820145256Sjkoshy __P4SETMASK(memcan); 1821145256Sjkoshy break; 1822145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1823145256Sjkoshy __P4SETMASK(memcomp); 1824145256Sjkoshy break; 1825145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1826145256Sjkoshy __P4SETMASK(lpr); 1827145256Sjkoshy break; 1828145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1829145256Sjkoshy __P4SETMASK(spr); 1830145256Sjkoshy break; 1831145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1832145256Sjkoshy __P4SETMASK(mlr); 1833145256Sjkoshy break; 1834145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1835145256Sjkoshy __P4SETMASK(pwt); 1836145256Sjkoshy break; 1837145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1838145256Sjkoshy __P4SETMASK(bcr); 1839145256Sjkoshy break; 1840145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1841145256Sjkoshy __P4SETMASK(ia); 1842145256Sjkoshy has_busreqtype = 1; 1843145256Sjkoshy break; 1844145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1845145256Sjkoshy __P4SETMASK(iae); 1846145256Sjkoshy has_busreqtype = 1; 1847145256Sjkoshy break; 1848145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1849145256Sjkoshy __P4SETMASK(fda); 1850145256Sjkoshy break; 1851145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1852145256Sjkoshy __P4SETMASK(ba); 1853145256Sjkoshy break; 1854145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1855145256Sjkoshy __P4SETMASK(sia); 1856145256Sjkoshy break; 1857145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1858145256Sjkoshy __P4SETMASK(psu); 1859145256Sjkoshy break; 1860145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1861145256Sjkoshy __P4SETMASK(pdu); 1862145256Sjkoshy break; 1863145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1864145256Sjkoshy __P4SETMASK(ssu); 1865145256Sjkoshy break; 1866145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1867145256Sjkoshy __P4SETMASK(sdu); 1868145256Sjkoshy break; 1869145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1870145256Sjkoshy __P4SETMASK(64bmu); 1871145256Sjkoshy break; 1872145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1873145256Sjkoshy __P4SETMASK(128bmu); 1874145256Sjkoshy break; 1875145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1876145256Sjkoshy __P4SETMASK(xfu); 1877145256Sjkoshy break; 1878145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1879145256Sjkoshy __P4SETMASK(xsmu); 1880145256Sjkoshy break; 1881145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1882145256Sjkoshy __P4SETMASK(gpe); 1883145256Sjkoshy break; 1884145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1885145256Sjkoshy __P4SETMASK(tmx); 1886145256Sjkoshy break; 1887145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1888145256Sjkoshy __P4SETMASK(uqw); 1889145256Sjkoshy break; 1890145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1891145256Sjkoshy __P4SETMASK(rmbt); 1892145256Sjkoshy break; 1893145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1894145256Sjkoshy __P4SETMASK(rbt); 1895145256Sjkoshy break; 1896145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1897145256Sjkoshy __P4SETMASK(rs); 1898145256Sjkoshy break; 1899145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1900145256Sjkoshy __P4SETMASK(wb); 1901145256Sjkoshy break; 1902145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1903145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1904145256Sjkoshy case PMC_EV_P4_BNR: 1905145256Sjkoshy case PMC_EV_P4_SNOOP: 1906145256Sjkoshy case PMC_EV_P4_RESPONSE: 1907145256Sjkoshy break; 1908145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1909145256Sjkoshy __P4SETMASK(fee); 1910145256Sjkoshy break; 1911145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1912145256Sjkoshy __P4SETMASK(ee); 1913145256Sjkoshy break; 1914145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1915145256Sjkoshy __P4SETMASK(re); 1916145256Sjkoshy break; 1917145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1918145256Sjkoshy __P4SETMASK(insret); 1919145256Sjkoshy break; 1920145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1921145256Sjkoshy __P4SETMASK(ur); 1922145256Sjkoshy break; 1923145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1924145256Sjkoshy __P4SETMASK(ut); 1925145256Sjkoshy break; 1926145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1927145256Sjkoshy __P4SETMASK(br); 1928145256Sjkoshy break; 1929145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1930145256Sjkoshy __P4SETMASK(mbr); 1931145256Sjkoshy break; 1932145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1933145256Sjkoshy __P4SETMASK(xa); 1934145256Sjkoshy break; 1935145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1936145256Sjkoshy __P4SETMASK(machclr); 1937145256Sjkoshy break; 1938145256Sjkoshy default: 1939174406Sjkoshy return (-1); 1940145256Sjkoshy } 1941145256Sjkoshy 1942145256Sjkoshy /* process additional flags */ 1943145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1944145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1945145256Sjkoshy q = strchr(p, '='); 1946145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1947174406Sjkoshy return (-1); 1948145256Sjkoshy 1949183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1950145256Sjkoshy cccractivemask = 0x0; 1951183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1952145256Sjkoshy cccractivemask = 0x1; 1953183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1954145256Sjkoshy cccractivemask = 0x2; 1955183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1956145256Sjkoshy cccractivemask = 0x3; 1957145256Sjkoshy else 1958174406Sjkoshy return (-1); 1959145256Sjkoshy 1960145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1961145256Sjkoshy if (has_busreqtype == 0) 1962174406Sjkoshy return (-1); 1963145256Sjkoshy 1964145256Sjkoshy q = strchr(p, '='); 1965145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1966174406Sjkoshy return (-1); 1967145256Sjkoshy 1968145256Sjkoshy count = strtol(q, &e, 0); 1969145256Sjkoshy if (e == q || *e != '\0') 1970174406Sjkoshy return (-1); 1971145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1972145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1973145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1974145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1975145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1976145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1977145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1978145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1979145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1980174406Sjkoshy return (-1); 1981145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1982145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1983145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1984145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1985145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1986145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1987145256Sjkoshy if (has_tag == 0) 1988174406Sjkoshy return (-1); 1989145256Sjkoshy 1990145256Sjkoshy q = strchr(p, '='); 1991145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1992174406Sjkoshy return (-1); 1993145256Sjkoshy 1994145256Sjkoshy count = strtol(q, &e, 0); 1995145256Sjkoshy if (e == q || *e != '\0') 1996174406Sjkoshy return (-1); 1997145256Sjkoshy 1998145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1999147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 2000145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 2001145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 2002145256Sjkoshy q = strchr(p, '='); 2003145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2004174406Sjkoshy return (-1); 2005145256Sjkoshy 2006145256Sjkoshy count = strtol(q, &e, 0); 2007145256Sjkoshy if (e == q || *e != '\0') 2008174406Sjkoshy return (-1); 2009145256Sjkoshy 2010145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2011147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 2012147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 2013147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 2014147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 2015145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 2016145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2017145256Sjkoshy else 2018174406Sjkoshy return (-1); 2019145256Sjkoshy } 2020145256Sjkoshy 2021145256Sjkoshy /* other post processing */ 2022145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 2023145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 2024145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 2025145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2026145256Sjkoshy 2027145256Sjkoshy /* fill in thread activity mask */ 2028147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 2029145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 2030145256Sjkoshy 2031145256Sjkoshy if (evmask) 2032145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2033145256Sjkoshy 2034145256Sjkoshy switch (pe) { 2035145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 2036145256Sjkoshy if ((evmask & 0x06) == 0x06 || 2037145256Sjkoshy (evmask & 0x18) == 0x18) 2038174406Sjkoshy return (-1); /* can't have own+other bits together */ 2039145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 2040145256Sjkoshy evmask = 0x1D; 2041145256Sjkoshy break; 2042145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 2043145256Sjkoshy /* only one bit is allowed to be set */ 2044145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 2045174406Sjkoshy return (-1); 2046145256Sjkoshy if (evmask == 0) { 2047183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 2048145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2049145256Sjkoshy } 2050145256Sjkoshy break; 2051145256Sjkoshy default: 2052145256Sjkoshy if (evmask == 0 && pmask) { 2053145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2054145256Sjkoshy evmask |= pm->pm_value; 2055145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2056145256Sjkoshy } 2057145256Sjkoshy } 2058145256Sjkoshy 2059147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 2060147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 2061145256Sjkoshy 2062174406Sjkoshy return (0); 2063145256Sjkoshy} 2064145256Sjkoshy 2065147759Sjkoshy#endif 2066147759Sjkoshy 2067147759Sjkoshy#if defined(__i386__) 2068147759Sjkoshy 2069145256Sjkoshy/* 2070147191Sjkoshy * Pentium style PMCs 2071147191Sjkoshy */ 2072147191Sjkoshy 2073147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 2074183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 2075183105Sjkoshy EV_ALIAS("cycles", "tsc"), 2076183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 2077183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 2078183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 2079183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 2080183105Sjkoshy EV_ALIAS("unhalted-cycles", 2081183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 2082147191Sjkoshy EV_ALIAS(NULL, NULL) 2083147191Sjkoshy}; 2084147191Sjkoshy 2085147191Sjkoshystatic int 2086147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 2087147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2088147191Sjkoshy{ 2089174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 2090147191Sjkoshy} 2091147191Sjkoshy 2092147191Sjkoshy/* 2093145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 2094145256Sjkoshy * and Pentium M CPUs. 2095145256Sjkoshy */ 2096145256Sjkoshy 2097145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 2098145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 2099145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 2100145351Sjkoshy EV_ALIAS("cycles", "tsc"), 2101145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 2102168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 2103145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 2104145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 2105155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 2106145351Sjkoshy EV_ALIAS(NULL, NULL) 2107145256Sjkoshy}; 2108145256Sjkoshy 2109145256Sjkoshy#define P6_KW_CMASK "cmask" 2110145256Sjkoshy#define P6_KW_EDGE "edge" 2111145256Sjkoshy#define P6_KW_INV "inv" 2112145256Sjkoshy#define P6_KW_OS "os" 2113145256Sjkoshy#define P6_KW_UMASK "umask" 2114145256Sjkoshy#define P6_KW_USR "usr" 2115145256Sjkoshy 2116145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 2117145256Sjkoshy PMCMASK(m, 0x01), 2118145256Sjkoshy PMCMASK(e, 0x02), 2119145256Sjkoshy PMCMASK(s, 0x04), 2120145256Sjkoshy PMCMASK(i, 0x08), 2121145256Sjkoshy NULLMASK 2122145256Sjkoshy}; 2123145256Sjkoshy 2124145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 2125145256Sjkoshy PMCMASK(m, 0x01), 2126145256Sjkoshy PMCMASK(e, 0x02), 2127145256Sjkoshy PMCMASK(s, 0x04), 2128145256Sjkoshy PMCMASK(i, 0x08), 2129145256Sjkoshy PMCMASK(nonhw, 0x00), 2130145256Sjkoshy PMCMASK(hw, 0x10), 2131145256Sjkoshy PMCMASK(both, 0x30), 2132145256Sjkoshy NULLMASK 2133145256Sjkoshy}; 2134145256Sjkoshy 2135145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 2136145256Sjkoshy PMCMASK(nonhw, 0x00), 2137145256Sjkoshy PMCMASK(hw, 0x10), 2138145256Sjkoshy PMCMASK(both, 0x30), 2139145256Sjkoshy NULLMASK 2140145256Sjkoshy}; 2141145256Sjkoshy 2142145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 2143145256Sjkoshy PMCMASK(self, 0x00), 2144145256Sjkoshy PMCMASK(any, 0x20), 2145145256Sjkoshy NULLMASK 2146145256Sjkoshy}; 2147145256Sjkoshy 2148145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 2149145256Sjkoshy PMCMASK(nta, 0x00), 2150145256Sjkoshy PMCMASK(t1, 0x01), 2151145256Sjkoshy PMCMASK(t2, 0x02), 2152145256Sjkoshy PMCMASK(wos, 0x03), 2153145256Sjkoshy NULLMASK 2154145256Sjkoshy}; 2155145256Sjkoshy 2156145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 2157145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 2158145256Sjkoshy PMCMASK(scalar, 0x01), 2159145256Sjkoshy NULLMASK 2160145256Sjkoshy}; 2161145256Sjkoshy 2162145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 2163145256Sjkoshy PMCMASK(packed-multiply, 0x01), 2164145256Sjkoshy PMCMASK(packed-shift, 0x02), 2165145256Sjkoshy PMCMASK(pack, 0x04), 2166145256Sjkoshy PMCMASK(unpack, 0x08), 2167145256Sjkoshy PMCMASK(packed-logical, 0x10), 2168145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 2169145256Sjkoshy NULLMASK 2170145256Sjkoshy}; 2171145256Sjkoshy 2172145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 2173145256Sjkoshy PMCMASK(mmxtofp, 0x00), 2174145256Sjkoshy PMCMASK(fptommx, 0x01), 2175145256Sjkoshy NULLMASK 2176145256Sjkoshy}; 2177145256Sjkoshy 2178145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 2179145256Sjkoshy PMCMASK(es, 0x01), 2180145256Sjkoshy PMCMASK(ds, 0x02), 2181145256Sjkoshy PMCMASK(fs, 0x04), 2182145256Sjkoshy PMCMASK(gs, 0x08), 2183145256Sjkoshy NULLMASK 2184145256Sjkoshy}; 2185145256Sjkoshy 2186145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 2187145256Sjkoshy PMCMASK(all, 0x00), 2188145256Sjkoshy PMCMASK(freq, 0x02), 2189145256Sjkoshy NULLMASK 2190145256Sjkoshy}; 2191145256Sjkoshy 2192145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 2193145256Sjkoshy PMCMASK(all, 0x00), 2194145256Sjkoshy PMCMASK(loadop, 0x01), 2195145256Sjkoshy PMCMASK(stdsta, 0x02), 2196145256Sjkoshy NULLMASK 2197145256Sjkoshy}; 2198145256Sjkoshy 2199145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 2200145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2201145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 2202145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2203145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2204145256Sjkoshy NULLMASK 2205145256Sjkoshy}; 2206145256Sjkoshy 2207145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 2208145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2209145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 2210145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2211145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2212145256Sjkoshy NULLMASK 2213145256Sjkoshy}; 2214145256Sjkoshy 2215145256Sjkoshy/* P6 event parser */ 2216145256Sjkoshystatic int 2217145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 2218145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2219145256Sjkoshy{ 2220145256Sjkoshy char *e, *p, *q; 2221240164Sfabient uint64_t evmask; 2222145256Sjkoshy int count, n; 2223145256Sjkoshy const struct pmc_masks *pm, *pmask; 2224145256Sjkoshy 2225183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2226147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 2227145256Sjkoshy 2228145256Sjkoshy evmask = 0; 2229145256Sjkoshy 2230145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 2231145256Sjkoshy 2232145256Sjkoshy switch(pe) { 2233183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 2234145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 2235145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2236145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2237145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2238145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2239145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2240145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2241145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2242145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2243145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2244145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2245145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2246145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2247145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2248145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2249145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2250145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2251145256Sjkoshy P6MASKSET(any); break; 2252145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2253145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2254145256Sjkoshy P6MASKSET(ekp); break; 2255145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2256145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2257145256Sjkoshy P6MASKSET(pps); break; 2258145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2259145256Sjkoshy P6MASKSET(mite); break; 2260145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2261145256Sjkoshy P6MASKSET(fmt); break; 2262145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2263145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2264145256Sjkoshy P6MASKSET(sr); break; 2265145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2266145256Sjkoshy P6MASKSET(eet); break; 2267145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2268145256Sjkoshy P6MASKSET(efur); break; 2269145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2270145256Sjkoshy P6MASKSET(essir); break; 2271145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2272145256Sjkoshy P6MASKSET(esscir); break; 2273145256Sjkoshy default: 2274145256Sjkoshy pmask = NULL; 2275145256Sjkoshy break; 2276145256Sjkoshy } 2277145256Sjkoshy 2278145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2279145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2280145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2281145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2282145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2283145256Sjkoshy P6MASKSET(mesihw); 2284145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2285145256Sjkoshy P6MASKSET(hw); 2286145256Sjkoshy } 2287145256Sjkoshy 2288145256Sjkoshy /* Parse additional modifiers if present */ 2289145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2290145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2291145256Sjkoshy q = strchr(p, '='); 2292145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2293174406Sjkoshy return (-1); 2294145256Sjkoshy count = strtol(q, &e, 0); 2295145256Sjkoshy if (e == q || *e != '\0') 2296174406Sjkoshy return (-1); 2297145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2298147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2299147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2300145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2301145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2302145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2303145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2304145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2305145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2306145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2307145256Sjkoshy evmask = 0; 2308145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2309174406Sjkoshy return (-1); 2310145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2311145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2312145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2313145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2314145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2315145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2316145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2317145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2318145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2319145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2320145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2321145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2322145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2323145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2324145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2325145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2326145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2327145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2328145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2329145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2330145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2331145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2332145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2333174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2334174406Sjkoshy return (-1); 2335145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2336145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2337145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2338145256Sjkoshy } else 2339174406Sjkoshy return (-1); 2340145256Sjkoshy } 2341145256Sjkoshy 2342145256Sjkoshy /* post processing */ 2343145256Sjkoshy switch (pe) { 2344145256Sjkoshy 2345145256Sjkoshy /* 2346145256Sjkoshy * The following events default to an evmask of 0 2347145256Sjkoshy */ 2348145256Sjkoshy 2349145256Sjkoshy /* default => 'self' */ 2350145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2351145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2352145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2353145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2354145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2355145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2356145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2357145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2358145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2359145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2360145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2361145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2362145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2363145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2364145256Sjkoshy 2365145256Sjkoshy /* default => 'nta' */ 2366145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2367145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2368145256Sjkoshy 2369145256Sjkoshy /* default => 'packed and scalar' */ 2370145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2371145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2372145256Sjkoshy 2373145256Sjkoshy /* default => 'mmx to fp transitions' */ 2374145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2375145256Sjkoshy 2376145256Sjkoshy /* default => 'SSE Packed Single' */ 2377145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2378145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2379145256Sjkoshy 2380145256Sjkoshy /* default => 'all fused micro-ops' */ 2381145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2382145256Sjkoshy 2383145256Sjkoshy /* default => 'all transitions' */ 2384145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2385145256Sjkoshy break; 2386145256Sjkoshy 2387145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2388145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2389145256Sjkoshy break; 2390145256Sjkoshy 2391145256Sjkoshy default: 2392145256Sjkoshy /* 2393145256Sjkoshy * For all other events, set the default event mask 2394145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2395145256Sjkoshy */ 2396145256Sjkoshy if (evmask == 0 && pmask) { 2397145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2398145256Sjkoshy evmask |= pm->pm_value; 2399145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2400145256Sjkoshy } 2401145256Sjkoshy 2402145256Sjkoshy break; 2403145256Sjkoshy } 2404145256Sjkoshy 2405145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2406147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2407147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2408145256Sjkoshy 2409174406Sjkoshy return (0); 2410145256Sjkoshy} 2411145256Sjkoshy 2412147191Sjkoshy#endif 2413147191Sjkoshy 2414183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2415183725Sjkoshystatic int 2416183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2417183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2418183725Sjkoshy{ 2419183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2420183725Sjkoshy return (-1); 2421183725Sjkoshy 2422183725Sjkoshy /* TSC events must be unqualified. */ 2423183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2424183725Sjkoshy return (-1); 2425183725Sjkoshy 2426183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2427183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2428183725Sjkoshy 2429183725Sjkoshy return (0); 2430183725Sjkoshy} 2431183725Sjkoshy#endif 2432183725Sjkoshy 2433233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2434233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2435233628Sfabient EV_ALIAS(NULL, NULL) 2436233628Sfabient}; 2437233628Sfabient 2438233628Sfabientstatic int 2439233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2440233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2441233628Sfabient{ 2442233628Sfabient (void)ctrspec; 2443233628Sfabient (void)pmc_config; 2444233628Sfabient 2445242622Sdim if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST) 2446233628Sfabient return (-1); 2447233628Sfabient 2448233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2449233628Sfabient return (0); 2450233628Sfabient} 2451233628Sfabient 2452200928Srpaulo#if defined(__XSCALE__) 2453200928Srpaulo 2454200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2455200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2456200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2457200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2458200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2459200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2460200928Srpaulo EV_ALIAS(NULL, NULL) 2461200928Srpaulo}; 2462200928Srpaulostatic int 2463200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2464200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2465200928Srpaulo{ 2466200928Srpaulo switch (pe) { 2467200928Srpaulo default: 2468200928Srpaulo break; 2469200928Srpaulo } 2470200928Srpaulo 2471200928Srpaulo return (0); 2472200928Srpaulo} 2473200928Srpaulo#endif 2474200928Srpaulo 2475204635Sgnn#if defined(__mips__) 2476204635Sgnn 2477204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2478204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2479204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2480204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2481204635Sgnn EV_ALIAS(NULL, NULL) 2482204635Sgnn}; 2483204635Sgnn 2484233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2485233335Sgonzo EV_ALIAS("instructions", "RET"), 2486233335Sgonzo EV_ALIAS("branches", "BR"), 2487233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2488233335Sgonzo EV_ALIAS(NULL, NULL) 2489233335Sgonzo}; 2490233335Sgonzo 2491233320Sgonzo#define MIPS_KW_OS "os" 2492233320Sgonzo#define MIPS_KW_USR "usr" 2493233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2494204635Sgnn 2495204635Sgnnstatic int 2496233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2497204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2498204635Sgnn{ 2499204635Sgnn char *p; 2500204635Sgnn 2501204635Sgnn (void) pe; 2502204635Sgnn 2503204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2504204635Sgnn 2505204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2506233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2507204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2508233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2509204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2510233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2511204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2512204635Sgnn else 2513204635Sgnn return (-1); 2514204635Sgnn } 2515204635Sgnn 2516204635Sgnn return (0); 2517204635Sgnn} 2518233320Sgonzo 2519204635Sgnn#endif /* __mips__ */ 2520204635Sgnn 2521228869Sjhibbits#if defined(__powerpc__) 2522204635Sgnn 2523228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2524228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2525228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2526228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2527228869Sjhibbits EV_ALIAS(NULL, NULL) 2528228869Sjhibbits}; 2529228869Sjhibbits 2530263122Sjhibbitsstatic struct pmc_event_alias ppc970_aliases[] = { 2531263122Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2532263122Sjhibbits EV_ALIAS("cycles", "CYCLES"), 2533263122Sjhibbits EV_ALIAS(NULL, NULL) 2534263122Sjhibbits}; 2535228869Sjhibbits 2536263122Sjhibbits#define POWERPC_KW_OS "os" 2537263122Sjhibbits#define POWERPC_KW_USR "usr" 2538263122Sjhibbits#define POWERPC_KW_ANYTHREAD "anythread" 2539263122Sjhibbits 2540228869Sjhibbitsstatic int 2541263122Sjhibbitspowerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2542263122Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2543228869Sjhibbits{ 2544228869Sjhibbits char *p; 2545228869Sjhibbits 2546228869Sjhibbits (void) pe; 2547228869Sjhibbits 2548228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2549228869Sjhibbits 2550228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2551263122Sjhibbits if (KWMATCH(p, POWERPC_KW_OS)) 2552228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2553263122Sjhibbits else if (KWMATCH(p, POWERPC_KW_USR)) 2554228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2555263122Sjhibbits else if (KWMATCH(p, POWERPC_KW_ANYTHREAD)) 2556228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2557228869Sjhibbits else 2558228869Sjhibbits return (-1); 2559228869Sjhibbits } 2560228869Sjhibbits 2561228869Sjhibbits return (0); 2562228869Sjhibbits} 2563263122Sjhibbits 2564228869Sjhibbits#endif /* __powerpc__ */ 2565228869Sjhibbits 2566228869Sjhibbits 2567145256Sjkoshy/* 2568183725Sjkoshy * Match an event name `name' with its canonical form. 2569183725Sjkoshy * 2570185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2571185363Sjkoshy * hyphen characters are considered to match each other. 2572185363Sjkoshy * 2573183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2574183725Sjkoshy */ 2575183725Sjkoshy 2576183725Sjkoshystatic int 2577183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2578183725Sjkoshy{ 2579183725Sjkoshy int cc, nc; 2580183725Sjkoshy const unsigned char *c, *n; 2581183725Sjkoshy 2582183725Sjkoshy c = (const unsigned char *) canonicalname; 2583183725Sjkoshy n = (const unsigned char *) name; 2584183725Sjkoshy 2585183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2586183725Sjkoshy 2587185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2588185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2589183725Sjkoshy continue; 2590183725Sjkoshy 2591185363Sjkoshy if (toupper(nc) == toupper(cc)) 2592183725Sjkoshy continue; 2593183725Sjkoshy 2594185363Sjkoshy 2595183725Sjkoshy return (0); 2596183725Sjkoshy } 2597183725Sjkoshy 2598183725Sjkoshy if (*n == '\0' && *c == '\0') 2599183725Sjkoshy return (1); 2600183725Sjkoshy 2601183725Sjkoshy return (0); 2602183725Sjkoshy} 2603183725Sjkoshy 2604183725Sjkoshy/* 2605183725Sjkoshy * Match an event name against all the event named supported by a 2606183725Sjkoshy * PMC class. 2607183725Sjkoshy * 2608183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2609183725Sjkoshy */ 2610183725Sjkoshystatic const struct pmc_event_descr * 2611183725Sjkoshypmc_match_event_class(const char *name, 2612183725Sjkoshy const struct pmc_class_descr *pcd) 2613183725Sjkoshy{ 2614183725Sjkoshy size_t n; 2615183725Sjkoshy const struct pmc_event_descr *ev; 2616185363Sjkoshy 2617183725Sjkoshy ev = pcd->pm_evc_event_table; 2618183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2619183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2620183725Sjkoshy return (ev); 2621183725Sjkoshy 2622183725Sjkoshy return (NULL); 2623183725Sjkoshy} 2624183725Sjkoshy 2625183725Sjkoshystatic int 2626183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2627183725Sjkoshy{ 2628183725Sjkoshy size_t n; 2629183725Sjkoshy 2630183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2631183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2632183725Sjkoshy return (1); 2633183725Sjkoshy return (0); 2634183725Sjkoshy} 2635183725Sjkoshy 2636183725Sjkoshy/* 2637147191Sjkoshy * API entry points 2638145256Sjkoshy */ 2639145256Sjkoshy 2640147191Sjkoshyint 2641147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2642147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2643145256Sjkoshy{ 2644183725Sjkoshy size_t n; 2645147191Sjkoshy int retval; 2646147191Sjkoshy char *r, *spec_copy; 2647147191Sjkoshy const char *ctrname; 2648183725Sjkoshy const struct pmc_event_descr *ev; 2649183725Sjkoshy const struct pmc_event_alias *alias; 2650147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2651183725Sjkoshy const struct pmc_class_descr *pcd; 2652145256Sjkoshy 2653147191Sjkoshy spec_copy = NULL; 2654147191Sjkoshy retval = -1; 2655145256Sjkoshy 2656147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2657147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2658147191Sjkoshy errno = EINVAL; 2659147191Sjkoshy goto out; 2660147191Sjkoshy } 2661145256Sjkoshy 2662147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2663147191Sjkoshy if (pmc_mdep_event_aliases) 2664183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2665183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2666183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2667147191Sjkoshy break; 2668147191Sjkoshy } 2669145256Sjkoshy 2670147191Sjkoshy if (spec_copy == NULL) 2671147191Sjkoshy spec_copy = strdup(ctrspec); 2672145256Sjkoshy 2673147191Sjkoshy r = spec_copy; 2674147191Sjkoshy ctrname = strsep(&r, ","); 2675145256Sjkoshy 2676183725Sjkoshy /* 2677183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2678183725Sjkoshy * search for the event to the specified PMC class. 2679183725Sjkoshy */ 2680183725Sjkoshy ev = NULL; 2681185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2682185363Sjkoshy pcd = pmc_class_table[n]; 2683183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2684183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2685183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2686183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2687183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2688183725Sjkoshy errno = EINVAL; 2689183725Sjkoshy goto out; 2690183725Sjkoshy } 2691147191Sjkoshy break; 2692183725Sjkoshy } 2693183725Sjkoshy } 2694145256Sjkoshy 2695183725Sjkoshy /* 2696183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2697183725Sjkoshy * classes. 2698183725Sjkoshy */ 2699185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2700185363Sjkoshy pcd = pmc_class_table[n]; 2701183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2702183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2703183725Sjkoshy } 2704183725Sjkoshy 2705183725Sjkoshy if (ev == NULL) { 2706147191Sjkoshy errno = EINVAL; 2707147191Sjkoshy goto out; 2708147191Sjkoshy } 2709145256Sjkoshy 2710147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2711183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2712183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2713147191Sjkoshy pmc_config.pm_cpu = cpu; 2714147191Sjkoshy pmc_config.pm_mode = mode; 2715147191Sjkoshy pmc_config.pm_flags = flags; 2716145256Sjkoshy 2717147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2718147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2719145256Sjkoshy 2720183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2721147191Sjkoshy errno = EINVAL; 2722147191Sjkoshy goto out; 2723147191Sjkoshy } 2724145256Sjkoshy 2725147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2726147191Sjkoshy goto out; 2727145256Sjkoshy 2728147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2729145256Sjkoshy 2730147191Sjkoshy retval = 0; 2731145256Sjkoshy 2732147191Sjkoshy out: 2733147191Sjkoshy if (spec_copy) 2734147191Sjkoshy free(spec_copy); 2735145256Sjkoshy 2736174406Sjkoshy return (retval); 2737147191Sjkoshy} 2738145256Sjkoshy 2739147191Sjkoshyint 2740147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2741147191Sjkoshy{ 2742147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2743145256Sjkoshy 2744147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2745147191Sjkoshy pmc_attach_args.pm_pid = pid; 2746145256Sjkoshy 2747174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2748147191Sjkoshy} 2749145256Sjkoshy 2750147191Sjkoshyint 2751147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2752147191Sjkoshy{ 2753147191Sjkoshy unsigned int i; 2754147191Sjkoshy enum pmc_class cl; 2755145256Sjkoshy 2756147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2757147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2758147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2759147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2760174406Sjkoshy return (0); 2761147191Sjkoshy } 2762177107Sjkoshy errno = EINVAL; 2763177107Sjkoshy return (-1); 2764147191Sjkoshy} 2765145256Sjkoshy 2766147191Sjkoshyint 2767147191Sjkoshypmc_configure_logfile(int fd) 2768147191Sjkoshy{ 2769147191Sjkoshy struct pmc_op_configurelog cla; 2770145256Sjkoshy 2771147191Sjkoshy cla.pm_logfd = fd; 2772147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2773174406Sjkoshy return (-1); 2774174406Sjkoshy return (0); 2775147191Sjkoshy} 2776145256Sjkoshy 2777147191Sjkoshyint 2778147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2779147191Sjkoshy{ 2780147191Sjkoshy if (pmc_syscall == -1) { 2781147191Sjkoshy errno = ENXIO; 2782174406Sjkoshy return (-1); 2783147191Sjkoshy } 2784145256Sjkoshy 2785147219Sjkoshy *pci = &cpu_info; 2786174406Sjkoshy return (0); 2787147191Sjkoshy} 2788145256Sjkoshy 2789147191Sjkoshyint 2790147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2791147191Sjkoshy{ 2792147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2793145256Sjkoshy 2794147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2795147191Sjkoshy pmc_detach_args.pm_pid = pid; 2796174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2797147191Sjkoshy} 2798147191Sjkoshy 2799147191Sjkoshyint 2800147191Sjkoshypmc_disable(int cpu, int pmc) 2801145256Sjkoshy{ 2802147191Sjkoshy struct pmc_op_pmcadmin ssa; 2803145256Sjkoshy 2804147191Sjkoshy ssa.pm_cpu = cpu; 2805147191Sjkoshy ssa.pm_pmc = pmc; 2806147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2807174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2808147191Sjkoshy} 2809145256Sjkoshy 2810147191Sjkoshyint 2811147191Sjkoshypmc_enable(int cpu, int pmc) 2812147191Sjkoshy{ 2813147191Sjkoshy struct pmc_op_pmcadmin ssa; 2814145256Sjkoshy 2815147191Sjkoshy ssa.pm_cpu = cpu; 2816147191Sjkoshy ssa.pm_pmc = pmc; 2817147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2818174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2819147191Sjkoshy} 2820145256Sjkoshy 2821147191Sjkoshy/* 2822147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2823147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2824147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2825147191Sjkoshy * the number of event name pointers returned. 2826147191Sjkoshy * 2827147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2828147191Sjkoshy * is responsible for freeing this space when done. 2829147191Sjkoshy */ 2830147191Sjkoshyint 2831147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2832147191Sjkoshy int *nevents) 2833147191Sjkoshy{ 2834147191Sjkoshy int count; 2835147191Sjkoshy const char **names; 2836147191Sjkoshy const struct pmc_event_descr *ev; 2837147191Sjkoshy 2838147191Sjkoshy switch (cl) 2839147191Sjkoshy { 2840185363Sjkoshy case PMC_CLASS_IAF: 2841185363Sjkoshy ev = iaf_event_table; 2842185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2843185363Sjkoshy break; 2844185363Sjkoshy case PMC_CLASS_IAP: 2845185363Sjkoshy /* 2846185363Sjkoshy * Return the most appropriate set of event name 2847185363Sjkoshy * spellings for the current CPU. 2848185363Sjkoshy */ 2849185363Sjkoshy switch (cpu_info.pm_cputype) { 2850185363Sjkoshy default: 2851185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2852185363Sjkoshy ev = atom_event_table; 2853185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2854185363Sjkoshy break; 2855266911Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 2856266911Shiren ev = atom_silvermont_event_table; 2857266911Shiren count = PMC_EVENT_TABLE_SIZE(atom_silvermont); 2858266911Shiren break; 2859185363Sjkoshy case PMC_CPU_INTEL_CORE: 2860185363Sjkoshy ev = core_event_table; 2861185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2862185363Sjkoshy break; 2863185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2864185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2865185363Sjkoshy ev = core2_event_table; 2866185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2867185363Sjkoshy break; 2868187761Sjeff case PMC_CPU_INTEL_COREI7: 2869187761Sjeff ev = corei7_event_table; 2870187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2871187761Sjeff break; 2872267602Skib case PMC_CPU_INTEL_NEHALEM_EX: 2873267602Skib ev = nehalem_ex_event_table; 2874267602Skib count = PMC_EVENT_TABLE_SIZE(nehalem_ex); 2875267602Skib break; 2876248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2877248842Ssbruno ev = haswell_event_table; 2878248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswell); 2879248842Ssbruno break; 2880280455Srrs case PMC_CPU_INTEL_HASWELL_XEON: 2881280455Srrs ev = haswell_xeon_event_table; 2882280455Srrs count = PMC_EVENT_TABLE_SIZE(haswell_xeon); 2883280455Srrs break; 2884320113Savg case PMC_CPU_INTEL_BROADWELL: 2885320113Savg ev = broadwell_event_table; 2886320113Savg count = PMC_EVENT_TABLE_SIZE(broadwell); 2887320113Savg break; 2888320113Savg case PMC_CPU_INTEL_BROADWELL_XEON: 2889320113Savg ev = broadwell_xeon_event_table; 2890320113Savg count = PMC_EVENT_TABLE_SIZE(broadwell_xeon); 2891320113Savg break; 2892320113Savg case PMC_CPU_INTEL_SKYLAKE: 2893320113Savg ev = skylake_event_table; 2894320113Savg count = PMC_EVENT_TABLE_SIZE(skylake); 2895320113Savg break; 2896240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2897240164Sfabient ev = ivybridge_event_table; 2898240164Sfabient count = PMC_EVENT_TABLE_SIZE(ivybridge); 2899240164Sfabient break; 2900246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 2901246166Ssbruno ev = ivybridge_xeon_event_table; 2902246166Ssbruno count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 2903246166Ssbruno break; 2904232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2905232366Sdavide ev = sandybridge_event_table; 2906232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2907232366Sdavide break; 2908241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2909241738Ssbruno ev = sandybridge_xeon_event_table; 2910241738Ssbruno count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 2911241738Ssbruno break; 2912206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2913206089Sfabient ev = westmere_event_table; 2914206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2915206089Sfabient break; 2916267602Skib case PMC_CPU_INTEL_WESTMERE_EX: 2917267602Skib ev = westmere_ex_event_table; 2918267602Skib count = PMC_EVENT_TABLE_SIZE(westmere_ex); 2919267602Skib break; 2920185363Sjkoshy } 2921185363Sjkoshy break; 2922206089Sfabient case PMC_CLASS_UCF: 2923206089Sfabient ev = ucf_event_table; 2924206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2925206089Sfabient break; 2926206089Sfabient case PMC_CLASS_UCP: 2927206089Sfabient /* 2928206089Sfabient * Return the most appropriate set of event name 2929206089Sfabient * spellings for the current CPU. 2930206089Sfabient */ 2931206089Sfabient switch (cpu_info.pm_cputype) { 2932206089Sfabient default: 2933206089Sfabient case PMC_CPU_INTEL_COREI7: 2934206089Sfabient ev = corei7uc_event_table; 2935206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2936206089Sfabient break; 2937248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2938248842Ssbruno ev = haswelluc_event_table; 2939248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswelluc); 2940248842Ssbruno break; 2941320113Savg case PMC_CPU_INTEL_BROADWELL: 2942320113Savg ev = broadwelluc_event_table; 2943320113Savg count = PMC_EVENT_TABLE_SIZE(broadwelluc); 2944320113Savg break; 2945232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2946232366Sdavide ev = sandybridgeuc_event_table; 2947232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2948232366Sdavide break; 2949206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2950206089Sfabient ev = westmereuc_event_table; 2951206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2952206089Sfabient break; 2953206089Sfabient } 2954206089Sfabient break; 2955147191Sjkoshy case PMC_CLASS_TSC: 2956183725Sjkoshy ev = tsc_event_table; 2957183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2958145256Sjkoshy break; 2959147191Sjkoshy case PMC_CLASS_K7: 2960183725Sjkoshy ev = k7_event_table; 2961183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2962145256Sjkoshy break; 2963147191Sjkoshy case PMC_CLASS_K8: 2964183725Sjkoshy ev = k8_event_table; 2965183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2966145256Sjkoshy break; 2967183725Sjkoshy case PMC_CLASS_P4: 2968183725Sjkoshy ev = p4_event_table; 2969183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2970183725Sjkoshy break; 2971147191Sjkoshy case PMC_CLASS_P5: 2972183725Sjkoshy ev = p5_event_table; 2973183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2974145256Sjkoshy break; 2975147191Sjkoshy case PMC_CLASS_P6: 2976183725Sjkoshy ev = p6_event_table; 2977183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2978145256Sjkoshy break; 2979200928Srpaulo case PMC_CLASS_XSCALE: 2980200928Srpaulo ev = xscale_event_table; 2981200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2982200928Srpaulo break; 2983204635Sgnn case PMC_CLASS_MIPS24K: 2984204635Sgnn ev = mips24k_event_table; 2985204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2986204635Sgnn break; 2987233335Sgonzo case PMC_CLASS_OCTEON: 2988233335Sgonzo ev = octeon_event_table; 2989233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 2990233335Sgonzo break; 2991228869Sjhibbits case PMC_CLASS_PPC7450: 2992228869Sjhibbits ev = ppc7450_event_table; 2993228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2994228869Sjhibbits break; 2995263122Sjhibbits case PMC_CLASS_PPC970: 2996263122Sjhibbits ev = ppc970_event_table; 2997263122Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc970); 2998263122Sjhibbits break; 2999233628Sfabient case PMC_CLASS_SOFT: 3000233628Sfabient ev = soft_event_table; 3001233628Sfabient count = soft_event_info.pm_nevent; 3002233628Sfabient break; 3003145256Sjkoshy default: 3004147191Sjkoshy errno = EINVAL; 3005174406Sjkoshy return (-1); 3006145256Sjkoshy } 3007145256Sjkoshy 3008147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 3009174406Sjkoshy return (-1); 3010145256Sjkoshy 3011147191Sjkoshy *eventnames = names; 3012147191Sjkoshy *nevents = count; 3013145256Sjkoshy 3014147191Sjkoshy for (;count--; ev++, names++) 3015147191Sjkoshy *names = ev->pm_ev_name; 3016233628Sfabient 3017174406Sjkoshy return (0); 3018147191Sjkoshy} 3019145256Sjkoshy 3020147191Sjkoshyint 3021147191Sjkoshypmc_flush_logfile(void) 3022147191Sjkoshy{ 3023174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 3024147191Sjkoshy} 3025145256Sjkoshy 3026147191Sjkoshyint 3027226514Sfabientpmc_close_logfile(void) 3028226514Sfabient{ 3029226514Sfabient return (PMC_CALL(CLOSELOG,0)); 3030226514Sfabient} 3031226514Sfabient 3032226514Sfabientint 3033147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 3034147191Sjkoshy{ 3035147191Sjkoshy struct pmc_op_getdriverstats gms; 3036145256Sjkoshy 3037147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 3038174406Sjkoshy return (-1); 3039145256Sjkoshy 3040147191Sjkoshy /* copy out fields in the current userland<->library interface */ 3041147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 3042147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 3043147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 3044147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 3045147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 3046147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 3047147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 3048147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 3049174406Sjkoshy return (0); 3050147191Sjkoshy} 3051145256Sjkoshy 3052147191Sjkoshyint 3053147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 3054147191Sjkoshy{ 3055147191Sjkoshy struct pmc_op_getmsr gm; 3056147191Sjkoshy 3057147191Sjkoshy gm.pm_pmcid = pmc; 3058147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 3059174406Sjkoshy return (-1); 3060147191Sjkoshy *msr = gm.pm_msr; 3061174406Sjkoshy return (0); 3062145256Sjkoshy} 3063145256Sjkoshy 3064145256Sjkoshyint 3065145256Sjkoshypmc_init(void) 3066145256Sjkoshy{ 3067145256Sjkoshy int error, pmc_mod_id; 3068147219Sjkoshy unsigned int n; 3069145256Sjkoshy uint32_t abi_version; 3070145256Sjkoshy struct module_stat pmc_modstat; 3071147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 3072198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 3073198433Sjkoshy int cpu_has_iaf_counters; 3074198433Sjkoshy unsigned int t; 3075198433Sjkoshy#endif 3076145256Sjkoshy 3077145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 3078174406Sjkoshy return (0); 3079145256Sjkoshy 3080145256Sjkoshy /* retrieve the system call number from the KLD */ 3081145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 3082174406Sjkoshy return (-1); 3083145256Sjkoshy 3084145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 3085145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 3086174406Sjkoshy return (-1); 3087145256Sjkoshy 3088145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 3089145256Sjkoshy 3090147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 3091147191Sjkoshy abi_version = PMC_VERSION; 3092145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 3093145256Sjkoshy return (pmc_syscall = -1); 3094145256Sjkoshy 3095147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 3096147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 3097145256Sjkoshy errno = EPROGMISMATCH; 3098145256Sjkoshy return (pmc_syscall = -1); 3099145256Sjkoshy } 3100145256Sjkoshy 3101147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 3102145256Sjkoshy return (pmc_syscall = -1); 3103145256Sjkoshy 3104147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 3105147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 3106147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 3107147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 3108147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 3109147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 3110147219Sjkoshy 3111185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 3112185363Sjkoshy sizeof(struct pmc_class_descr *)); 3113185363Sjkoshy 3114185363Sjkoshy if (pmc_class_table == NULL) 3115185363Sjkoshy return (-1); 3116185363Sjkoshy 3117198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 3118198433Sjkoshy pmc_class_table[n] = NULL; 3119185363Sjkoshy 3120185363Sjkoshy /* 3121233628Sfabient * Get soft events list. 3122233628Sfabient */ 3123233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 3124233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 3125233628Sfabient return (pmc_syscall = -1); 3126233628Sfabient 3127233628Sfabient /* Map soft events to static list. */ 3128233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 3129233628Sfabient soft_event_table[n].pm_ev_name = 3130233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 3131233628Sfabient soft_event_table[n].pm_ev_code = 3132233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 3133233628Sfabient } 3134233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 3135233628Sfabient soft_event_info.pm_nevent; 3136233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 3137233628Sfabient soft_event_table; 3138233628Sfabient 3139233628Sfabient /* 3140185363Sjkoshy * Fill in the class table. 3141185363Sjkoshy */ 3142185363Sjkoshy n = 0; 3143233628Sfabient 3144233628Sfabient /* Fill soft events information. */ 3145233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 3146185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 3147233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 3148233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 3149198433Sjkoshy 3150198433Sjkoshy /* 3151198433Sjkoshy * Check if this CPU has fixed function counters. 3152198433Sjkoshy */ 3153198433Sjkoshy cpu_has_iaf_counters = 0; 3154198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 3155212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 3156212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 3157198433Sjkoshy cpu_has_iaf_counters = 1; 3158185363Sjkoshy#endif 3159185363Sjkoshy 3160183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 3161183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 3162183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 3163183725Sjkoshy pmc_mdep_class_list_size = \ 3164183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 3165183725Sjkoshy } while (0) 3166183725Sjkoshy 3167198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 3168198433Sjkoshy PMC_MDEP_INIT(C); \ 3169212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 3170212224Sfabient if (!cpu_has_iaf_counters) \ 3171198433Sjkoshy pmc_mdep_event_aliases = \ 3172198433Sjkoshy C##_aliases_without_iaf; \ 3173198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 3174198433Sjkoshy } while (0) 3175198433Sjkoshy 3176183725Sjkoshy /* Configure the event name parser. */ 3177145256Sjkoshy switch (cpu_info.pm_cputype) { 3178145340Smarcel#if defined(__i386__) 3179145256Sjkoshy case PMC_CPU_AMD_K7: 3180183725Sjkoshy PMC_MDEP_INIT(k7); 3181185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 3182145256Sjkoshy break; 3183145256Sjkoshy case PMC_CPU_INTEL_P5: 3184183725Sjkoshy PMC_MDEP_INIT(p5); 3185185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 3186145256Sjkoshy break; 3187145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 3188145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 3189145256Sjkoshy case PMC_CPU_INTEL_PIII: 3190145256Sjkoshy case PMC_CPU_INTEL_PM: 3191183725Sjkoshy PMC_MDEP_INIT(p6); 3192185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 3193145256Sjkoshy break; 3194147759Sjkoshy#endif 3195147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 3196183725Sjkoshy case PMC_CPU_AMD_K8: 3197183725Sjkoshy PMC_MDEP_INIT(k8); 3198185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 3199183725Sjkoshy break; 3200185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3201198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 3202185363Sjkoshy break; 3203266911Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3204266911Shiren PMC_MDEP_INIT_INTEL_V2(atom_silvermont); 3205266911Shiren break; 3206185363Sjkoshy case PMC_CPU_INTEL_CORE: 3207185363Sjkoshy PMC_MDEP_INIT(core); 3208202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 3209185363Sjkoshy break; 3210185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3211185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3212198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 3213185363Sjkoshy break; 3214187761Sjeff case PMC_CPU_INTEL_COREI7: 3215206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3216206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 3217198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 3218187761Sjeff break; 3219267602Skib case PMC_CPU_INTEL_NEHALEM_EX: 3220267602Skib PMC_MDEP_INIT_INTEL_V2(nehalem_ex); 3221267602Skib break; 3222248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3223248842Ssbruno pmc_class_table[n++] = &ucf_class_table_descr; 3224248842Ssbruno pmc_class_table[n++] = &haswelluc_class_table_descr; 3225248842Ssbruno PMC_MDEP_INIT_INTEL_V2(haswell); 3226248842Ssbruno break; 3227280455Srrs case PMC_CPU_INTEL_HASWELL_XEON: 3228280455Srrs PMC_MDEP_INIT_INTEL_V2(haswell_xeon); 3229280455Srrs break; 3230320113Savg case PMC_CPU_INTEL_BROADWELL: 3231320113Savg pmc_class_table[n++] = &ucf_class_table_descr; 3232320113Savg pmc_class_table[n++] = &broadwelluc_class_table_descr; 3233320113Savg PMC_MDEP_INIT_INTEL_V2(broadwell); 3234320113Savg break; 3235320113Savg case PMC_CPU_INTEL_BROADWELL_XEON: 3236320113Savg PMC_MDEP_INIT_INTEL_V2(broadwell_xeon); 3237320113Savg break; 3238320113Savg case PMC_CPU_INTEL_SKYLAKE: 3239320113Savg PMC_MDEP_INIT_INTEL_V2(skylake); 3240320113Savg break; 3241240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3242240164Sfabient PMC_MDEP_INIT_INTEL_V2(ivybridge); 3243240164Sfabient break; 3244246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3245246166Ssbruno PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon); 3246246166Ssbruno break; 3247232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3248232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 3249232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 3250232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 3251232366Sdavide break; 3252241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3253241738Ssbruno PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); 3254241738Ssbruno break; 3255206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3256206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3257206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 3258206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 3259206089Sfabient break; 3260267602Skib case PMC_CPU_INTEL_WESTMERE_EX: 3261267602Skib PMC_MDEP_INIT_INTEL_V2(westmere_ex); 3262267602Skib break; 3263145256Sjkoshy case PMC_CPU_INTEL_PIV: 3264183725Sjkoshy PMC_MDEP_INIT(p4); 3265185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 3266145256Sjkoshy break; 3267145256Sjkoshy#endif 3268233628Sfabient case PMC_CPU_GENERIC: 3269233628Sfabient PMC_MDEP_INIT(generic); 3270233628Sfabient break; 3271200928Srpaulo#if defined(__XSCALE__) 3272200928Srpaulo case PMC_CPU_INTEL_XSCALE: 3273200928Srpaulo PMC_MDEP_INIT(xscale); 3274200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 3275200928Srpaulo break; 3276200928Srpaulo#endif 3277204635Sgnn#if defined(__mips__) 3278204635Sgnn case PMC_CPU_MIPS_24K: 3279204635Sgnn PMC_MDEP_INIT(mips24k); 3280204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 3281204635Sgnn break; 3282233335Sgonzo case PMC_CPU_MIPS_OCTEON: 3283233335Sgonzo PMC_MDEP_INIT(octeon); 3284233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 3285233335Sgonzo break; 3286204635Sgnn#endif /* __mips__ */ 3287228869Sjhibbits#if defined(__powerpc__) 3288228869Sjhibbits case PMC_CPU_PPC_7450: 3289228869Sjhibbits PMC_MDEP_INIT(ppc7450); 3290228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 3291228869Sjhibbits break; 3292263122Sjhibbits case PMC_CPU_PPC_970: 3293263122Sjhibbits PMC_MDEP_INIT(ppc970); 3294263122Sjhibbits pmc_class_table[n] = &ppc970_class_table_descr; 3295263122Sjhibbits break; 3296228869Sjhibbits#endif 3297145256Sjkoshy default: 3298145256Sjkoshy /* 3299145256Sjkoshy * Some kind of CPU this version of the library knows nothing 3300145256Sjkoshy * about. This shouldn't happen since the abi version check 3301145256Sjkoshy * should have caught this. 3302145256Sjkoshy */ 3303145256Sjkoshy errno = ENXIO; 3304145256Sjkoshy return (pmc_syscall = -1); 3305145256Sjkoshy } 3306145256Sjkoshy 3307174406Sjkoshy return (0); 3308145256Sjkoshy} 3309145256Sjkoshy 3310147191Sjkoshyconst char * 3311147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 3312145256Sjkoshy{ 3313147191Sjkoshy int i; 3314145256Sjkoshy 3315147191Sjkoshy /* 3316147191Sjkoshy * 'cap' should have a single bit set and should be in 3317147191Sjkoshy * range. 3318147191Sjkoshy */ 3319147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 3320147191Sjkoshy cap > PMC_CAP_LAST) { 3321145256Sjkoshy errno = EINVAL; 3322174406Sjkoshy return (NULL); 3323145256Sjkoshy } 3324145256Sjkoshy 3325147191Sjkoshy i = ffs(cap); 3326174406Sjkoshy return (pmc_capability_names[i - 1]); 3327147191Sjkoshy} 3328145256Sjkoshy 3329147191Sjkoshyconst char * 3330147191Sjkoshypmc_name_of_class(enum pmc_class pc) 3331147191Sjkoshy{ 3332147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 3333147191Sjkoshy pc <= PMC_CLASS_LAST) 3334174406Sjkoshy return (pmc_class_names[pc]); 3335145256Sjkoshy 3336147191Sjkoshy errno = EINVAL; 3337174406Sjkoshy return (NULL); 3338147191Sjkoshy} 3339145256Sjkoshy 3340147191Sjkoshyconst char * 3341147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3342147191Sjkoshy{ 3343183725Sjkoshy size_t n; 3344183725Sjkoshy 3345183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3346183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3347183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3348183725Sjkoshy 3349147191Sjkoshy errno = EINVAL; 3350174406Sjkoshy return (NULL); 3351147191Sjkoshy} 3352145256Sjkoshy 3353147191Sjkoshyconst char * 3354147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3355147191Sjkoshy{ 3356147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3357147191Sjkoshy pd <= PMC_DISP_LAST) 3358174406Sjkoshy return (pmc_disposition_names[pd]); 3359145256Sjkoshy 3360147191Sjkoshy errno = EINVAL; 3361174406Sjkoshy return (NULL); 3362147191Sjkoshy} 3363145256Sjkoshy 3364147191Sjkoshyconst char * 3365185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3366147191Sjkoshy{ 3367183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3368145256Sjkoshy 3369183725Sjkoshy ev = evfence = NULL; 3370185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3371185363Sjkoshy ev = iaf_event_table; 3372185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3373185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3374185363Sjkoshy switch (cpu) { 3375185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3376185363Sjkoshy ev = atom_event_table; 3377185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3378185363Sjkoshy break; 3379266911Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3380266911Shiren ev = atom_silvermont_event_table; 3381266911Shiren evfence = atom_silvermont_event_table + 3382266911Shiren PMC_EVENT_TABLE_SIZE(atom_silvermont); 3383266911Shiren break; 3384185363Sjkoshy case PMC_CPU_INTEL_CORE: 3385185363Sjkoshy ev = core_event_table; 3386185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3387185363Sjkoshy break; 3388185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3389185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3390185363Sjkoshy ev = core2_event_table; 3391185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3392185363Sjkoshy break; 3393187761Sjeff case PMC_CPU_INTEL_COREI7: 3394187761Sjeff ev = corei7_event_table; 3395187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3396187761Sjeff break; 3397267602Skib case PMC_CPU_INTEL_NEHALEM_EX: 3398267602Skib ev = nehalem_ex_event_table; 3399267602Skib evfence = nehalem_ex_event_table + 3400267602Skib PMC_EVENT_TABLE_SIZE(nehalem_ex); 3401267602Skib break; 3402248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3403248842Ssbruno ev = haswell_event_table; 3404248842Ssbruno evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell); 3405248842Ssbruno break; 3406280455Srrs case PMC_CPU_INTEL_HASWELL_XEON: 3407280455Srrs ev = haswell_xeon_event_table; 3408280455Srrs evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon); 3409280455Srrs break; 3410320113Savg case PMC_CPU_INTEL_BROADWELL: 3411320113Savg ev = broadwell_event_table; 3412320113Savg evfence = broadwell_event_table + PMC_EVENT_TABLE_SIZE(broadwell); 3413320113Savg break; 3414320113Savg case PMC_CPU_INTEL_BROADWELL_XEON: 3415320113Savg ev = broadwell_xeon_event_table; 3416320113Savg evfence = broadwell_xeon_event_table + PMC_EVENT_TABLE_SIZE(broadwell_xeon); 3417320113Savg break; 3418320113Savg case PMC_CPU_INTEL_SKYLAKE: 3419320113Savg ev = skylake_event_table; 3420320113Savg evfence = skylake_event_table + PMC_EVENT_TABLE_SIZE(skylake); 3421320113Savg break; 3422240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3423240164Sfabient ev = ivybridge_event_table; 3424240164Sfabient evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); 3425240164Sfabient break; 3426246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3427246166Ssbruno ev = ivybridge_xeon_event_table; 3428246166Ssbruno evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 3429246166Ssbruno break; 3430232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3431232366Sdavide ev = sandybridge_event_table; 3432232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3433232366Sdavide break; 3434241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3435241738Ssbruno ev = sandybridge_xeon_event_table; 3436241738Ssbruno evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 3437241738Ssbruno break; 3438206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3439206089Sfabient ev = westmere_event_table; 3440206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3441206089Sfabient break; 3442267602Skib case PMC_CPU_INTEL_WESTMERE_EX: 3443267602Skib ev = westmere_ex_event_table; 3444267602Skib evfence = westmere_ex_event_table + 3445267602Skib PMC_EVENT_TABLE_SIZE(westmere_ex); 3446267602Skib break; 3447185363Sjkoshy default: /* Unknown CPU type. */ 3448185363Sjkoshy break; 3449185363Sjkoshy } 3450206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3451206089Sfabient ev = ucf_event_table; 3452206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3453206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3454206089Sfabient switch (cpu) { 3455206089Sfabient case PMC_CPU_INTEL_COREI7: 3456206089Sfabient ev = corei7uc_event_table; 3457206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3458206089Sfabient break; 3459232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3460232366Sdavide ev = sandybridgeuc_event_table; 3461232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3462232366Sdavide break; 3463206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3464206089Sfabient ev = westmereuc_event_table; 3465206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3466206089Sfabient break; 3467206089Sfabient default: /* Unknown CPU type. */ 3468206089Sfabient break; 3469206089Sfabient } 3470206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3471183725Sjkoshy ev = k7_event_table; 3472183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3473183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3474183725Sjkoshy ev = k8_event_table; 3475183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3476183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3477183725Sjkoshy ev = p4_event_table; 3478183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3479183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3480183725Sjkoshy ev = p5_event_table; 3481183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3482183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3483183725Sjkoshy ev = p6_event_table; 3484183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3485200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3486200928Srpaulo ev = xscale_event_table; 3487200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3488204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3489204635Sgnn ev = mips24k_event_table; 3490233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3491233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3492233335Sgonzo ev = octeon_event_table; 3493233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3494228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3495228869Sjhibbits ev = ppc7450_event_table; 3496233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3497263122Sjhibbits } else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) { 3498263122Sjhibbits ev = ppc970_event_table; 3499263122Sjhibbits evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970); 3500183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3501183725Sjkoshy ev = tsc_event_table; 3502183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3503242622Sdim } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { 3504233628Sfabient ev = soft_event_table; 3505233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3506183725Sjkoshy } 3507183725Sjkoshy 3508183725Sjkoshy for (; ev != evfence; ev++) 3509183725Sjkoshy if (pe == ev->pm_ev_code) 3510183725Sjkoshy return (ev->pm_ev_name); 3511183725Sjkoshy 3512185363Sjkoshy return (NULL); 3513185363Sjkoshy} 3514185363Sjkoshy 3515185363Sjkoshyconst char * 3516185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3517185363Sjkoshy{ 3518185363Sjkoshy const char *n; 3519185363Sjkoshy 3520185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3521185363Sjkoshy return (n); 3522185363Sjkoshy 3523147191Sjkoshy errno = EINVAL; 3524174406Sjkoshy return (NULL); 3525147191Sjkoshy} 3526145256Sjkoshy 3527147191Sjkoshyconst char * 3528147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3529147191Sjkoshy{ 3530147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3531147191Sjkoshy pm <= PMC_MODE_LAST) 3532174406Sjkoshy return (pmc_mode_names[pm]); 3533145256Sjkoshy 3534147191Sjkoshy errno = EINVAL; 3535174406Sjkoshy return (NULL); 3536147191Sjkoshy} 3537145256Sjkoshy 3538147191Sjkoshyconst char * 3539147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3540147191Sjkoshy{ 3541147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3542147191Sjkoshy ps <= PMC_STATE_LAST) 3543174406Sjkoshy return (pmc_state_names[ps]); 3544145256Sjkoshy 3545147191Sjkoshy errno = EINVAL; 3546174406Sjkoshy return (NULL); 3547145256Sjkoshy} 3548145256Sjkoshy 3549145256Sjkoshyint 3550147191Sjkoshypmc_ncpu(void) 3551145256Sjkoshy{ 3552147191Sjkoshy if (pmc_syscall == -1) { 3553147191Sjkoshy errno = ENXIO; 3554174406Sjkoshy return (-1); 3555147191Sjkoshy } 3556145256Sjkoshy 3557174406Sjkoshy return (cpu_info.pm_ncpu); 3558145256Sjkoshy} 3559145256Sjkoshy 3560145256Sjkoshyint 3561147191Sjkoshypmc_npmc(int cpu) 3562145256Sjkoshy{ 3563147191Sjkoshy if (pmc_syscall == -1) { 3564147191Sjkoshy errno = ENXIO; 3565174406Sjkoshy return (-1); 3566147191Sjkoshy } 3567145256Sjkoshy 3568147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3569147191Sjkoshy errno = EINVAL; 3570174406Sjkoshy return (-1); 3571147191Sjkoshy } 3572145256Sjkoshy 3573174406Sjkoshy return (cpu_info.pm_npmc); 3574145256Sjkoshy} 3575145256Sjkoshy 3576145256Sjkoshyint 3577147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3578145256Sjkoshy{ 3579147191Sjkoshy int nbytes, npmc; 3580147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3581145256Sjkoshy 3582147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3583174406Sjkoshy return (-1); 3584145256Sjkoshy 3585147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3586147191Sjkoshy npmc * sizeof(struct pmc_info); 3587145256Sjkoshy 3588147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3589174406Sjkoshy return (-1); 3590145256Sjkoshy 3591147191Sjkoshy pmci->pm_cpu = cpu; 3592145256Sjkoshy 3593147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3594147191Sjkoshy free(pmci); 3595174406Sjkoshy return (-1); 3596147191Sjkoshy } 3597145256Sjkoshy 3598147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3599147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3600174406Sjkoshy return (0); 3601145256Sjkoshy} 3602145256Sjkoshy 3603145256Sjkoshyint 3604145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3605145256Sjkoshy{ 3606145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3607145256Sjkoshy 3608145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3609145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3610145256Sjkoshy pmc_read_op.pm_value = -1; 3611145256Sjkoshy 3612145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3613174406Sjkoshy return (-1); 3614145256Sjkoshy 3615145256Sjkoshy *value = pmc_read_op.pm_value; 3616174406Sjkoshy return (0); 3617145256Sjkoshy} 3618145256Sjkoshy 3619145256Sjkoshyint 3620147191Sjkoshypmc_release(pmc_id_t pmc) 3621145256Sjkoshy{ 3622147191Sjkoshy struct pmc_op_simple pmc_release_args; 3623145256Sjkoshy 3624147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3625174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3626145256Sjkoshy} 3627145256Sjkoshy 3628145256Sjkoshyint 3629145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3630145256Sjkoshy{ 3631145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3632145256Sjkoshy 3633145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3634145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3635145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3636145256Sjkoshy 3637145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3638174406Sjkoshy return (-1); 3639145256Sjkoshy 3640145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3641174406Sjkoshy return (0); 3642145256Sjkoshy} 3643145256Sjkoshy 3644145256Sjkoshyint 3645145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3646145256Sjkoshy{ 3647145256Sjkoshy struct pmc_op_pmcsetcount sc; 3648145256Sjkoshy 3649145256Sjkoshy sc.pm_pmcid = pmc; 3650145256Sjkoshy sc.pm_count = value; 3651145256Sjkoshy 3652145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3653174406Sjkoshy return (-1); 3654174406Sjkoshy return (0); 3655145256Sjkoshy} 3656145256Sjkoshy 3657145256Sjkoshyint 3658147191Sjkoshypmc_start(pmc_id_t pmc) 3659145256Sjkoshy{ 3660147191Sjkoshy struct pmc_op_simple pmc_start_args; 3661145256Sjkoshy 3662147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3663174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3664145256Sjkoshy} 3665145256Sjkoshy 3666145256Sjkoshyint 3667147191Sjkoshypmc_stop(pmc_id_t pmc) 3668145256Sjkoshy{ 3669147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3670145256Sjkoshy 3671147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3672174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3673145256Sjkoshy} 3674145256Sjkoshy 3675145256Sjkoshyint 3676145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3677145774Sjkoshy{ 3678145774Sjkoshy unsigned int i; 3679145774Sjkoshy enum pmc_class cl; 3680145774Sjkoshy 3681145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3682145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3683145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3684145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3685174406Sjkoshy return (0); 3686145774Sjkoshy } 3687177107Sjkoshy errno = EINVAL; 3688177107Sjkoshy return (-1); 3689145774Sjkoshy} 3690145774Sjkoshy 3691145774Sjkoshyint 3692147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3693145774Sjkoshy{ 3694147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3695145774Sjkoshy 3696147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3697147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3698147191Sjkoshy pmc_write_op.pm_value = value; 3699174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3700145256Sjkoshy} 3701145256Sjkoshy 3702145256Sjkoshyint 3703147191Sjkoshypmc_writelog(uint32_t userdata) 3704145256Sjkoshy{ 3705147191Sjkoshy struct pmc_op_writelog wl; 3706145256Sjkoshy 3707147191Sjkoshy wl.pm_userdata = userdata; 3708174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3709145256Sjkoshy} 3710