opteron_pcbe.c (b885580b) | opteron_pcbe.c (d0e58ef5) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 51 unchanged lines hidden (view full) --- 60 * POSSIBILITY OF SUCH DAMAGE. 61 * 62 * 63 * This open source software license conforms to the BSD License template. 64 */ 65 66/* 67 * Portions Copyright 2009 Advanced Micro Devices, Inc. | 1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 51 unchanged lines hidden (view full) --- 60 * POSSIBILITY OF SUCH DAMAGE. 61 * 62 * 63 * This open source software license conforms to the BSD License template. 64 */ 65 66/* 67 * Portions Copyright 2009 Advanced Micro Devices, Inc. |
68 * Copyright 2019 Joyent, Inc. |
|
68 */ 69 70/* 71 * Performance Counter Back-End for AMD Opteron and AMD Athlon 64 processors. 72 */ 73 74#include <sys/cpuvar.h> 75#include <sys/param.h> --- 5 unchanged lines hidden (view full) --- 81#include <sys/errno.h> 82#include <sys/debug.h> 83#include <sys/archsystm.h> 84#include <sys/x86_archext.h> 85#include <sys/privregs.h> 86#include <sys/ddi.h> 87#include <sys/sunddi.h> 88 | 69 */ 70 71/* 72 * Performance Counter Back-End for AMD Opteron and AMD Athlon 64 processors. 73 */ 74 75#include <sys/cpuvar.h> 76#include <sys/param.h> --- 5 unchanged lines hidden (view full) --- 82#include <sys/errno.h> 83#include <sys/debug.h> 84#include <sys/archsystm.h> 85#include <sys/x86_archext.h> 86#include <sys/privregs.h> 87#include <sys/ddi.h> 88#include <sys/sunddi.h> 89 |
90#include "opteron_pcbe_table.h" 91#include <opteron_pcbe_cpcgen.h> 92 |
|
89static int opt_pcbe_init(void); 90static uint_t opt_pcbe_ncounters(void); 91static const char *opt_pcbe_impl_name(void); 92static const char *opt_pcbe_cpuref(void); 93static char *opt_pcbe_list_events(uint_t picnum); 94static char *opt_pcbe_list_attrs(void); 95static uint64_t opt_pcbe_event_coverage(char *event); 96static uint64_t opt_pcbe_overflow_bitmap(void); --- 18 unchanged lines hidden (view full) --- 115 opt_pcbe_configure, 116 opt_pcbe_program, 117 opt_pcbe_allstop, 118 opt_pcbe_sample, 119 opt_pcbe_free 120}; 121 122/* | 93static int opt_pcbe_init(void); 94static uint_t opt_pcbe_ncounters(void); 95static const char *opt_pcbe_impl_name(void); 96static const char *opt_pcbe_cpuref(void); 97static char *opt_pcbe_list_events(uint_t picnum); 98static char *opt_pcbe_list_attrs(void); 99static uint64_t opt_pcbe_event_coverage(char *event); 100static uint64_t opt_pcbe_overflow_bitmap(void); --- 18 unchanged lines hidden (view full) --- 119 opt_pcbe_configure, 120 opt_pcbe_program, 121 opt_pcbe_allstop, 122 opt_pcbe_sample, 123 opt_pcbe_free 124}; 125 126/* |
127 * Base MSR addresses for the PerfEvtSel registers and the counters themselves. 128 * Add counter number to base address to get corresponding MSR address. 129 */ 130#define PES_BASE_ADDR 0xC0010000 131#define PIC_BASE_ADDR 0xC0010004 132 133/* 134 * Base MSR addresses for the PerfEvtSel registers and counters. The counter and 135 * event select registers are interleaved, so one needs to multiply the counter 136 * number by two to determine what they should be set to. 137 */ 138#define PES_EXT_BASE_ADDR 0xC0010200 139#define PIC_EXT_BASE_ADDR 0xC0010201 140 141/* 142 * The number of counters present depends on which CPU features are present. 143 */ 144#define OPT_PCBE_DEF_NCOUNTERS 4 145#define OPT_PCBE_EXT_NCOUNTERS 6 146 147/* |
|
123 * Define offsets and masks for the fields in the Performance 124 * Event-Select (PES) registers. 125 */ 126#define OPT_PES_HOST_SHIFT 41 127#define OPT_PES_GUEST_SHIFT 40 | 148 * Define offsets and masks for the fields in the Performance 149 * Event-Select (PES) registers. 150 */ 151#define OPT_PES_HOST_SHIFT 41 152#define OPT_PES_GUEST_SHIFT 40 |
153#define OPT_PES_EVSELHI_SHIFT 32 |
|
128#define OPT_PES_CMASK_SHIFT 24 129#define OPT_PES_CMASK_MASK 0xFF 130#define OPT_PES_INV_SHIFT 23 131#define OPT_PES_ENABLE_SHIFT 22 132#define OPT_PES_INT_SHIFT 20 133#define OPT_PES_PC_SHIFT 19 134#define OPT_PES_EDGE_SHIFT 18 135#define OPT_PES_OS_SHIFT 17 --- 12 unchanged lines hidden (view full) --- 148#define OPT_PES_GUEST (1ULL << OPT_PES_GUEST_SHIFT) 149 150typedef struct _opt_pcbe_config { 151 uint8_t opt_picno; /* Counter number: 0, 1, 2, or 3 */ 152 uint64_t opt_evsel; /* Event Selection register */ 153 uint64_t opt_rawpic; /* Raw counter value */ 154} opt_pcbe_config_t; 155 | 154#define OPT_PES_CMASK_SHIFT 24 155#define OPT_PES_CMASK_MASK 0xFF 156#define OPT_PES_INV_SHIFT 23 157#define OPT_PES_ENABLE_SHIFT 22 158#define OPT_PES_INT_SHIFT 20 159#define OPT_PES_PC_SHIFT 19 160#define OPT_PES_EDGE_SHIFT 18 161#define OPT_PES_OS_SHIFT 17 --- 12 unchanged lines hidden (view full) --- 174#define OPT_PES_GUEST (1ULL << OPT_PES_GUEST_SHIFT) 175 176typedef struct _opt_pcbe_config { 177 uint8_t opt_picno; /* Counter number: 0, 1, 2, or 3 */ 178 uint64_t opt_evsel; /* Event Selection register */ 179 uint64_t opt_rawpic; /* Raw counter value */ 180} opt_pcbe_config_t; 181 |
156opt_pcbe_config_t nullcfgs[4] = { | 182opt_pcbe_config_t nullcfgs[OPT_PCBE_EXT_NCOUNTERS] = { |
157 { 0, 0, 0 }, 158 { 1, 0, 0 }, 159 { 2, 0, 0 }, | 183 { 0, 0, 0 }, 184 { 1, 0, 0 }, 185 { 2, 0, 0 }, |
160 { 3, 0, 0 } | 186 { 3, 0, 0 }, 187 { 4, 0, 0 }, 188 { 5, 0, 0 }, |
161}; 162 | 189}; 190 |
163typedef struct _amd_event { 164 char *name; 165 uint16_t emask; /* Event mask setting */ 166} amd_event_t; | 191typedef uint64_t (*opt_pcbe_addr_f)(uint_t); |
167 | 192 |
168typedef struct _amd_generic_event { 169 char *name; 170 char *event; 171 uint8_t umask; 172} amd_generic_event_t; | 193typedef struct opt_pcbe_data { 194 uint_t opd_ncounters; 195 uint_t opd_cmask; 196 opt_pcbe_addr_f opd_pesf; 197 opt_pcbe_addr_f opd_picf; 198} opt_pcbe_data_t; |
173 | 199 |
174/* 175 * Base MSR addresses for the PerfEvtSel registers and the counters themselves. 176 * Add counter number to base address to get corresponding MSR address. 177 */ 178#define PES_BASE_ADDR 0xC0010000 179#define PIC_BASE_ADDR 0xC0010004 | 200opt_pcbe_data_t opd; |
180 181#define MASK48 0xFFFFFFFFFFFF 182 183#define EV_END {NULL, 0} 184#define GEN_EV_END {NULL, NULL, 0 } 185 | 201 202#define MASK48 0xFFFFFFFFFFFF 203 204#define EV_END {NULL, 0} 205#define GEN_EV_END {NULL, NULL, 0 } 206 |
207/* 208 * The following Macros are used to define tables of events that are used by 209 * various families and some generic classes of events. 210 * 211 * When programming a performance counter there are two different values that we 212 * need to set: 213 * 214 * o Event - Determines the general class of event that is being used. 215 * o Unit - A further breakdown that gives more specific value. 216 * 217 * Prior to the introduction of family 17h support, all family specific events 218 * were programmed based on their event. The generic events, which tried to 219 * provide PAPI mappings to events specified an additional unit mask. 220 * 221 * Starting with Family 17h, CPU performance counters default to using both the 222 * unit mask and the event select. Generic events are always aliases to a 223 * specific event/unit pair, hence why the units for them are always zero. In 224 * addition, the naming of events in family 17h has been changed to reflect 225 * AMD's guide. While this is a departure from what people are used to, it is 226 * believed that matching the more detailed literature that folks are told to 227 * reference is more valuable. 228 */ 229 |
|
186#define AMD_cmn_events \ 187 { "FP_dispatched_fpu_ops", 0x0 }, \ 188 { "FP_cycles_no_fpu_ops_retired", 0x1 }, \ 189 { "FP_dispatched_fpu_ops_ff", 0x2 }, \ 190 { "LS_seg_reg_load", 0x20 }, \ 191 { "LS_uarch_resync_self_modify", 0x21 }, \ 192 { "LS_uarch_resync_snoop", 0x22 }, \ 193 { "LS_buffer_2_full", 0x23 }, \ --- 173 unchanged lines hidden (view full) --- 367 { "PAPI_tlb_im", "IC_itlb_L1_miss_L2_miss", 0x3 }, \ 368 { "PAPI_l3_dcr", "L3_read_req", 0xf1 }, \ 369 { "PAPI_l3_icr", "L3_read_req", 0xf2 }, \ 370 { "PAPI_l3_tcr", "L3_read_req", 0xf7 }, \ 371 { "PAPI_l3_stm", "L3_miss", 0xf4 }, \ 372 { "PAPI_l3_ldm", "L3_miss", 0xf3 }, \ 373 { "PAPI_l3_tcm", "L3_miss", 0xf7 } 374 | 230#define AMD_cmn_events \ 231 { "FP_dispatched_fpu_ops", 0x0 }, \ 232 { "FP_cycles_no_fpu_ops_retired", 0x1 }, \ 233 { "FP_dispatched_fpu_ops_ff", 0x2 }, \ 234 { "LS_seg_reg_load", 0x20 }, \ 235 { "LS_uarch_resync_self_modify", 0x21 }, \ 236 { "LS_uarch_resync_snoop", 0x22 }, \ 237 { "LS_buffer_2_full", 0x23 }, \ --- 173 unchanged lines hidden (view full) --- 411 { "PAPI_tlb_im", "IC_itlb_L1_miss_L2_miss", 0x3 }, \ 412 { "PAPI_l3_dcr", "L3_read_req", 0xf1 }, \ 413 { "PAPI_l3_icr", "L3_read_req", 0xf2 }, \ 414 { "PAPI_l3_tcr", "L3_read_req", 0xf7 }, \ 415 { "PAPI_l3_stm", "L3_miss", 0xf4 }, \ 416 { "PAPI_l3_ldm", "L3_miss", 0xf3 }, \ 417 { "PAPI_l3_tcm", "L3_miss", 0xf7 } 418 |
375#define AMD_PCBE_SUPPORTED(family) (((family) >= 0xf) && ((family) <= 0x11)) 376 377static amd_event_t family_f_events[] = { | 419static const amd_event_t family_f_events[] = { |
378 AMD_cmn_events, 379 AMD_FAMILY_f_events, 380 EV_END 381}; 382 | 420 AMD_cmn_events, 421 AMD_FAMILY_f_events, 422 EV_END 423}; 424 |
383static amd_event_t family_10h_events[] = { | 425static const amd_event_t family_10h_events[] = { |
384 AMD_cmn_events, 385 AMD_FAMILY_10h_events, 386 EV_END 387}; 388 | 426 AMD_cmn_events, 427 AMD_FAMILY_10h_events, 428 EV_END 429}; 430 |
389static amd_event_t family_11h_events[] = { | 431static const amd_event_t family_11h_events[] = { |
390 AMD_cmn_events, 391 AMD_FAMILY_11h_events, 392 EV_END 393}; 394 | 432 AMD_cmn_events, 433 AMD_FAMILY_11h_events, 434 EV_END 435}; 436 |
395static amd_generic_event_t opt_generic_events[] = { | 437static const amd_generic_event_t opt_generic_events[] = { |
396 AMD_cmn_generic_events, 397 OPT_cmn_generic_events, 398 GEN_EV_END 399}; 400 | 438 AMD_cmn_generic_events, 439 OPT_cmn_generic_events, 440 GEN_EV_END 441}; 442 |
401static amd_generic_event_t family_10h_generic_events[] = { | 443static const amd_generic_event_t family_10h_generic_events[] = { |
402 AMD_cmn_generic_events, 403 AMD_FAMILY_10h_generic_events, 404 GEN_EV_END 405}; 406 | 444 AMD_cmn_generic_events, 445 AMD_FAMILY_10h_generic_events, 446 GEN_EV_END 447}; 448 |
449/* 450 * For Family 17h, the cpcgen utility generates all of our events including ones 451 * that need specific unit codes, therefore we leave all unit codes out of 452 * these. 453 */ 454static const amd_generic_event_t family_17h_papi_events[] = { 455 { "PAPI_br_cn", "ExRetCond" }, 456 { "PAPI_br_ins", "ExRetBrnMis" }, 457 { "PAPI_fpu_idl", "FpSchedEmpty" }, 458 { "PAPI_tot_cyc", "LsNotHaltedCyc" }, 459 { "PAPI_tot_ins", "ExRetInstr" }, 460 { "PAPI_tlb_dm", "LsL1DTlbMiss" }, 461 { "PAPI_tlb_im", "BpL1TlbMissL2Miss" }, 462 { "PAPI_tot_cyc", "LsNotHaltedCyc" }, 463 GEN_EV_END 464}; 465 |
|
407static char *evlist; 408static size_t evlist_sz; | 466static char *evlist; 467static size_t evlist_sz; |
409static amd_event_t *amd_events = NULL; 410static uint_t amd_family; 411static amd_generic_event_t *amd_generic_events = NULL; | 468static const amd_event_t *amd_events = NULL; 469static uint_t amd_family, amd_model; 470static const amd_generic_event_t *amd_generic_events = NULL; |
412 | 471 |
413#define AMD_CPUREF_SIZE 256 414static char amd_generic_bkdg[AMD_CPUREF_SIZE]; 415static char amd_fam_f_rev_ae_bkdg[] = "See \"BIOS and Kernel Developer's " \ | 472static char amd_fam_f_rev_ae_bkdg[] = "See \"BIOS and Kernel Developer's " |
416"Guide for AMD Athlon 64 and AMD Opteron Processors\" (AMD publication 26094)"; | 473"Guide for AMD Athlon 64 and AMD Opteron Processors\" (AMD publication 26094)"; |
417static char amd_fam_f_NPT_bkdg[] = "See \"BIOS and Kernel Developer's Guide " \ | 474static char amd_fam_f_NPT_bkdg[] = "See \"BIOS and Kernel Developer's Guide " |
418"for AMD NPT Family 0Fh Processors\" (AMD publication 32559)"; | 475"for AMD NPT Family 0Fh Processors\" (AMD publication 32559)"; |
419static char amd_fam_10h_bkdg[] = "See \"BIOS and Kernel Developer's Guide " \ | 476static char amd_fam_10h_bkdg[] = "See \"BIOS and Kernel Developer's Guide " |
420"(BKDG) For AMD Family 10h Processors\" (AMD publication 31116)"; | 477"(BKDG) For AMD Family 10h Processors\" (AMD publication 31116)"; |
421static char amd_fam_11h_bkdg[] = "See \"BIOS and Kernel Developer's Guide " \ | 478static char amd_fam_11h_bkdg[] = "See \"BIOS and Kernel Developer's Guide " |
422"(BKDG) For AMD Family 11h Processors\" (AMD publication 41256)"; | 479"(BKDG) For AMD Family 11h Processors\" (AMD publication 41256)"; |
480static char amd_fam_17h_reg[] = "See \"Open-Source Register Reference For " 481"AMD Family 17h Processors Models 00h-2Fh\" (AMD publication 56255) and " 482"amd_f17h_events(3CPC)"; |
|
423 424static char amd_pcbe_impl_name[64]; 425static char *amd_pcbe_cpuref; 426 427 428#define BITS(v, u, l) \ 429 (((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1)) 430 | 483 484static char amd_pcbe_impl_name[64]; 485static char *amd_pcbe_cpuref; 486 487 488#define BITS(v, u, l) \ 489 (((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1)) 490 |
491static uint64_t 492opt_pcbe_pes_addr(uint_t counter) 493{ 494 ASSERT3U(counter, <, opd.opd_ncounters); 495 return (PES_BASE_ADDR + counter); 496} |
|
431 | 497 |
498static uint64_t 499opt_pcbe_pes_ext_addr(uint_t counter) 500{ 501 ASSERT3U(counter, <, opd.opd_ncounters); 502 return (PES_EXT_BASE_ADDR + 2 * counter); 503} 504 505static uint64_t 506opt_pcbe_pic_addr(uint_t counter) 507{ 508 ASSERT3U(counter, <, opd.opd_ncounters); 509 return (PIC_BASE_ADDR + 2 * counter); 510} 511 512static uint64_t 513opt_pcbe_pic_ext_addr(uint_t counter) 514{ 515 ASSERT3U(counter, <, opd.opd_ncounters); 516 return (PIC_EXT_BASE_ADDR + 2 * counter); 517} 518 |
|
432static int 433opt_pcbe_init(void) 434{ | 519static int 520opt_pcbe_init(void) 521{ |
435 amd_event_t *evp; 436 amd_generic_event_t *gevp; | 522 const amd_event_t *evp; 523 const amd_generic_event_t *gevp; |
437 438 amd_family = cpuid_getfamily(CPU); | 524 525 amd_family = cpuid_getfamily(CPU); |
526 amd_model = cpuid_getmodel(CPU); |
|
439 440 /* 441 * Make sure this really _is_ an Opteron or Athlon 64 system. The kernel 442 * loads this module based on its name in the module directory, but it 443 * could have been renamed. 444 */ 445 if (cpuid_getvendor(CPU) != X86_VENDOR_AMD || amd_family < 0xf) 446 return (-1); 447 | 527 528 /* 529 * Make sure this really _is_ an Opteron or Athlon 64 system. The kernel 530 * loads this module based on its name in the module directory, but it 531 * could have been renamed. 532 */ 533 if (cpuid_getvendor(CPU) != X86_VENDOR_AMD || amd_family < 0xf) 534 return (-1); 535 |
448 if (amd_family == 0xf) | 536 if (amd_family == 0xf) { |
449 /* Some tools expect this string for family 0fh */ 450 (void) snprintf(amd_pcbe_impl_name, sizeof (amd_pcbe_impl_name), 451 "AMD Opteron & Athlon64"); | 537 /* Some tools expect this string for family 0fh */ 538 (void) snprintf(amd_pcbe_impl_name, sizeof (amd_pcbe_impl_name), 539 "AMD Opteron & Athlon64"); |
452 else | 540 } else { |
453 (void) snprintf(amd_pcbe_impl_name, sizeof (amd_pcbe_impl_name), | 541 (void) snprintf(amd_pcbe_impl_name, sizeof (amd_pcbe_impl_name), |
454 "AMD Family %02xh%s", amd_family, 455 AMD_PCBE_SUPPORTED(amd_family) ? "" :" (unsupported)"); | 542 "AMD Family %02xh", amd_family); 543 } |
456 457 /* | 544 545 /* |
546 * Determine whether or not the extended counter set is supported on 547 * this processor. 548 */ 549 if (is_x86_feature(x86_featureset, X86FSET_AMD_PCEC)) { 550 opd.opd_ncounters = OPT_PCBE_EXT_NCOUNTERS; 551 opd.opd_pesf = opt_pcbe_pes_ext_addr; 552 opd.opd_picf = opt_pcbe_pic_ext_addr; 553 } else { 554 opd.opd_ncounters = OPT_PCBE_DEF_NCOUNTERS; 555 opd.opd_pesf = opt_pcbe_pes_addr; 556 opd.opd_picf = opt_pcbe_pic_addr; 557 } 558 opd.opd_cmask = (1 << opd.opd_ncounters) - 1; 559 560 /* |
|
458 * Figure out processor revision here and assign appropriate 459 * event configuration. 460 */ 461 462 if (amd_family == 0xf) { 463 uint32_t rev; 464 465 rev = cpuid_getchiprev(CPU); --- 7 unchanged lines hidden (view full) --- 473 } else if (amd_family == 0x10) { 474 amd_pcbe_cpuref = amd_fam_10h_bkdg; 475 amd_events = family_10h_events; 476 amd_generic_events = family_10h_generic_events; 477 } else if (amd_family == 0x11) { 478 amd_pcbe_cpuref = amd_fam_11h_bkdg; 479 amd_events = family_11h_events; 480 amd_generic_events = opt_generic_events; | 561 * Figure out processor revision here and assign appropriate 562 * event configuration. 563 */ 564 565 if (amd_family == 0xf) { 566 uint32_t rev; 567 568 rev = cpuid_getchiprev(CPU); --- 7 unchanged lines hidden (view full) --- 576 } else if (amd_family == 0x10) { 577 amd_pcbe_cpuref = amd_fam_10h_bkdg; 578 amd_events = family_10h_events; 579 amd_generic_events = family_10h_generic_events; 580 } else if (amd_family == 0x11) { 581 amd_pcbe_cpuref = amd_fam_11h_bkdg; 582 amd_events = family_11h_events; 583 amd_generic_events = opt_generic_events; |
584 } else if (amd_family == 0x17 && amd_model <= 0x2f) { 585 amd_pcbe_cpuref = amd_fam_17h_reg; 586 amd_events = opteron_pcbe_f17h_events; 587 amd_generic_events = family_17h_papi_events; |
|
481 } else { | 588 } else { |
482 483 amd_pcbe_cpuref = amd_generic_bkdg; 484 (void) snprintf(amd_pcbe_cpuref, AMD_CPUREF_SIZE, 485 "See BIOS and Kernel Developer's Guide " \ 486 "(BKDG) For AMD Family %02xh Processors. " \ 487 "(Note that this pcbe does not explicitly " \ 488 "support this family)", amd_family); 489 | |
490 /* | 589 /* |
491 * For families that are not explicitly supported we'll use 492 * events for family 0xf. Even if they are not quite right, 493 * it's OK --- we state that pcbe is unsupported. | 590 * Different families have different meanings on events and even 591 * worse (like family 15h), different constraints around 592 * programming these values. |
494 */ | 593 */ |
495 amd_events = family_f_events; 496 amd_generic_events = opt_generic_events; | 594 return (-1); |
497 } 498 499 /* 500 * Construct event list. 501 * 502 * First pass: Calculate size needed. We'll need an additional byte 503 * for the NULL pointer during the last strcat. 504 * --- 24 unchanged lines hidden (view full) --- 529 evlist[evlist_sz - 1] = '\0'; 530 531 return (0); 532} 533 534static uint_t 535opt_pcbe_ncounters(void) 536{ | 595 } 596 597 /* 598 * Construct event list. 599 * 600 * First pass: Calculate size needed. We'll need an additional byte 601 * for the NULL pointer during the last strcat. 602 * --- 24 unchanged lines hidden (view full) --- 627 evlist[evlist_sz - 1] = '\0'; 628 629 return (0); 630} 631 632static uint_t 633opt_pcbe_ncounters(void) 634{ |
537 return (4); | 635 return (opd.opd_ncounters); |
538} 539 540static const char * 541opt_pcbe_impl_name(void) 542{ 543 return (amd_pcbe_impl_name); 544} 545 --- 12 unchanged lines hidden (view full) --- 558} 559 560static char * 561opt_pcbe_list_attrs(void) 562{ 563 return ("edge,pc,inv,cmask,umask"); 564} 565 | 636} 637 638static const char * 639opt_pcbe_impl_name(void) 640{ 641 return (amd_pcbe_impl_name); 642} 643 --- 12 unchanged lines hidden (view full) --- 656} 657 658static char * 659opt_pcbe_list_attrs(void) 660{ 661 return ("edge,pc,inv,cmask,umask"); 662} 663 |
566static amd_generic_event_t * | 664static const amd_generic_event_t * |
567find_generic_event(char *name) 568{ | 665find_generic_event(char *name) 666{ |
569 amd_generic_event_t *gevp; | 667 const amd_generic_event_t *gevp; |
570 571 for (gevp = amd_generic_events; gevp->name != NULL; gevp++) 572 if (strcmp(name, gevp->name) == 0) 573 return (gevp); 574 575 return (NULL); 576} 577 | 668 669 for (gevp = amd_generic_events; gevp->name != NULL; gevp++) 670 if (strcmp(name, gevp->name) == 0) 671 return (gevp); 672 673 return (NULL); 674} 675 |
578static amd_event_t * | 676static const amd_event_t * |
579find_event(char *name) 580{ | 677find_event(char *name) 678{ |
581 amd_event_t *evp; | 679 const amd_event_t *evp; |
582 583 for (evp = amd_events; evp->name != NULL; evp++) 584 if (strcmp(name, evp->name) == 0) 585 return (evp); 586 587 return (NULL); 588} 589 --- 5 unchanged lines hidden (view full) --- 595 * Check whether counter event is supported 596 */ 597 if (find_event(event) == NULL && find_generic_event(event) == NULL) 598 return (0); 599 600 /* 601 * Fortunately, all counters can count all events. 602 */ | 680 681 for (evp = amd_events; evp->name != NULL; evp++) 682 if (strcmp(name, evp->name) == 0) 683 return (evp); 684 685 return (NULL); 686} 687 --- 5 unchanged lines hidden (view full) --- 693 * Check whether counter event is supported 694 */ 695 if (find_event(event) == NULL && find_generic_event(event) == NULL) 696 return (0); 697 698 /* 699 * Fortunately, all counters can count all events. 700 */ |
603 return (0xF); | 701 return (opd.opd_cmask); |
604} 605 606static uint64_t 607opt_pcbe_overflow_bitmap(void) 608{ 609 /* 610 * Unfortunately, this chip cannot detect which counter overflowed, so 611 * we must act as if they all did. 612 */ | 702} 703 704static uint64_t 705opt_pcbe_overflow_bitmap(void) 706{ 707 /* 708 * Unfortunately, this chip cannot detect which counter overflowed, so 709 * we must act as if they all did. 710 */ |
613 return (0xF); | 711 return (opd.opd_cmask); |
614} 615 616/*ARGSUSED*/ 617static int 618opt_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 619 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 620{ | 712} 713 714/*ARGSUSED*/ 715static int 716opt_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 717 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 718{ |
621 opt_pcbe_config_t *cfg; 622 amd_event_t *evp; 623 amd_event_t ev_raw = { "raw", 0}; 624 amd_generic_event_t *gevp; 625 int i; 626 uint64_t evsel = 0, evsel_tmp = 0; | 719 opt_pcbe_config_t *cfg; 720 const amd_event_t *evp; 721 amd_event_t ev_raw = { "raw", 0}; 722 const amd_generic_event_t *gevp; 723 int i; 724 uint64_t evsel = 0, evsel_tmp = 0; |
627 628 /* 629 * If we've been handed an existing configuration, we need only preset 630 * the counter value. 631 */ 632 if (*data != NULL) { 633 cfg = *data; 634 cfg->opt_rawpic = preset & MASK48; 635 return (0); 636 } 637 | 725 726 /* 727 * If we've been handed an existing configuration, we need only preset 728 * the counter value. 729 */ 730 if (*data != NULL) { 731 cfg = *data; 732 cfg->opt_rawpic = preset & MASK48; 733 return (0); 734 } 735 |
638 if (picnum >= 4) | 736 if (picnum >= opd.opd_ncounters) |
639 return (CPC_INVALID_PICNUM); 640 641 if ((evp = find_event(event)) == NULL) { 642 if ((gevp = find_generic_event(event)) != NULL) { 643 evp = find_event(gevp->event); 644 ASSERT(evp != NULL); 645 646 if (nattrs > 0) --- 22 unchanged lines hidden (view full) --- 669 */ 670 671 /* Set GuestOnly bit to 0 and HostOnly bit to 1 */ 672 evsel &= ~OPT_PES_HOST; 673 evsel &= ~OPT_PES_GUEST; 674 675 /* Set bits [35:32] for extended part of Event Select field */ 676 evsel_tmp = evp->emask & 0x0f00; | 737 return (CPC_INVALID_PICNUM); 738 739 if ((evp = find_event(event)) == NULL) { 740 if ((gevp = find_generic_event(event)) != NULL) { 741 evp = find_event(gevp->event); 742 ASSERT(evp != NULL); 743 744 if (nattrs > 0) --- 22 unchanged lines hidden (view full) --- 767 */ 768 769 /* Set GuestOnly bit to 0 and HostOnly bit to 1 */ 770 evsel &= ~OPT_PES_HOST; 771 evsel &= ~OPT_PES_GUEST; 772 773 /* Set bits [35:32] for extended part of Event Select field */ 774 evsel_tmp = evp->emask & 0x0f00; |
677 evsel |= evsel_tmp << 24; | 775 evsel |= evsel_tmp << OPT_PES_EVSELHI_SHIFT; |
678 679 evsel |= evp->emask & 0x00ff; | 776 777 evsel |= evp->emask & 0x00ff; |
778 evsel |= evp->unit << OPT_PES_UMASK_SHIFT; |
|
680 681 if (flags & CPC_COUNT_USER) 682 evsel |= OPT_PES_USR; 683 if (flags & CPC_COUNT_SYSTEM) 684 evsel |= OPT_PES_OS; 685 if (flags & CPC_OVF_NOTIFY_EMT) 686 evsel |= OPT_PES_INT; 687 --- 29 unchanged lines hidden (view full) --- 717 718 *data = cfg; 719 return (0); 720} 721 722static void 723opt_pcbe_program(void *token) 724{ | 779 780 if (flags & CPC_COUNT_USER) 781 evsel |= OPT_PES_USR; 782 if (flags & CPC_COUNT_SYSTEM) 783 evsel |= OPT_PES_OS; 784 if (flags & CPC_OVF_NOTIFY_EMT) 785 evsel |= OPT_PES_INT; 786 --- 29 unchanged lines hidden (view full) --- 816 817 *data = cfg; 818 return (0); 819} 820 821static void 822opt_pcbe_program(void *token) 823{ |
725 opt_pcbe_config_t *cfgs[4] = { &nullcfgs[0], &nullcfgs[1], 726 &nullcfgs[2], &nullcfgs[3] }; | 824 opt_pcbe_config_t *cfgs[OPT_PCBE_EXT_NCOUNTERS] = { &nullcfgs[0], 825 &nullcfgs[1], &nullcfgs[2], 826 &nullcfgs[3], &nullcfgs[4], 827 &nullcfgs[5] }; |
727 opt_pcbe_config_t *pcfg = NULL; 728 int i; 729 ulong_t curcr4 = getcr4(); 730 731 /* 732 * Allow nonprivileged code to read the performance counters if desired. 733 */ 734 if (kcpc_allow_nonpriv(token)) 735 setcr4(curcr4 | CR4_PCE); 736 else 737 setcr4(curcr4 & ~CR4_PCE); 738 739 /* 740 * Query kernel for all configs which will be co-programmed. 741 */ 742 do { 743 pcfg = (opt_pcbe_config_t *)kcpc_next_config(token, pcfg, NULL); 744 745 if (pcfg != NULL) { | 828 opt_pcbe_config_t *pcfg = NULL; 829 int i; 830 ulong_t curcr4 = getcr4(); 831 832 /* 833 * Allow nonprivileged code to read the performance counters if desired. 834 */ 835 if (kcpc_allow_nonpriv(token)) 836 setcr4(curcr4 | CR4_PCE); 837 else 838 setcr4(curcr4 & ~CR4_PCE); 839 840 /* 841 * Query kernel for all configs which will be co-programmed. 842 */ 843 do { 844 pcfg = (opt_pcbe_config_t *)kcpc_next_config(token, pcfg, NULL); 845 846 if (pcfg != NULL) { |
746 ASSERT(pcfg->opt_picno < 4); | 847 ASSERT(pcfg->opt_picno < opd.opd_ncounters); |
747 cfgs[pcfg->opt_picno] = pcfg; 748 } 749 } while (pcfg != NULL); 750 751 /* 752 * Program in two loops. The first configures and presets the counter, 753 * and the second loop enables the counters. This ensures that the 754 * counters are all enabled as closely together in time as possible. 755 */ 756 | 848 cfgs[pcfg->opt_picno] = pcfg; 849 } 850 } while (pcfg != NULL); 851 852 /* 853 * Program in two loops. The first configures and presets the counter, 854 * and the second loop enables the counters. This ensures that the 855 * counters are all enabled as closely together in time as possible. 856 */ 857 |
757 for (i = 0; i < 4; i++) { 758 wrmsr(PES_BASE_ADDR + i, cfgs[i]->opt_evsel); 759 wrmsr(PIC_BASE_ADDR + i, cfgs[i]->opt_rawpic); | 858 for (i = 0; i < opd.opd_ncounters; i++) { 859 wrmsr(opd.opd_pesf(i), cfgs[i]->opt_evsel); 860 wrmsr(opd.opd_picf(i), cfgs[i]->opt_rawpic); |
760 } 761 | 861 } 862 |
762 for (i = 0; i < 4; i++) { 763 wrmsr(PES_BASE_ADDR + i, cfgs[i]->opt_evsel | | 863 for (i = 0; i < opd.opd_ncounters; i++) { 864 wrmsr(opd.opd_pesf(i), cfgs[i]->opt_evsel | |
764 (uint64_t)(uintptr_t)OPT_PES_ENABLE); 765 } 766} 767 768static void 769opt_pcbe_allstop(void) 770{ 771 int i; 772 | 865 (uint64_t)(uintptr_t)OPT_PES_ENABLE); 866 } 867} 868 869static void 870opt_pcbe_allstop(void) 871{ 872 int i; 873 |
773 for (i = 0; i < 4; i++) 774 wrmsr(PES_BASE_ADDR + i, 0ULL); | 874 for (i = 0; i < opd.opd_ncounters; i++) 875 wrmsr(opd.opd_pesf(i), 0ULL); |
775 776 /* 777 * Disable non-privileged access to the counter registers. 778 */ 779 setcr4(getcr4() & ~CR4_PCE); 780} 781 782static void 783opt_pcbe_sample(void *token) 784{ | 876 877 /* 878 * Disable non-privileged access to the counter registers. 879 */ 880 setcr4(getcr4() & ~CR4_PCE); 881} 882 883static void 884opt_pcbe_sample(void *token) 885{ |
785 opt_pcbe_config_t *cfgs[4] = { NULL, NULL, NULL, NULL }; | 886 opt_pcbe_config_t *cfgs[OPT_PCBE_EXT_NCOUNTERS] = { NULL, NULL, 887 NULL, NULL, NULL, NULL }; |
786 opt_pcbe_config_t *pcfg = NULL; 787 int i; | 888 opt_pcbe_config_t *pcfg = NULL; 889 int i; |
788 uint64_t curpic[4]; 789 uint64_t *addrs[4]; | 890 uint64_t curpic[OPT_PCBE_EXT_NCOUNTERS]; 891 uint64_t *addrs[OPT_PCBE_EXT_NCOUNTERS]; |
790 uint64_t *tmp; 791 int64_t diff; 792 | 892 uint64_t *tmp; 893 int64_t diff; 894 |
793 for (i = 0; i < 4; i++) 794 curpic[i] = rdmsr(PIC_BASE_ADDR + i); | 895 for (i = 0; i < opd.opd_ncounters; i++) 896 curpic[i] = rdmsr(opd.opd_picf(i)); |
795 796 /* 797 * Query kernel for all configs which are co-programmed. 798 */ 799 do { 800 pcfg = (opt_pcbe_config_t *)kcpc_next_config(token, pcfg, &tmp); 801 802 if (pcfg != NULL) { | 897 898 /* 899 * Query kernel for all configs which are co-programmed. 900 */ 901 do { 902 pcfg = (opt_pcbe_config_t *)kcpc_next_config(token, pcfg, &tmp); 903 904 if (pcfg != NULL) { |
803 ASSERT(pcfg->opt_picno < 4); | 905 ASSERT3U(pcfg->opt_picno, <, opd.opd_ncounters); |
804 cfgs[pcfg->opt_picno] = pcfg; 805 addrs[pcfg->opt_picno] = tmp; 806 } 807 } while (pcfg != NULL); 808 | 906 cfgs[pcfg->opt_picno] = pcfg; 907 addrs[pcfg->opt_picno] = tmp; 908 } 909 } while (pcfg != NULL); 910 |
809 for (i = 0; i < 4; i++) { | 911 for (i = 0; i < opd.opd_ncounters; i++) { |
810 if (cfgs[i] == NULL) 811 continue; 812 813 diff = (curpic[i] - cfgs[i]->opt_rawpic) & MASK48; 814 *addrs[i] += diff; 815 DTRACE_PROBE4(opt__pcbe__sample, int, i, uint64_t, *addrs[i], 816 uint64_t, curpic[i], uint64_t, cfgs[i]->opt_rawpic); 817 cfgs[i]->opt_rawpic = *addrs[i] & MASK48; --- 50 unchanged lines hidden --- | 912 if (cfgs[i] == NULL) 913 continue; 914 915 diff = (curpic[i] - cfgs[i]->opt_rawpic) & MASK48; 916 *addrs[i] += diff; 917 DTRACE_PROBE4(opt__pcbe__sample, int, i, uint64_t, *addrs[i], 918 uint64_t, curpic[i], uint64_t, cfgs[i]->opt_rawpic); 919 cfgs[i]->opt_rawpic = *addrs[i] & MASK48; --- 50 unchanged lines hidden --- |