/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* This file contains preset event names from the Performance Application
* Programming Interface v3.5 which included the following notice:
*
* Copyright (c) 2005,6
* Innovative Computing Labs
* Computer Science Department,
* University of Tennessee,
* Knoxville, TN.
* All Rights Reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* * Neither the name of the University of Tennessee nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* This open source software license conforms to the BSD License template.
*/
/*
* Performance Counter Back-End for Intel processors supporting Architectural
* Performance Monitoring.
*/
#include <sys/cpc_impl.h>
#include <sys/cpc_pcbe.h>
#include <sys/inttypes.h>
#include <sys/x86_archext.h>
#include <sys/archsystm.h>
#include <sys/privregs.h>
static int core_pcbe_init(void);
static uint_t core_pcbe_ncounters(void);
static const char *core_pcbe_impl_name(void);
static const char *core_pcbe_cpuref(void);
static char *core_pcbe_list_attrs(void);
static uint64_t core_pcbe_overflow_bitmap(void);
void *token);
static void core_pcbe_program(void *token);
static void core_pcbe_allstop(void);
static void core_pcbe_sample(void *token);
static void core_pcbe_free(void *config);
#define FALSE 0
/* Counter Type */
/* MSR Addresses */
/*
* Processor Event Select register fields
*/
/*
* Fixed-function counter attributes
*/
/*
* Number of bits for specifying each FFC's attributes in the control register
*/
/*
* CondChgd and OvfBuffer fields of global status and overflow control registers
*/
/*
* Only the lower 32-bits can be written to in the general-purpose
* counters. The higher bits are extended from bit 31; all ones if
* bit 31 is one and all zeros otherwise.
*
* The fixed-function counters do not have this restriction.
*/
typedef struct core_pcbe_config {
PCBE_VER_1, /* pcbe_ver */
core_pcbe_ncounters, /* pcbe_ncounters */
core_pcbe_impl_name, /* pcbe_impl_name */
core_pcbe_cpuref, /* pcbe_cpuref */
core_pcbe_list_events, /* pcbe_list_events */
core_pcbe_list_attrs, /* pcbe_list_attrs */
core_pcbe_event_coverage, /* pcbe_event_coverage */
core_pcbe_overflow_bitmap, /* pcbe_overflow_bitmap */
core_pcbe_configure, /* pcbe_configure */
core_pcbe_program, /* pcbe_program */
core_pcbe_allstop, /* pcbe_allstop */
core_pcbe_sample, /* pcbe_sample */
core_pcbe_free /* pcbe_free */
};
struct nametable_core_uarch {
const char *name;
};
/*
* Counting an event for all cores or all bus agents requires cpc_cpu privileges
*/
struct generic_events {
const char *name;
};
{ "PAPI_tot_ins", 0xc0, 0x00 }, /* inst_retired.any_p */
{ "PAPI_br_msp", 0xc5, 0x00 }, /* br_inst_retired.mispred */
{ "PAPI_br_ntk", 0xc4, 0x03 },
/* br_inst_retired.pred_not_taken|pred_taken */
{ "PAPI_br_prc", 0xc4, 0x05 },
/* br_inst_retired.pred_not_taken|pred_taken */
{ "PAPI_hw_int", 0xc8, 0x00 }, /* hw_int_rvc */
{ "PAPI_tot_iis", 0xaa, 0x01 }, /* macro_insts.decoded */
{ "PAPI_l1_dca", 0x43, 0x01 }, /* l1d_all_ref */
{ "PAPI_l1_icm", 0x81, 0x00 }, /* l1i_misses */
{ "PAPI_l1_icr", 0x80, 0x00 }, /* l1i_reads */
{ "PAPI_l1_tcw", 0x41, 0x0f }, /* l1d_cache_st.mesi */
{ "PAPI_l2_tch", 0x2e, 0x4e }, /* l2_rqsts.mes */
{ "PAPI_ld_ins", 0xc0, 0x01 }, /* inst_retired.loads */
{ "PAPI_lst_ins", 0xc0, 0x03 }, /* inst_retired.loads|stores */
{ "PAPI_tlb_dm", 0x08, 0x01 }, /* dtlb_misses.any */
{ "PAPI_tlb_tl", 0x0c, 0x03 }, /* page_walks */
{ "", NT_END, 0 }
};
{ "PAPI_l1_dcm", 0xcb, 0x01 }, /* mem_load_retired.l1d_miss */
{ "", NT_END, 0 }
};
/*
* The events listed in the following table can be counted on all
* general-purpose counters on processors that are of Penryn and Merom Family
*/
/* Alphabetical order of event name */
{ "baclears", 0x0, 0xe6 },
{ "bogus_br", 0x0, 0xe4 },
{ "br_bac_missp_exec", 0x0, 0x8a },
{ "br_call_exec", 0x0, 0x92 },
{ "br_call_missp_exec", 0x0, 0x93 },
{ "br_cnd_exec", 0x0, 0x8b },
{ "br_cnd_missp_exec", 0x0, 0x8c },
{ "br_ind_call_exec", 0x0, 0x94 },
{ "br_ind_exec", 0x0, 0x8d },
{ "br_ind_missp_exec", 0x0, 0x8e },
{ "br_inst_decoded", 0x0, 0xe0 },
{ "br_inst_exec", 0x0, 0x88 },
{ "br_inst_retired", 0x0, 0xc4 },
{ "br_inst_retired_mispred", 0x0, 0xc5 },
{ "br_missp_exec", 0x0, 0x89 },
{ "br_ret_bac_missp_exec", 0x0, 0x91 },
{ "br_ret_exec", 0x0, 0x8f },
{ "br_ret_missp_exec", 0x0, 0x90 },
{ "br_tkn_bubble_1", 0x0, 0x97 },
{ "br_tkn_bubble_2", 0x0, 0x98 },
{ "cpu_clk_unhalted", 0x0, 0x3c },
{ "cycles_int", 0x0, 0xc6 },
{ "cycles_l1i_mem_stalled", 0x0, 0x86 },
{ "dtlb_misses", 0x0, 0x08 },
{ "eist_trans", 0x0, 0x3a },
{ "esp", 0x0, 0xab },
{ "fp_mmx_trans", 0x0, 0xcc },
{ "hw_int_rcv", 0x0, 0xc8 },
{ "ild_stall", 0x0, 0x87 },
{ "inst_queue", 0x0, 0x83 },
{ "inst_retired", 0x0, 0xc0 },
{ "itlb", 0x0, 0x82 },
{ "itlb_miss_retired", 0x0, 0xc9 },
{ "l1d_all_ref", 0x0, 0x43 },
{ "l1d_cache_ld", 0x0, 0x40 },
{ "l1d_cache_lock", 0x0, 0x42 },
{ "l1d_cache_st", 0x0, 0x41 },
{ "l1d_m_evict", 0x0, 0x47 },
{ "l1d_m_repl", 0x0, 0x46 },
{ "l1d_pend_miss", 0x0, 0x48 },
{ "l1d_prefetch", 0x0, 0x4e },
{ "l1d_repl", 0x0, 0x45 },
{ "l1d_split", 0x0, 0x49 },
{ "l1i_misses", 0x0, 0x81 },
{ "l1i_reads", 0x0, 0x80 },
{ "load_block", 0x0, 0x03 },
{ "load_hit_pre", 0x0, 0x4c },
{ "machine_nukes", 0x0, 0xc3 },
{ "macro_insts", 0x0, 0xaa },
{ "memory_disambiguation", 0x0, 0x09 },
{ "misalign_mem_ref", 0x0, 0x05 },
{ "page_walks", 0x0, 0x0c },
{ "pref_rqsts_dn", 0x0, 0xf8 },
{ "pref_rqsts_up", 0x0, 0xf0 },
{ "rat_stalls", 0x0, 0xd2 },
{ "resource_stalls", 0x0, 0xdc },
{ "rs_uops_dispatched", 0x0, 0xa0 },
{ "seg_reg_renames", 0x0, 0xd5 },
{ "seg_rename_stalls", 0x0, 0xd4 },
{ "segment_reg_loads", 0x0, 0x06 },
{ "simd_assist", 0x0, 0xcd },
{ "simd_comp_inst_retired", 0x0, 0xca },
{ "simd_inst_retired", 0x0, 0xc7 },
{ "simd_instr_retired", 0x0, 0xce },
{ "simd_sat_instr_retired", 0x0, 0xcf },
{ "simd_sat_uop_exec", 0x0, 0xb1 },
{ "simd_uop_type_exec", 0x0, 0xb3 },
{ "simd_uops_exec", 0x0, 0xb0 },
{ "sse_pre_exec", 0x0, 0x07 },
{ "sse_pre_miss", 0x0, 0x4b },
{ "store_block", 0x0, 0x04 },
{ "thermal_trip", 0x0, 0x3b },
{ "uops_retired", 0x0, 0xc2 },
{ "x87_ops_retired", 0x0, 0xc1 },
};
/*
* If any of the pic specific events require privileges, make sure to add a
* check in configure_gpc() to find whether an event hard-coded as a number by
* the user has any privilege requirements
*/
/* Alphabetical order of event name */
{ "cycles_div_busy", 0x0, 0x14 },
{ "fp_comp_ops_exe", 0x0, 0x10 },
{ "idle_during_div", 0x0, 0x18 },
{ "mem_load_retired", 0x0, 0xcb },
{ "rs_uops_dispatched_port", 0x0, 0xa1 },
};
/* Alphabetical order of event name */
{ "delayed_bypass", 0x0, 0x19 },
{ "div", 0x0, 0x13 },
{ "fp_assist", 0x0, 0x11 },
{ "mul", 0x0, 0x12 },
};
/* FFC entries must be in order */
static char *ffc_names_non_htt[] = {
"instr_retired.any",
"cpu_clk_unhalted.core",
"cpu_clk_unhalted.ref",
};
static char *ffc_names_htt[] = {
"instr_retired.any",
"cpu_clk_unhalted.thread",
"cpu_clk_unhalted.ref",
};
static char *ffc_genericnames[] = {
"PAPI_tot_ins",
"PAPI_tot_cyc",
"",
};
static const char *core_cpuref =
"See Appendix A of the \"Intel 64 and IA-32 Architectures Software" \
" Developer's Manual Volume 3B: System Programming Guide, Part 2\"" \
" Order Number: 253669-026US, Februrary 2008";
struct events_table_t {
const char *name;
};
/* Used to describe which counters support an event */
#define C(x) (1 << (x))
#define C0 C(0)
/* Architectural events */
#define ARCH_EVENTS_COMMON \
};
};
static char *arch_genevents_table[] = {
"PAPI_tot_cyc", /* cpu_clk_unhalted.thread_p/core */
"PAPI_tot_ins", /* inst_retired.any_p */
"", /* cpu_clk_unhalted.ref_p */
"", /* longest_lat_cache.reference */
"", /* longest_lat_cache.miss */
"", /* br_inst_retired.all_branches */
"", /* br_misp_retired.all_branches */
};
#define GENERICEVENTS_FAM6_NHM \
/* l2_rqsts. loads, rfos and ifetches */ \
/* l2_rqsts. ld_hit, rfo_hit and ifetch_hit */ \
/* l2_rqsts. ld_miss, rfo_miss and ifetch_miss */ \
/* mem_inst_retired.loads and stores */ \
#define EVENTS_FAM6_NHM \
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
#define GENERICEVENTS_FAM6_MOD28 \
/* br_inst_retired.pred_not_taken|mispred_not_taken */ \
/* br_inst_retired.pred_not_taken|pred_taken */ \
#define EVENTS_FAM6_MOD28 \
"cycles_int_masked.cycles_int_pending_and_masked" }, \
{ NT_END, 0, 0, "" }
};
{ NT_END, 0, 0, "" }
};
/*
* Initialize string containing list of supported general-purpose counter
* events for processors of Penryn and Merom Family
*/
static void
{
const struct nametable_core_uarch *n;
const struct generic_events *k;
uint64_t i;
/* Calculate space needed to save all the common event names */
common_size = 0;
}
}
for (i = 0; i < num_gpc; i++) {
size = 0;
switch (i) {
case 0:
break;
case 1:
break;
default:
break;
}
if (picspecific_events != NULL) {
for (n = picspecific_events;
n++) {
}
}
if (picspecific_genericevents != NULL) {
for (k = picspecific_genericevents;
}
}
gpc_names[i] =
gpc_names[i][0] = '\0';
if (picspecific_events != NULL) {
for (n = picspecific_events;
}
}
if (picspecific_genericevents != NULL) {
for (k = picspecific_genericevents;
}
}
n++) {
}
}
/*
* Remove trailing comma.
*/
}
}
static int
core_pcbe_init(void)
{
uint64_t i;
uint64_t j;
return (-1);
/* Obtain Basic CPUID information */
(void) __cpuid_insn(&cp);
/* No Architectural Performance Monitoring Leaf returned by CPUID */
return (-1);
}
/* Obtain the Architectural Performance Monitoring Leaf */
(void) __cpuid_insn(&cp);
/*
* Fixed-Function Counters (FFC)
*
* All Family 6 Model 15 and Model 23 processors have fixed-function
* counters. These counters were made Architectural with
* Family 6 Model 15 Stepping 9.
*/
switch (versionid) {
case 0:
return (-1);
case 2:
/*
* Some processors have an errata (AW34) where
* versionid is reported as 2 when actually 1.
* In this case, fixed-function counters are
* model-specific as in Version 1.
*/
if (num_ffc != 0) {
break;
}
/* FALLTHROUGH */
case 1:
num_ffc = 3;
width_ffc = 40;
versionid = 1;
break;
default:
break;
}
if (num_ffc >= 64)
return (-1);
/* Set HTT-specific names of architectural & FFC events */
sizeof (arch_events_table_htt) /
sizeof (struct events_table_t);
sizeof (ffc_names_htt) / sizeof (char *);
} else {
sizeof (arch_events_table_non_htt) /
sizeof (struct events_table_t);
sizeof (ffc_names_non_htt) / sizeof (char *);
}
if (num_ffc >= known_ffc_num) {
/*
* The system seems to have more fixed-function counters than
* what this PCBE is able to handle correctly. Default to the
* maximum number of fixed-function counters that this driver
* is aware of.
*/
}
/*
* General Purpose Counters (GPC)
*/
if (num_gpc >= 64)
return (-1);
if (total_pmc > 64) {
/* Too wide for the overflow bitmap */
return (-1);
}
/* FFC names */
for (i = 0; i < num_ffc; i++) {
ffc_allnames[i] = kmem_alloc(
KM_SLEEP);
ffc_allnames[i][0] = '\0';
/* Check if this ffc has a generic name */
}
}
/* GPC events for Family 6 Models 15, 23 and 29 only */
"Core Microarchitecture");
return (0);
}
"Intel Arch PerfMon v%d on Family %d Model %d",
/*
* Architectural events
*/
/*
* To handle the case where a new performance monitoring setup is run
* on a non-debug kernel
*/
} else {
}
/*
* Process architectural and non-architectural events using GPC
*/
if (num_gpc > 0) {
/* Calculate space required for the architectural gpc events */
for (i = 0; i < known_arch_events; i++) {
if (((1U << i) & arch_events_vector) == 0) {
}
}
}
/* Non-architectural events list */
switch (model) {
/* Nehalem */
case 26:
case 30:
case 31:
/* Westmere */
case 37:
case 44:
/* Nehalem-EX */
case 46:
case 47:
break;
case 28:
break;
}
for (i = 0; i < num_gpc; i++) {
/*
* Determine length of all supported event names
* (architectural + non-architectural)
*/
for (j = 0; events_table != NULL &&
j++) {
if (C(i) & events_table[j].supported_counters) {
1;
}
}
/* Allocate memory for this pics list */
gpc_names[i][0] = '\0';
if (size == 0) {
continue;
}
/*
* Create the list of all supported events
* (architectural + non-architectural)
*/
for (j = 0; j < known_arch_events; j++) {
if (((1U << j) & arch_events_vector) == 0) {
arch_events_table[j].name);
if (strcmp(
arch_genevents_table[j], "")
!= 0) {
arch_genevents_table[j]);
",");
}
}
}
for (j = 0; events_table != NULL &&
j++) {
if (C(i) & events_table[j].supported_counters) {
events_table[j].name);
}
}
/* Remove trailing comma */
}
}
return (0);
}
{
return (total_pmc);
}
static const char *core_pcbe_impl_name(void)
{
return (core_impl_name);
}
static const char *core_pcbe_cpuref(void)
{
return (core_cpuref);
}
{
} else {
}
}
static char *core_pcbe_list_attrs(void)
{
if (versionid >= 3) {
return ("edge,inv,umask,cmask,anythr");
} else {
return ("edge,pc,inv,umask,cmask");
}
}
static const struct nametable_core_uarch *
const struct nametable_core_uarch *nametable)
{
const struct nametable_core_uarch *n;
if (compare_result <= 0) {
break;
}
}
if (compare_result == 0) {
return (n);
}
return (NULL);
}
static const struct generic_events *
{
const struct generic_events *n;
return (n);
};
}
return (NULL);
}
static const struct events_table_t *
{
int i;
/* Search architectural events */
for (i = 0; i < known_arch_events; i++) {
if (((1U << i) & arch_events_vector) == 0) {
return (&arch_events_table[i]);
}
}
}
/* Search non-architectural events */
if (events_table != NULL) {
return (&events_table[i]);
}
}
}
return (NULL);
}
static uint64_t
{
const struct events_table_t *n;
int i;
bitmap = 0;
/* Is it an event that a GPC can track? */
if (versionid >= 3) {
n = find_gpcevent(event);
if (n != NULL) {
bitmap |= (n->supported_counters &
}
} else {
bitmap |= 1ULL;
} else if (find_gpcevent_core_uarch(event,
cmn_gpc_events_core_uarch) != NULL) {
NULL) {
bitmap |= 1ULL;
NULL) {
}
}
/* Check if the event can be counted in the fixed-function counters */
if (num_ffc > 0) {
for (i = 0; i < num_ffc; i++) {
}
}
}
return (bitmap);
}
static uint64_t
{
extern int kcpc_hw_overflow_intr_installed;
(*kcpc_hw_enable_cpc_intr)();
return (overflow_bitmap);
}
static int
const struct nametable_core_uarch *n)
{
if (secpolicy_cpc_cpu(crgetcred()) != 0) {
return (CPC_ATTR_REQUIRES_PRIVILEGE);
}
}
return (0);
}
static int
{
const struct nametable_core_uarch *n;
const struct generic_events *k = NULL;
const struct nametable_core_uarch *m;
uint_t i;
long event_num;
if (((preset & BITS_EXTENDED_FROM_31) != 0) &&
((preset & BITS_EXTENDED_FROM_31) !=
/*
* Bits beyond bit-31 in the general-purpose counters can only
* be written to by extension of bit 31. We cannot preset
* these bits to any value other than all 1s or all 0s.
*/
return (CPC_ATTRIBUTE_OUT_OF_RANGE);
}
if (versionid >= 3) {
return (CPC_PIC_NOT_CAPABLE);
}
if (nattrs > 0 &&
return (CPC_ATTRIBUTE_OUT_OF_RANGE);
}
} else {
/* Event specified as raw event code */
return (CPC_INVALID_EVENT);
}
}
} else {
NULL ||
(picnum == 0 &&
NULL)) {
if (nattrs > 0) {
return (CPC_ATTRIBUTE_OUT_OF_RANGE);
}
} else {
/* Not a generic event */
if (n == NULL) {
switch (picnum) {
case 0:
break;
case 1:
break;
default:
break;
}
if (picspecific_events != NULL) {
}
}
if (n == NULL) {
/*
* Check if this is a case where the event was
* specified directly by its event number
* instead of its name string.
*/
0) {
return (CPC_INVALID_EVENT);
}
/*
* Search the event table to find out if the
* event specified has an privilege
* requirements. Currently none of the
* pic-specific counters have any privilege
* requirements. Hence only the table
* cmn_gpc_events_core_uarch is searched.
*/
for (m = cmn_gpc_events_core_uarch;
m++) {
break;
}
}
n = &nt_raw;
} else {
n = m;
}
}
}
}
for (i = 0; i < nattrs; i++) {
return (CPC_ATTRIBUTE_OUT_OF_RANGE);
}
/* Clear out the default umask */
/* Use the user provided umask */
return (CPC_ATTRIBUTE_OUT_OF_RANGE);
}
0) {
if (versionid < 3)
return (CPC_INVALID_ATTRIBUTE);
if (secpolicy_cpc_cpu(crgetcred()) != 0) {
return (CPC_ATTR_REQUIRES_PRIVILEGE);
}
} else {
return (CPC_INVALID_ATTRIBUTE);
}
}
if (flags & CPC_COUNT_USER)
if (flags & CPC_COUNT_SYSTEM)
if (flags & CPC_OVF_NOTIFY_EMT)
if (check_cpc_securitypolicy(&conf, n) != 0) {
return (CPC_ATTR_REQUIRES_PRIVILEGE);
}
}
return (0);
}
static int
{
uint_t i;
return (CPC_INVALID_PICNUM);
}
return (CPC_INVALID_EVENT);
}
return (CPC_INVALID_ATTRIBUTE);
}
for (i = 0; i < nattrs; i++) {
if (secpolicy_cpc_cpu(crgetcred()) != 0) {
return (CPC_ATTR_REQUIRES_PRIVILEGE);
}
}
} else {
return (CPC_INVALID_ATTRIBUTE);
}
}
/* All fixed-function counters have the same control register */
if (flags & CPC_COUNT_USER)
if (flags & CPC_COUNT_SYSTEM)
if (flags & CPC_OVF_NOTIFY_EMT)
return (0);
}
/*ARGSUSED*/
static int
void *token)
{
int ret;
/*
* If we've been handed an existing configuration, we need only preset
* the counter value.
*/
else /* CORE_FFC */
return (0);
}
return (CPC_INVALID_PICNUM);
}
} else {
}
return (ret);
}
static void
{
if (kcpc_allow_nonpriv(token))
/* Allow RDPMC at any ring level */
else
/* Allow RDPMC only at ring 0 */
/* Clear any overflow indicators before programming the counters */
perf_global_ctrl = 0;
perf_fixed_ctr_ctrl = 0;
/*
* General-purpose counter registers have write
* restrictions where only the lower 32-bits can be
* written to. The rest of the relevant bits are
* written to by extension from bit 31 (all ZEROS if
* bit-31 is ZERO and all ONE if bit-31 is ONE). This
* makes it possible to write to the counter register
* only values that have all ONEs or all ZEROs in the
* higher bits.
*/
/*
* Straighforward case where the higher bits
* are all ZEROs or all ONEs.
*/
} else {
/*
* The high order bits are not all the same.
* We save what is currently in the registers
* and do not write to it. When we want to do
* a read from this register later (in
* core_pcbe_sample()), we subtract the value
* we save here to get the actual event count.
*
* NOTE: As a result, we will not get overflow
* interrupts as expected.
*/
}
} else {
/*
* Unlike the general-purpose counters, all relevant
* bits of fixed-function counters can be written to.
*/
/*
* Collect the control bits for all the
* fixed-function counters and write it at one shot
* later in this function
*/
}
cfg = (core_pcbe_config_t *)
}
/* Enable all the counters */
}
static void
core_pcbe_allstop(void)
{
/* Disable all the counters together */
}
static void
{
} else {
}
} else {
/* Counter overflowed since our last sample */
1;
}
cfg =
}
}
static void
{
}
"Core Performance Counters",
};
};
int
_init(void)
{
if (core_pcbe_init() != 0) {
return (ENOTSUP);
}
return (mod_install(&core_modl));
}
int
_fini(void)
{
return (mod_remove(&core_modl));
}
int
{
}