17bd4a6f5Skk /*
27bd4a6f5Skk * CDDL HEADER START
37bd4a6f5Skk *
47bd4a6f5Skk * The contents of this file are subject to the terms of the
57bd4a6f5Skk * Common Development and Distribution License (the "License").
67bd4a6f5Skk * You may not use this file except in compliance with the License.
77bd4a6f5Skk *
87bd4a6f5Skk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97bd4a6f5Skk * or http://www.opensolaris.org/os/licensing.
107bd4a6f5Skk * See the License for the specific language governing permissions
117bd4a6f5Skk * and limitations under the License.
127bd4a6f5Skk *
137bd4a6f5Skk * When distributing Covered Code, include this CDDL HEADER in each
147bd4a6f5Skk * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157bd4a6f5Skk * If applicable, add the following below this CDDL HEADER, with the
167bd4a6f5Skk * fields enclosed by brackets "[]" replaced with your own identifying
177bd4a6f5Skk * information: Portions Copyright [yyyy] [name of copyright owner]
187bd4a6f5Skk *
197bd4a6f5Skk * CDDL HEADER END
207bd4a6f5Skk */
217bd4a6f5Skk /*
22ac13ce24SAdrian Frost * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23a00b240dSJohn Levon * Copyright 2019 Joyent, Inc.
247bd4a6f5Skk */
257bd4a6f5Skk
26560e0ee2SKuriakose Kuruvilla /*
27560e0ee2SKuriakose Kuruvilla * This file contains preset event names from the Performance Application
28560e0ee2SKuriakose Kuruvilla * Programming Interface v3.5 which included the following notice:
29560e0ee2SKuriakose Kuruvilla *
30560e0ee2SKuriakose Kuruvilla * Copyright (c) 2005,6
31560e0ee2SKuriakose Kuruvilla * Innovative Computing Labs
32560e0ee2SKuriakose Kuruvilla * Computer Science Department,
33560e0ee2SKuriakose Kuruvilla * University of Tennessee,
34560e0ee2SKuriakose Kuruvilla * Knoxville, TN.
35560e0ee2SKuriakose Kuruvilla * All Rights Reserved.
36560e0ee2SKuriakose Kuruvilla *
37560e0ee2SKuriakose Kuruvilla *
38560e0ee2SKuriakose Kuruvilla * Redistribution and use in source and binary forms, with or without
39560e0ee2SKuriakose Kuruvilla * modification, are permitted provided that the following conditions are met:
40560e0ee2SKuriakose Kuruvilla *
41560e0ee2SKuriakose Kuruvilla * * Redistributions of source code must retain the above copyright notice,
42560e0ee2SKuriakose Kuruvilla * this list of conditions and the following disclaimer.
43560e0ee2SKuriakose Kuruvilla * * Redistributions in binary form must reproduce the above copyright
44560e0ee2SKuriakose Kuruvilla * notice, this list of conditions and the following disclaimer in the
45560e0ee2SKuriakose Kuruvilla * documentation and/or other materials provided with the distribution.
46560e0ee2SKuriakose Kuruvilla * * Neither the name of the University of Tennessee nor the names of its
47560e0ee2SKuriakose Kuruvilla * contributors may be used to endorse or promote products derived from
48560e0ee2SKuriakose Kuruvilla * this software without specific prior written permission.
49560e0ee2SKuriakose Kuruvilla *
50560e0ee2SKuriakose Kuruvilla * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51560e0ee2SKuriakose Kuruvilla * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52560e0ee2SKuriakose Kuruvilla * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53560e0ee2SKuriakose Kuruvilla * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
54560e0ee2SKuriakose Kuruvilla * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55560e0ee2SKuriakose Kuruvilla * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56560e0ee2SKuriakose Kuruvilla * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57560e0ee2SKuriakose Kuruvilla * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58560e0ee2SKuriakose Kuruvilla * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59560e0ee2SKuriakose Kuruvilla * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60560e0ee2SKuriakose Kuruvilla * POSSIBILITY OF SUCH DAMAGE.
61560e0ee2SKuriakose Kuruvilla *
62560e0ee2SKuriakose Kuruvilla *
63560e0ee2SKuriakose Kuruvilla * This open source software license conforms to the BSD License template.
64560e0ee2SKuriakose Kuruvilla */
65560e0ee2SKuriakose Kuruvilla
66560e0ee2SKuriakose Kuruvilla
677bd4a6f5Skk /*
68afb806e6SKuriakose Kuruvilla * Performance Counter Back-End for Intel processors supporting Architectural
69afb806e6SKuriakose Kuruvilla * Performance Monitoring.
707bd4a6f5Skk */
717bd4a6f5Skk
727bd4a6f5Skk #include <sys/cpuvar.h>
737bd4a6f5Skk #include <sys/param.h>
747bd4a6f5Skk #include <sys/cpc_impl.h>
757bd4a6f5Skk #include <sys/cpc_pcbe.h>
767bd4a6f5Skk #include <sys/modctl.h>
777bd4a6f5Skk #include <sys/inttypes.h>
787bd4a6f5Skk #include <sys/systm.h>
797bd4a6f5Skk #include <sys/cmn_err.h>
807bd4a6f5Skk #include <sys/x86_archext.h>
817bd4a6f5Skk #include <sys/sdt.h>
827bd4a6f5Skk #include <sys/archsystm.h>
837bd4a6f5Skk #include <sys/privregs.h>
847bd4a6f5Skk #include <sys/ddi.h>
857bd4a6f5Skk #include <sys/sunddi.h>
867bd4a6f5Skk #include <sys/cred.h>
877bd4a6f5Skk #include <sys/policy.h>
887bd4a6f5Skk
897e3dbbacSRobert Mustacchi #include "core_pcbe_table.h"
907e3dbbacSRobert Mustacchi #include <core_pcbe_cpcgen.h>
917e3dbbacSRobert Mustacchi
927bd4a6f5Skk static int core_pcbe_init(void);
937bd4a6f5Skk static uint_t core_pcbe_ncounters(void);
947bd4a6f5Skk static const char *core_pcbe_impl_name(void);
957bd4a6f5Skk static const char *core_pcbe_cpuref(void);
967bd4a6f5Skk static char *core_pcbe_list_events(uint_t picnum);
977bd4a6f5Skk static char *core_pcbe_list_attrs(void);
987bd4a6f5Skk static uint64_t core_pcbe_event_coverage(char *event);
997bd4a6f5Skk static uint64_t core_pcbe_overflow_bitmap(void);
1007bd4a6f5Skk static int core_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
1017bd4a6f5Skk uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
1027bd4a6f5Skk void *token);
1037bd4a6f5Skk static void core_pcbe_program(void *token);
1047bd4a6f5Skk static void core_pcbe_allstop(void);
1057bd4a6f5Skk static void core_pcbe_sample(void *token);
1067bd4a6f5Skk static void core_pcbe_free(void *config);
1077bd4a6f5Skk
1087bd4a6f5Skk #define FALSE 0
1097bd4a6f5Skk #define TRUE 1
1107bd4a6f5Skk
1117bd4a6f5Skk /* Counter Type */
1127bd4a6f5Skk #define CORE_GPC 0 /* General-Purpose Counter (GPC) */
1137bd4a6f5Skk #define CORE_FFC 1 /* Fixed-Function Counter (FFC) */
1147bd4a6f5Skk
1157bd4a6f5Skk /* MSR Addresses */
1167bd4a6f5Skk #define GPC_BASE_PMC 0x00c1 /* First GPC */
1177bd4a6f5Skk #define GPC_BASE_PES 0x0186 /* First GPC Event Select register */
1187bd4a6f5Skk #define FFC_BASE_PMC 0x0309 /* First FFC */
1197bd4a6f5Skk #define PERF_FIXED_CTR_CTRL 0x038d /* Used to enable/disable FFCs */
1207bd4a6f5Skk #define PERF_GLOBAL_STATUS 0x038e /* Overflow status register */
1217bd4a6f5Skk #define PERF_GLOBAL_CTRL 0x038f /* Used to enable/disable counting */
1227bd4a6f5Skk #define PERF_GLOBAL_OVF_CTRL 0x0390 /* Used to clear overflow status */
1237bd4a6f5Skk
1247bd4a6f5Skk /*
1257bd4a6f5Skk * Processor Event Select register fields
1267bd4a6f5Skk */
1277bd4a6f5Skk #define CORE_USR (1ULL << 16) /* Count while not in ring 0 */
1287bd4a6f5Skk #define CORE_OS (1ULL << 17) /* Count while in ring 0 */
1297bd4a6f5Skk #define CORE_EDGE (1ULL << 18) /* Enable edge detection */
1307bd4a6f5Skk #define CORE_PC (1ULL << 19) /* Enable pin control */
1317bd4a6f5Skk #define CORE_INT (1ULL << 20) /* Enable interrupt on overflow */
1327bd4a6f5Skk #define CORE_EN (1ULL << 22) /* Enable counting */
1337bd4a6f5Skk #define CORE_INV (1ULL << 23) /* Invert the CMASK */
134a18ddb3cSKuriakose Kuruvilla #define CORE_ANYTHR (1ULL << 21) /* Count event for any thread on core */
1357bd4a6f5Skk
1367bd4a6f5Skk #define CORE_UMASK_SHIFT 8
1377bd4a6f5Skk #define CORE_UMASK_MASK 0xffu
1387bd4a6f5Skk #define CORE_CMASK_SHIFT 24
1397bd4a6f5Skk #define CORE_CMASK_MASK 0xffu
1407bd4a6f5Skk
1417bd4a6f5Skk /*
1427bd4a6f5Skk * Fixed-function counter attributes
1437bd4a6f5Skk */
1447bd4a6f5Skk #define CORE_FFC_OS_EN (1ULL << 0) /* Count while not in ring 0 */
1457bd4a6f5Skk #define CORE_FFC_USR_EN (1ULL << 1) /* Count while in ring 1 */
146a18ddb3cSKuriakose Kuruvilla #define CORE_FFC_ANYTHR (1ULL << 2) /* Count event for any thread on core */
1477bd4a6f5Skk #define CORE_FFC_PMI (1ULL << 3) /* Enable interrupt on overflow */
1487bd4a6f5Skk
1497bd4a6f5Skk /*
1507bd4a6f5Skk * Number of bits for specifying each FFC's attributes in the control register
1517bd4a6f5Skk */
1527bd4a6f5Skk #define CORE_FFC_ATTR_SIZE 4
1537bd4a6f5Skk
1547bd4a6f5Skk /*
1557bd4a6f5Skk * CondChgd and OvfBuffer fields of global status and overflow control registers
1567bd4a6f5Skk */
1577bd4a6f5Skk #define CONDCHGD (1ULL << 63)
1587bd4a6f5Skk #define OVFBUFFER (1ULL << 62)
1597bd4a6f5Skk #define MASK_CONDCHGD_OVFBUFFER (CONDCHGD | OVFBUFFER)
1607bd4a6f5Skk
1617bd4a6f5Skk #define ALL_STOPPED 0ULL
1627bd4a6f5Skk
1637bd4a6f5Skk #define BITMASK_XBITS(x) ((1ull << (x)) - 1ull)
1647bd4a6f5Skk
1657bd4a6f5Skk /*
1667bd4a6f5Skk * Only the lower 32-bits can be written to in the general-purpose
1677bd4a6f5Skk * counters. The higher bits are extended from bit 31; all ones if
1687bd4a6f5Skk * bit 31 is one and all zeros otherwise.
1697bd4a6f5Skk *
1707bd4a6f5Skk * The fixed-function counters do not have this restriction.
1717bd4a6f5Skk */
1727bd4a6f5Skk #define BITS_EXTENDED_FROM_31 (BITMASK_XBITS(width_gpc) & ~BITMASK_XBITS(31))
1737bd4a6f5Skk
1747bd4a6f5Skk #define WRMSR(msr, value) \
1757bd4a6f5Skk wrmsr((msr), (value)); \
1767bd4a6f5Skk DTRACE_PROBE2(wrmsr, uint64_t, (msr), uint64_t, (value));
1777bd4a6f5Skk
1787bd4a6f5Skk #define RDMSR(msr, value) \
1797bd4a6f5Skk (value) = rdmsr((msr)); \
1807bd4a6f5Skk DTRACE_PROBE2(rdmsr, uint64_t, (msr), uint64_t, (value));
1817bd4a6f5Skk
1827bd4a6f5Skk typedef struct core_pcbe_config {
1837bd4a6f5Skk uint64_t core_rawpic;
1847bd4a6f5Skk uint64_t core_ctl; /* Event Select bits */
1857bd4a6f5Skk uint64_t core_pmc; /* Counter register address */
1867bd4a6f5Skk uint64_t core_pes; /* Event Select register address */
1877bd4a6f5Skk uint_t core_picno;
1887bd4a6f5Skk uint8_t core_pictype; /* CORE_GPC or CORE_FFC */
1897bd4a6f5Skk } core_pcbe_config_t;
1907bd4a6f5Skk
1917bd4a6f5Skk pcbe_ops_t core_pcbe_ops = {
1927bd4a6f5Skk PCBE_VER_1, /* pcbe_ver */
1937bd4a6f5Skk CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE, /* pcbe_caps */
1947bd4a6f5Skk core_pcbe_ncounters, /* pcbe_ncounters */
1957bd4a6f5Skk core_pcbe_impl_name, /* pcbe_impl_name */
1967bd4a6f5Skk core_pcbe_cpuref, /* pcbe_cpuref */
1977bd4a6f5Skk core_pcbe_list_events, /* pcbe_list_events */
1987bd4a6f5Skk core_pcbe_list_attrs, /* pcbe_list_attrs */
1997bd4a6f5Skk core_pcbe_event_coverage, /* pcbe_event_coverage */
2007bd4a6f5Skk core_pcbe_overflow_bitmap, /* pcbe_overflow_bitmap */
2017bd4a6f5Skk core_pcbe_configure, /* pcbe_configure */
2027bd4a6f5Skk core_pcbe_program, /* pcbe_program */
2037bd4a6f5Skk core_pcbe_allstop, /* pcbe_allstop */
2047bd4a6f5Skk core_pcbe_sample, /* pcbe_sample */
2057bd4a6f5Skk core_pcbe_free /* pcbe_free */
2067bd4a6f5Skk };
2077bd4a6f5Skk
208afb806e6SKuriakose Kuruvilla struct nametable_core_uarch {
2097bd4a6f5Skk const char *name;
2107bd4a6f5Skk uint64_t restricted_bits;
2117bd4a6f5Skk uint8_t event_num;
2127bd4a6f5Skk };
2137bd4a6f5Skk
2147bd4a6f5Skk /*
2157bd4a6f5Skk * Counting an event for all cores or all bus agents requires cpc_cpu privileges
2167bd4a6f5Skk */
2177bd4a6f5Skk #define ALL_CORES (1ULL << 15)
2187bd4a6f5Skk #define ALL_AGENTS (1ULL << 13)
2197bd4a6f5Skk
220560e0ee2SKuriakose Kuruvilla struct generic_events {
221560e0ee2SKuriakose Kuruvilla const char *name;
222560e0ee2SKuriakose Kuruvilla uint8_t event_num;
223560e0ee2SKuriakose Kuruvilla uint8_t umask;
224560e0ee2SKuriakose Kuruvilla };
225560e0ee2SKuriakose Kuruvilla
226560e0ee2SKuriakose Kuruvilla static const struct generic_events cmn_generic_events[] = {
227560e0ee2SKuriakose Kuruvilla { "PAPI_tot_cyc", 0x3c, 0x00 }, /* cpu_clk_unhalted.thread_p/core */
228560e0ee2SKuriakose Kuruvilla { "PAPI_tot_ins", 0xc0, 0x00 }, /* inst_retired.any_p */
229560e0ee2SKuriakose Kuruvilla { "PAPI_br_ins", 0xc4, 0x0c }, /* br_inst_retired.taken */
230560e0ee2SKuriakose Kuruvilla { "PAPI_br_msp", 0xc5, 0x00 }, /* br_inst_retired.mispred */
231560e0ee2SKuriakose Kuruvilla { "PAPI_br_ntk", 0xc4, 0x03 },
232560e0ee2SKuriakose Kuruvilla /* br_inst_retired.pred_not_taken|pred_taken */
233560e0ee2SKuriakose Kuruvilla { "PAPI_br_prc", 0xc4, 0x05 },
234560e0ee2SKuriakose Kuruvilla /* br_inst_retired.pred_not_taken|pred_taken */
235560e0ee2SKuriakose Kuruvilla { "PAPI_hw_int", 0xc8, 0x00 }, /* hw_int_rvc */
236560e0ee2SKuriakose Kuruvilla { "PAPI_tot_iis", 0xaa, 0x01 }, /* macro_insts.decoded */
237560e0ee2SKuriakose Kuruvilla { "PAPI_l1_dca", 0x43, 0x01 }, /* l1d_all_ref */
238560e0ee2SKuriakose Kuruvilla { "PAPI_l1_icm", 0x81, 0x00 }, /* l1i_misses */
239560e0ee2SKuriakose Kuruvilla { "PAPI_l1_icr", 0x80, 0x00 }, /* l1i_reads */
240560e0ee2SKuriakose Kuruvilla { "PAPI_l1_tcw", 0x41, 0x0f }, /* l1d_cache_st.mesi */
241560e0ee2SKuriakose Kuruvilla { "PAPI_l2_stm", 0x2a, 0x41 }, /* l2_st.self.i_state */
242560e0ee2SKuriakose Kuruvilla { "PAPI_l2_tca", 0x2e, 0x4f }, /* l2_rqsts.self.demand.mesi */
243560e0ee2SKuriakose Kuruvilla { "PAPI_l2_tch", 0x2e, 0x4e }, /* l2_rqsts.mes */
244560e0ee2SKuriakose Kuruvilla { "PAPI_l2_tcm", 0x2e, 0x41 }, /* l2_rqsts.self.demand.i_state */
245560e0ee2SKuriakose Kuruvilla { "PAPI_l2_tcw", 0x2a, 0x4f }, /* l2_st.self.mesi */
246560e0ee2SKuriakose Kuruvilla { "PAPI_ld_ins", 0xc0, 0x01 }, /* inst_retired.loads */
247560e0ee2SKuriakose Kuruvilla { "PAPI_lst_ins", 0xc0, 0x03 }, /* inst_retired.loads|stores */
248560e0ee2SKuriakose Kuruvilla { "PAPI_sr_ins", 0xc0, 0x02 }, /* inst_retired.stores */
249560e0ee2SKuriakose Kuruvilla { "PAPI_tlb_dm", 0x08, 0x01 }, /* dtlb_misses.any */
250560e0ee2SKuriakose Kuruvilla { "PAPI_tlb_im", 0x82, 0x12 }, /* itlb.small_miss|large_miss */
251560e0ee2SKuriakose Kuruvilla { "PAPI_tlb_tl", 0x0c, 0x03 }, /* page_walks */
252560e0ee2SKuriakose Kuruvilla { "", NT_END, 0 }
253560e0ee2SKuriakose Kuruvilla };
254560e0ee2SKuriakose Kuruvilla
255560e0ee2SKuriakose Kuruvilla static const struct generic_events generic_events_pic0[] = {
256560e0ee2SKuriakose Kuruvilla { "PAPI_l1_dcm", 0xcb, 0x01 }, /* mem_load_retired.l1d_miss */
257560e0ee2SKuriakose Kuruvilla { "", NT_END, 0 }
258560e0ee2SKuriakose Kuruvilla };
259560e0ee2SKuriakose Kuruvilla
260a18ddb3cSKuriakose Kuruvilla /*
261a18ddb3cSKuriakose Kuruvilla * The events listed in the following table can be counted on all
262afb806e6SKuriakose Kuruvilla * general-purpose counters on processors that are of Penryn and Merom Family
263a18ddb3cSKuriakose Kuruvilla */
264afb806e6SKuriakose Kuruvilla static const struct nametable_core_uarch cmn_gpc_events_core_uarch[] = {
2657bd4a6f5Skk /* Alphabetical order of event name */
2667bd4a6f5Skk
2677bd4a6f5Skk { "baclears", 0x0, 0xe6 },
2687bd4a6f5Skk { "bogus_br", 0x0, 0xe4 },
2697bd4a6f5Skk { "br_bac_missp_exec", 0x0, 0x8a },
2707bd4a6f5Skk
2717bd4a6f5Skk { "br_call_exec", 0x0, 0x92 },
2727bd4a6f5Skk { "br_call_missp_exec", 0x0, 0x93 },
2737bd4a6f5Skk { "br_cnd_exec", 0x0, 0x8b },
2747bd4a6f5Skk
2757bd4a6f5Skk { "br_cnd_missp_exec", 0x0, 0x8c },
2767bd4a6f5Skk { "br_ind_call_exec", 0x0, 0x94 },
2777bd4a6f5Skk { "br_ind_exec", 0x0, 0x8d },
2787bd4a6f5Skk
2797bd4a6f5Skk { "br_ind_missp_exec", 0x0, 0x8e },
2807bd4a6f5Skk { "br_inst_decoded", 0x0, 0xe0 },
2817bd4a6f5Skk { "br_inst_exec", 0x0, 0x88 },
2827bd4a6f5Skk
2837bd4a6f5Skk { "br_inst_retired", 0x0, 0xc4 },
2847bd4a6f5Skk { "br_inst_retired_mispred", 0x0, 0xc5 },
2857bd4a6f5Skk { "br_missp_exec", 0x0, 0x89 },
2867bd4a6f5Skk
2877bd4a6f5Skk { "br_ret_bac_missp_exec", 0x0, 0x91 },
2887bd4a6f5Skk { "br_ret_exec", 0x0, 0x8f },
2897bd4a6f5Skk { "br_ret_missp_exec", 0x0, 0x90 },
2907bd4a6f5Skk
2917bd4a6f5Skk { "br_tkn_bubble_1", 0x0, 0x97 },
2927bd4a6f5Skk { "br_tkn_bubble_2", 0x0, 0x98 },
2937bd4a6f5Skk { "bus_bnr_drv", ALL_AGENTS, 0x61 },
2947bd4a6f5Skk
2957bd4a6f5Skk { "bus_data_rcv", ALL_CORES, 0x64 },
2967bd4a6f5Skk { "bus_drdy_clocks", ALL_AGENTS, 0x62 },
2977bd4a6f5Skk { "bus_hit_drv", ALL_AGENTS, 0x7a },
2987bd4a6f5Skk
2997bd4a6f5Skk { "bus_hitm_drv", ALL_AGENTS, 0x7b },
3007bd4a6f5Skk { "bus_io_wait", ALL_CORES, 0x7f },
3017bd4a6f5Skk { "bus_lock_clocks", ALL_CORES | ALL_AGENTS, 0x63 },
3027bd4a6f5Skk
3037bd4a6f5Skk { "bus_request_outstanding", ALL_CORES | ALL_AGENTS, 0x60 },
3047bd4a6f5Skk { "bus_trans_any", ALL_CORES | ALL_AGENTS, 0x70 },
3057bd4a6f5Skk { "bus_trans_brd", ALL_CORES | ALL_AGENTS, 0x65 },
3067bd4a6f5Skk
3077bd4a6f5Skk { "bus_trans_burst", ALL_CORES | ALL_AGENTS, 0x6e },
3087bd4a6f5Skk { "bus_trans_def", ALL_CORES | ALL_AGENTS, 0x6d },
3097bd4a6f5Skk { "bus_trans_ifetch", ALL_CORES | ALL_AGENTS, 0x68 },
3107bd4a6f5Skk
3117bd4a6f5Skk { "bus_trans_inval", ALL_CORES | ALL_AGENTS, 0x69 },
3127bd4a6f5Skk { "bus_trans_io", ALL_CORES | ALL_AGENTS, 0x6c },
3137bd4a6f5Skk { "bus_trans_mem", ALL_CORES | ALL_AGENTS, 0x6f },
3147bd4a6f5Skk
3157bd4a6f5Skk { "bus_trans_p", ALL_CORES | ALL_AGENTS, 0x6b },
3167bd4a6f5Skk { "bus_trans_pwr", ALL_CORES | ALL_AGENTS, 0x6a },
3177bd4a6f5Skk { "bus_trans_rfo", ALL_CORES | ALL_AGENTS, 0x66 },
3187bd4a6f5Skk
3197bd4a6f5Skk { "bus_trans_wb", ALL_CORES | ALL_AGENTS, 0x67 },
3207bd4a6f5Skk { "busq_empty", ALL_CORES, 0x7d },
3217bd4a6f5Skk { "cmp_snoop", ALL_CORES, 0x78 },
3227bd4a6f5Skk
3237bd4a6f5Skk { "cpu_clk_unhalted", 0x0, 0x3c },
3247bd4a6f5Skk { "cycles_int", 0x0, 0xc6 },
3257bd4a6f5Skk { "cycles_l1i_mem_stalled", 0x0, 0x86 },
3267bd4a6f5Skk
3277bd4a6f5Skk { "dtlb_misses", 0x0, 0x08 },
3287bd4a6f5Skk { "eist_trans", 0x0, 0x3a },
3297bd4a6f5Skk { "esp", 0x0, 0xab },
3307bd4a6f5Skk
3317bd4a6f5Skk { "ext_snoop", ALL_AGENTS, 0x77 },
3327bd4a6f5Skk { "fp_mmx_trans", 0x0, 0xcc },
3337bd4a6f5Skk { "hw_int_rcv", 0x0, 0xc8 },
3347bd4a6f5Skk
3357bd4a6f5Skk { "ild_stall", 0x0, 0x87 },
3367bd4a6f5Skk { "inst_queue", 0x0, 0x83 },
3377bd4a6f5Skk { "inst_retired", 0x0, 0xc0 },
3387bd4a6f5Skk
3397bd4a6f5Skk { "itlb", 0x0, 0x82 },
3407bd4a6f5Skk { "itlb_miss_retired", 0x0, 0xc9 },
3417bd4a6f5Skk { "l1d_all_ref", 0x0, 0x43 },
3427bd4a6f5Skk
3437bd4a6f5Skk { "l1d_cache_ld", 0x0, 0x40 },
3447bd4a6f5Skk { "l1d_cache_lock", 0x0, 0x42 },
3457bd4a6f5Skk { "l1d_cache_st", 0x0, 0x41 },
3467bd4a6f5Skk
3477bd4a6f5Skk { "l1d_m_evict", 0x0, 0x47 },
3487bd4a6f5Skk { "l1d_m_repl", 0x0, 0x46 },
3497bd4a6f5Skk { "l1d_pend_miss", 0x0, 0x48 },
3507bd4a6f5Skk
3517bd4a6f5Skk { "l1d_prefetch", 0x0, 0x4e },
3527bd4a6f5Skk { "l1d_repl", 0x0, 0x45 },
3537bd4a6f5Skk { "l1d_split", 0x0, 0x49 },
3547bd4a6f5Skk
3557bd4a6f5Skk { "l1i_misses", 0x0, 0x81 },
3567bd4a6f5Skk { "l1i_reads", 0x0, 0x80 },
3577bd4a6f5Skk { "l2_ads", ALL_CORES, 0x21 },
3587bd4a6f5Skk
3597bd4a6f5Skk { "l2_dbus_busy_rd", ALL_CORES, 0x23 },
3607bd4a6f5Skk { "l2_ifetch", ALL_CORES, 0x28 },
3617bd4a6f5Skk { "l2_ld", ALL_CORES, 0x29 },
3627bd4a6f5Skk
3637bd4a6f5Skk { "l2_lines_in", ALL_CORES, 0x24 },
3647bd4a6f5Skk { "l2_lines_out", ALL_CORES, 0x26 },
3657bd4a6f5Skk { "l2_lock", ALL_CORES, 0x2b },
3667bd4a6f5Skk
3677bd4a6f5Skk { "l2_m_lines_in", ALL_CORES, 0x25 },
3687bd4a6f5Skk { "l2_m_lines_out", ALL_CORES, 0x27 },
3697bd4a6f5Skk { "l2_no_req", ALL_CORES, 0x32 },
3707bd4a6f5Skk
3717bd4a6f5Skk { "l2_reject_busq", ALL_CORES, 0x30 },
3727bd4a6f5Skk { "l2_rqsts", ALL_CORES, 0x2e },
3737bd4a6f5Skk { "l2_st", ALL_CORES, 0x2a },
3747bd4a6f5Skk
3757bd4a6f5Skk { "load_block", 0x0, 0x03 },
3767bd4a6f5Skk { "load_hit_pre", 0x0, 0x4c },
3777bd4a6f5Skk { "machine_nukes", 0x0, 0xc3 },
3787bd4a6f5Skk
3797bd4a6f5Skk { "macro_insts", 0x0, 0xaa },
3807bd4a6f5Skk { "memory_disambiguation", 0x0, 0x09 },
381a18ddb3cSKuriakose Kuruvilla { "misalign_mem_ref", 0x0, 0x05 },
3827bd4a6f5Skk { "page_walks", 0x0, 0x0c },
3837bd4a6f5Skk
3847bd4a6f5Skk { "pref_rqsts_dn", 0x0, 0xf8 },
3857bd4a6f5Skk { "pref_rqsts_up", 0x0, 0xf0 },
3867bd4a6f5Skk { "rat_stalls", 0x0, 0xd2 },
3877bd4a6f5Skk
3887bd4a6f5Skk { "resource_stalls", 0x0, 0xdc },
3897bd4a6f5Skk { "rs_uops_dispatched", 0x0, 0xa0 },
3907bd4a6f5Skk { "seg_reg_renames", 0x0, 0xd5 },
3917bd4a6f5Skk
3927bd4a6f5Skk { "seg_rename_stalls", 0x0, 0xd4 },
3937bd4a6f5Skk { "segment_reg_loads", 0x0, 0x06 },
3947bd4a6f5Skk { "simd_assist", 0x0, 0xcd },
3957bd4a6f5Skk
3967bd4a6f5Skk { "simd_comp_inst_retired", 0x0, 0xca },
3977bd4a6f5Skk { "simd_inst_retired", 0x0, 0xc7 },
3987bd4a6f5Skk { "simd_instr_retired", 0x0, 0xce },
3997bd4a6f5Skk
4007bd4a6f5Skk { "simd_sat_instr_retired", 0x0, 0xcf },
4017bd4a6f5Skk { "simd_sat_uop_exec", 0x0, 0xb1 },
4027bd4a6f5Skk { "simd_uop_type_exec", 0x0, 0xb3 },
4037bd4a6f5Skk
4047bd4a6f5Skk { "simd_uops_exec", 0x0, 0xb0 },
4057bd4a6f5Skk { "snoop_stall_drv", ALL_CORES | ALL_AGENTS, 0x7e },
4067bd4a6f5Skk { "sse_pre_exec", 0x0, 0x07 },
4077bd4a6f5Skk
4087bd4a6f5Skk { "sse_pre_miss", 0x0, 0x4b },
4097bd4a6f5Skk { "store_block", 0x0, 0x04 },
4107bd4a6f5Skk { "thermal_trip", 0x0, 0x3b },
4117bd4a6f5Skk
4127bd4a6f5Skk { "uops_retired", 0x0, 0xc2 },
4137bd4a6f5Skk { "x87_ops_retired", 0x0, 0xc1 },
4147bd4a6f5Skk { "", 0x0, NT_END }
4157bd4a6f5Skk };
4167bd4a6f5Skk
4177bd4a6f5Skk /*
4187bd4a6f5Skk * If any of the pic specific events require privileges, make sure to add a
4197bd4a6f5Skk * check in configure_gpc() to find whether an event hard-coded as a number by
4207bd4a6f5Skk * the user has any privilege requirements
4217bd4a6f5Skk */
422afb806e6SKuriakose Kuruvilla static const struct nametable_core_uarch pic0_events[] = {
4237bd4a6f5Skk /* Alphabetical order of event name */
4247bd4a6f5Skk
4257bd4a6f5Skk { "cycles_div_busy", 0x0, 0x14 },
4267bd4a6f5Skk { "fp_comp_ops_exe", 0x0, 0x10 },
4277bd4a6f5Skk { "idle_during_div", 0x0, 0x18 },
4287bd4a6f5Skk
4297bd4a6f5Skk { "mem_load_retired", 0x0, 0xcb },
4307bd4a6f5Skk { "rs_uops_dispatched_port", 0x0, 0xa1 },
4317bd4a6f5Skk { "", 0x0, NT_END }
4327bd4a6f5Skk };
4337bd4a6f5Skk
434afb806e6SKuriakose Kuruvilla static const struct nametable_core_uarch pic1_events[] = {
4357bd4a6f5Skk /* Alphabetical order of event name */
4367bd4a6f5Skk
4377bd4a6f5Skk { "delayed_bypass", 0x0, 0x19 },
4387bd4a6f5Skk { "div", 0x0, 0x13 },
4397bd4a6f5Skk { "fp_assist", 0x0, 0x11 },
4407bd4a6f5Skk
4417bd4a6f5Skk { "mul", 0x0, 0x12 },
4427bd4a6f5Skk { "", 0x0, NT_END }
4437bd4a6f5Skk };
4447bd4a6f5Skk
4456323db19SKrishnendu Sadhukhan - Sun Microsystems /* FFC entries must be in order */
446560e0ee2SKuriakose Kuruvilla static char *ffc_names_non_htt[] = {
4476323db19SKrishnendu Sadhukhan - Sun Microsystems "instr_retired.any",
4486323db19SKrishnendu Sadhukhan - Sun Microsystems "cpu_clk_unhalted.core",
4496323db19SKrishnendu Sadhukhan - Sun Microsystems "cpu_clk_unhalted.ref",
4506323db19SKrishnendu Sadhukhan - Sun Microsystems NULL
4516323db19SKrishnendu Sadhukhan - Sun Microsystems };
4526323db19SKrishnendu Sadhukhan - Sun Microsystems
453560e0ee2SKuriakose Kuruvilla static char *ffc_names_htt[] = {
4546323db19SKrishnendu Sadhukhan - Sun Microsystems "instr_retired.any",
455a18ddb3cSKuriakose Kuruvilla "cpu_clk_unhalted.thread",
4567bd4a6f5Skk "cpu_clk_unhalted.ref",
4577bd4a6f5Skk NULL
4587bd4a6f5Skk };
4597bd4a6f5Skk
460560e0ee2SKuriakose Kuruvilla static char *ffc_genericnames[] = {
461560e0ee2SKuriakose Kuruvilla "PAPI_tot_ins",
462560e0ee2SKuriakose Kuruvilla "PAPI_tot_cyc",
463560e0ee2SKuriakose Kuruvilla "",
464560e0ee2SKuriakose Kuruvilla NULL
465560e0ee2SKuriakose Kuruvilla };
4666323db19SKrishnendu Sadhukhan - Sun Microsystems
467560e0ee2SKuriakose Kuruvilla static char **ffc_names = NULL;
468560e0ee2SKuriakose Kuruvilla static char **ffc_allnames = NULL;
469e7334537SKrishnendu Sadhukhan - Sun Microsystems static char **gpc_names = NULL;
470a18ddb3cSKuriakose Kuruvilla static uint32_t versionid;
4717bd4a6f5Skk static uint64_t num_gpc;
4727bd4a6f5Skk static uint64_t width_gpc;
4737bd4a6f5Skk static uint64_t mask_gpc;
4747bd4a6f5Skk static uint64_t num_ffc;
4757bd4a6f5Skk static uint64_t width_ffc;
4767bd4a6f5Skk static uint64_t mask_ffc;
4777bd4a6f5Skk static uint_t total_pmc;
4787bd4a6f5Skk static uint64_t control_ffc;
4797bd4a6f5Skk static uint64_t control_gpc;
4807bd4a6f5Skk static uint64_t control_mask;
481a18ddb3cSKuriakose Kuruvilla static uint32_t arch_events_vector;
4827bd4a6f5Skk
483a18ddb3cSKuriakose Kuruvilla #define IMPL_NAME_LEN 100
484a18ddb3cSKuriakose Kuruvilla static char core_impl_name[IMPL_NAME_LEN];
4857bd4a6f5Skk
4867bd4a6f5Skk static const char *core_cpuref =
4877e3dbbacSRobert Mustacchi "See https://download.01.org/perfmon/index/ or Chapers 18 and 19 " \
4887e3dbbacSRobert Mustacchi "of the \"Intel 64 and IA-32 Architectures Software Developer's " \
4897e3dbbacSRobert Mustacchi "Manual Volume 3: System Programming Guide\" Order Number: " \
4907e3dbbacSRobert Mustacchi "325384-062US, March 2017.";
491a18ddb3cSKuriakose Kuruvilla
492a18ddb3cSKuriakose Kuruvilla
4936323db19SKrishnendu Sadhukhan - Sun Microsystems /* Architectural events */
4946323db19SKrishnendu Sadhukhan - Sun Microsystems #define ARCH_EVENTS_COMMON \
4956323db19SKrishnendu Sadhukhan - Sun Microsystems { 0xc0, 0x00, C_ALL, "inst_retired.any_p" }, \
4966323db19SKrishnendu Sadhukhan - Sun Microsystems { 0x3c, 0x01, C_ALL, "cpu_clk_unhalted.ref_p" }, \
4976323db19SKrishnendu Sadhukhan - Sun Microsystems { 0x2e, 0x4f, C_ALL, "longest_lat_cache.reference" }, \
4986323db19SKrishnendu Sadhukhan - Sun Microsystems { 0x2e, 0x41, C_ALL, "longest_lat_cache.miss" }, \
4996323db19SKrishnendu Sadhukhan - Sun Microsystems { 0xc4, 0x00, C_ALL, "br_inst_retired.all_branches" }, \
5006323db19SKrishnendu Sadhukhan - Sun Microsystems { 0xc5, 0x00, C_ALL, "br_misp_retired.all_branches" }
5016323db19SKrishnendu Sadhukhan - Sun Microsystems
502560e0ee2SKuriakose Kuruvilla static const struct events_table_t arch_events_table_non_htt[] = {
5036323db19SKrishnendu Sadhukhan - Sun Microsystems { 0x3c, 0x00, C_ALL, "cpu_clk_unhalted.core" },
5046323db19SKrishnendu Sadhukhan - Sun Microsystems ARCH_EVENTS_COMMON
5056323db19SKrishnendu Sadhukhan - Sun Microsystems };
506a18ddb3cSKuriakose Kuruvilla
507560e0ee2SKuriakose Kuruvilla static const struct events_table_t arch_events_table_htt[] = {
5086323db19SKrishnendu Sadhukhan - Sun Microsystems { 0x3c, 0x00, C_ALL, "cpu_clk_unhalted.thread_p" },
5096323db19SKrishnendu Sadhukhan - Sun Microsystems ARCH_EVENTS_COMMON
510a18ddb3cSKuriakose Kuruvilla };
511a18ddb3cSKuriakose Kuruvilla
512560e0ee2SKuriakose Kuruvilla static char *arch_genevents_table[] = {
513560e0ee2SKuriakose Kuruvilla "PAPI_tot_cyc", /* cpu_clk_unhalted.thread_p/core */
514560e0ee2SKuriakose Kuruvilla "PAPI_tot_ins", /* inst_retired.any_p */
515560e0ee2SKuriakose Kuruvilla "", /* cpu_clk_unhalted.ref_p */
516560e0ee2SKuriakose Kuruvilla "", /* longest_lat_cache.reference */
517560e0ee2SKuriakose Kuruvilla "", /* longest_lat_cache.miss */
518560e0ee2SKuriakose Kuruvilla "", /* br_inst_retired.all_branches */
519560e0ee2SKuriakose Kuruvilla "", /* br_misp_retired.all_branches */
520560e0ee2SKuriakose Kuruvilla };
521560e0ee2SKuriakose Kuruvilla
522560e0ee2SKuriakose Kuruvilla static const struct events_table_t *arch_events_table = NULL;
5236323db19SKrishnendu Sadhukhan - Sun Microsystems static uint64_t known_arch_events;
5246323db19SKrishnendu Sadhukhan - Sun Microsystems static uint64_t known_ffc_num;
525a18ddb3cSKuriakose Kuruvilla static const struct events_table_t *events_table = NULL;
526a18ddb3cSKuriakose Kuruvilla
527a18ddb3cSKuriakose Kuruvilla /*
528a18ddb3cSKuriakose Kuruvilla * Initialize string containing list of supported general-purpose counter
529afb806e6SKuriakose Kuruvilla * events for processors of Penryn and Merom Family
530a18ddb3cSKuriakose Kuruvilla */
531a18ddb3cSKuriakose Kuruvilla static void
pcbe_init_core_uarch()532afb806e6SKuriakose Kuruvilla pcbe_init_core_uarch()
533a18ddb3cSKuriakose Kuruvilla {
534afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *n;
535560e0ee2SKuriakose Kuruvilla const struct generic_events *k;
536afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *picspecific_events;
537560e0ee2SKuriakose Kuruvilla const struct generic_events *picspecific_genericevents;
538a18ddb3cSKuriakose Kuruvilla size_t common_size;
539a18ddb3cSKuriakose Kuruvilla size_t size;
540a18ddb3cSKuriakose Kuruvilla uint64_t i;
541a18ddb3cSKuriakose Kuruvilla
542a18ddb3cSKuriakose Kuruvilla gpc_names = kmem_alloc(num_gpc * sizeof (char *), KM_SLEEP);
543a18ddb3cSKuriakose Kuruvilla
544a18ddb3cSKuriakose Kuruvilla /* Calculate space needed to save all the common event names */
545a18ddb3cSKuriakose Kuruvilla common_size = 0;
546afb806e6SKuriakose Kuruvilla for (n = cmn_gpc_events_core_uarch; n->event_num != NT_END; n++) {
547a18ddb3cSKuriakose Kuruvilla common_size += strlen(n->name) + 1;
548a18ddb3cSKuriakose Kuruvilla }
549a18ddb3cSKuriakose Kuruvilla
550560e0ee2SKuriakose Kuruvilla for (k = cmn_generic_events; k->event_num != NT_END; k++) {
551560e0ee2SKuriakose Kuruvilla common_size += strlen(k->name) + 1;
552560e0ee2SKuriakose Kuruvilla }
553560e0ee2SKuriakose Kuruvilla
554a18ddb3cSKuriakose Kuruvilla for (i = 0; i < num_gpc; i++) {
555a18ddb3cSKuriakose Kuruvilla size = 0;
556560e0ee2SKuriakose Kuruvilla picspecific_genericevents = NULL;
557560e0ee2SKuriakose Kuruvilla
558a18ddb3cSKuriakose Kuruvilla switch (i) {
559a18ddb3cSKuriakose Kuruvilla case 0:
560a18ddb3cSKuriakose Kuruvilla picspecific_events = pic0_events;
561560e0ee2SKuriakose Kuruvilla picspecific_genericevents = generic_events_pic0;
562a18ddb3cSKuriakose Kuruvilla break;
563a18ddb3cSKuriakose Kuruvilla case 1:
564a18ddb3cSKuriakose Kuruvilla picspecific_events = pic1_events;
565a18ddb3cSKuriakose Kuruvilla break;
566a18ddb3cSKuriakose Kuruvilla default:
567a18ddb3cSKuriakose Kuruvilla picspecific_events = NULL;
568a18ddb3cSKuriakose Kuruvilla break;
569a18ddb3cSKuriakose Kuruvilla }
570a18ddb3cSKuriakose Kuruvilla if (picspecific_events != NULL) {
571a18ddb3cSKuriakose Kuruvilla for (n = picspecific_events;
572a18ddb3cSKuriakose Kuruvilla n->event_num != NT_END;
573a18ddb3cSKuriakose Kuruvilla n++) {
574a18ddb3cSKuriakose Kuruvilla size += strlen(n->name) + 1;
575a18ddb3cSKuriakose Kuruvilla }
576a18ddb3cSKuriakose Kuruvilla }
577560e0ee2SKuriakose Kuruvilla if (picspecific_genericevents != NULL) {
578560e0ee2SKuriakose Kuruvilla for (k = picspecific_genericevents;
579560e0ee2SKuriakose Kuruvilla k->event_num != NT_END; k++) {
580560e0ee2SKuriakose Kuruvilla size += strlen(k->name) + 1;
581560e0ee2SKuriakose Kuruvilla }
582560e0ee2SKuriakose Kuruvilla }
583a18ddb3cSKuriakose Kuruvilla
584a18ddb3cSKuriakose Kuruvilla gpc_names[i] =
585a18ddb3cSKuriakose Kuruvilla kmem_alloc(size + common_size + 1, KM_SLEEP);
586a18ddb3cSKuriakose Kuruvilla
587a18ddb3cSKuriakose Kuruvilla gpc_names[i][0] = '\0';
588a18ddb3cSKuriakose Kuruvilla if (picspecific_events != NULL) {
589a18ddb3cSKuriakose Kuruvilla for (n = picspecific_events;
590560e0ee2SKuriakose Kuruvilla n->event_num != NT_END; n++) {
591a18ddb3cSKuriakose Kuruvilla (void) strcat(gpc_names[i], n->name);
592a18ddb3cSKuriakose Kuruvilla (void) strcat(gpc_names[i], ",");
593a18ddb3cSKuriakose Kuruvilla }
594a18ddb3cSKuriakose Kuruvilla }
595560e0ee2SKuriakose Kuruvilla if (picspecific_genericevents != NULL) {
596560e0ee2SKuriakose Kuruvilla for (k = picspecific_genericevents;
597560e0ee2SKuriakose Kuruvilla k->event_num != NT_END; k++) {
598560e0ee2SKuriakose Kuruvilla (void) strcat(gpc_names[i], k->name);
599560e0ee2SKuriakose Kuruvilla (void) strcat(gpc_names[i], ",");
600560e0ee2SKuriakose Kuruvilla }
601560e0ee2SKuriakose Kuruvilla }
602afb806e6SKuriakose Kuruvilla for (n = cmn_gpc_events_core_uarch; n->event_num != NT_END;
603a18ddb3cSKuriakose Kuruvilla n++) {
604a18ddb3cSKuriakose Kuruvilla (void) strcat(gpc_names[i], n->name);
605a18ddb3cSKuriakose Kuruvilla (void) strcat(gpc_names[i], ",");
606a18ddb3cSKuriakose Kuruvilla }
607560e0ee2SKuriakose Kuruvilla for (k = cmn_generic_events; k->event_num != NT_END; k++) {
608560e0ee2SKuriakose Kuruvilla (void) strcat(gpc_names[i], k->name);
609560e0ee2SKuriakose Kuruvilla (void) strcat(gpc_names[i], ",");
610560e0ee2SKuriakose Kuruvilla }
611560e0ee2SKuriakose Kuruvilla
612a18ddb3cSKuriakose Kuruvilla /*
613a18ddb3cSKuriakose Kuruvilla * Remove trailing comma.
614a18ddb3cSKuriakose Kuruvilla */
615a18ddb3cSKuriakose Kuruvilla gpc_names[i][common_size + size - 1] = '\0';
616a18ddb3cSKuriakose Kuruvilla }
617a18ddb3cSKuriakose Kuruvilla }
618a18ddb3cSKuriakose Kuruvilla
6197bd4a6f5Skk static int
core_pcbe_init(void)6207bd4a6f5Skk core_pcbe_init(void)
6217bd4a6f5Skk {
6227bd4a6f5Skk struct cpuid_regs cp;
6237bd4a6f5Skk size_t size;
6247bd4a6f5Skk uint64_t i;
625a18ddb3cSKuriakose Kuruvilla uint64_t j;
626a18ddb3cSKuriakose Kuruvilla uint64_t arch_events_vector_length;
627a18ddb3cSKuriakose Kuruvilla size_t arch_events_string_length;
628c18e9bc3SRobert Mustacchi uint_t model, stepping;
629a18ddb3cSKuriakose Kuruvilla
630a18ddb3cSKuriakose Kuruvilla if (cpuid_getvendor(CPU) != X86_VENDOR_Intel)
631a18ddb3cSKuriakose Kuruvilla return (-1);
632a18ddb3cSKuriakose Kuruvilla
633a18ddb3cSKuriakose Kuruvilla /* Obtain Basic CPUID information */
634a18ddb3cSKuriakose Kuruvilla cp.cp_eax = 0x0;
635a18ddb3cSKuriakose Kuruvilla (void) __cpuid_insn(&cp);
6367bd4a6f5Skk
637a18ddb3cSKuriakose Kuruvilla /* No Architectural Performance Monitoring Leaf returned by CPUID */
638a18ddb3cSKuriakose Kuruvilla if (cp.cp_eax < 0xa) {
6397bd4a6f5Skk return (-1);
640a18ddb3cSKuriakose Kuruvilla }
6417bd4a6f5Skk
6427bd4a6f5Skk /* Obtain the Architectural Performance Monitoring Leaf */
6437bd4a6f5Skk cp.cp_eax = 0xa;
6447bd4a6f5Skk (void) __cpuid_insn(&cp);
6457bd4a6f5Skk
6467bd4a6f5Skk versionid = cp.cp_eax & 0xFF;
6477bd4a6f5Skk
6487bd4a6f5Skk /*
649e7334537SKrishnendu Sadhukhan - Sun Microsystems * Fixed-Function Counters (FFC)
650e7334537SKrishnendu Sadhukhan - Sun Microsystems *
6517bd4a6f5Skk * All Family 6 Model 15 and Model 23 processors have fixed-function
6527bd4a6f5Skk * counters. These counters were made Architectural with
653a18ddb3cSKuriakose Kuruvilla * Family 6 Model 15 Stepping 9.
6547bd4a6f5Skk */
6557bd4a6f5Skk switch (versionid) {
6567bd4a6f5Skk
6577bd4a6f5Skk case 0:
6587bd4a6f5Skk return (-1);
6597bd4a6f5Skk
660a18ddb3cSKuriakose Kuruvilla case 2:
6617bd4a6f5Skk num_ffc = cp.cp_edx & 0x1F;
6627bd4a6f5Skk width_ffc = (cp.cp_edx >> 5) & 0xFF;
6637bd4a6f5Skk
6647bd4a6f5Skk /*
665a18ddb3cSKuriakose Kuruvilla * Some processors have an errata (AW34) where
666a18ddb3cSKuriakose Kuruvilla * versionid is reported as 2 when actually 1.
667a18ddb3cSKuriakose Kuruvilla * In this case, fixed-function counters are
668a18ddb3cSKuriakose Kuruvilla * model-specific as in Version 1.
6697bd4a6f5Skk */
670a18ddb3cSKuriakose Kuruvilla if (num_ffc != 0) {
671a18ddb3cSKuriakose Kuruvilla break;
672a18ddb3cSKuriakose Kuruvilla }
673a18ddb3cSKuriakose Kuruvilla /* FALLTHROUGH */
674a18ddb3cSKuriakose Kuruvilla case 1:
6757bd4a6f5Skk num_ffc = 3;
6767bd4a6f5Skk width_ffc = 40;
677a18ddb3cSKuriakose Kuruvilla versionid = 1;
678a18ddb3cSKuriakose Kuruvilla break;
679a18ddb3cSKuriakose Kuruvilla
680a18ddb3cSKuriakose Kuruvilla default:
681a18ddb3cSKuriakose Kuruvilla num_ffc = cp.cp_edx & 0x1F;
682a18ddb3cSKuriakose Kuruvilla width_ffc = (cp.cp_edx >> 5) & 0xFF;
6837bd4a6f5Skk break;
6847bd4a6f5Skk }
6857bd4a6f5Skk
686a18ddb3cSKuriakose Kuruvilla
6877bd4a6f5Skk if (num_ffc >= 64)
6887bd4a6f5Skk return (-1);
6897bd4a6f5Skk
6906323db19SKrishnendu Sadhukhan - Sun Microsystems /* Set HTT-specific names of architectural & FFC events */
6917417cfdeSKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_HTT)) {
6926323db19SKrishnendu Sadhukhan - Sun Microsystems ffc_names = ffc_names_htt;
6936323db19SKrishnendu Sadhukhan - Sun Microsystems arch_events_table = arch_events_table_htt;
6946323db19SKrishnendu Sadhukhan - Sun Microsystems known_arch_events =
6956323db19SKrishnendu Sadhukhan - Sun Microsystems sizeof (arch_events_table_htt) /
6966323db19SKrishnendu Sadhukhan - Sun Microsystems sizeof (struct events_table_t);
6976323db19SKrishnendu Sadhukhan - Sun Microsystems known_ffc_num =
6986323db19SKrishnendu Sadhukhan - Sun Microsystems sizeof (ffc_names_htt) / sizeof (char *);
6996323db19SKrishnendu Sadhukhan - Sun Microsystems } else {
7006323db19SKrishnendu Sadhukhan - Sun Microsystems ffc_names = ffc_names_non_htt;
7016323db19SKrishnendu Sadhukhan - Sun Microsystems arch_events_table = arch_events_table_non_htt;
7026323db19SKrishnendu Sadhukhan - Sun Microsystems known_arch_events =
7036323db19SKrishnendu Sadhukhan - Sun Microsystems sizeof (arch_events_table_non_htt) /
7046323db19SKrishnendu Sadhukhan - Sun Microsystems sizeof (struct events_table_t);
7056323db19SKrishnendu Sadhukhan - Sun Microsystems known_ffc_num =
7066323db19SKrishnendu Sadhukhan - Sun Microsystems sizeof (ffc_names_non_htt) / sizeof (char *);
7076323db19SKrishnendu Sadhukhan - Sun Microsystems }
7086323db19SKrishnendu Sadhukhan - Sun Microsystems
7096323db19SKrishnendu Sadhukhan - Sun Microsystems if (num_ffc >= known_ffc_num) {
7107bd4a6f5Skk /*
7117bd4a6f5Skk * The system seems to have more fixed-function counters than
7127bd4a6f5Skk * what this PCBE is able to handle correctly. Default to the
7137bd4a6f5Skk * maximum number of fixed-function counters that this driver
7147bd4a6f5Skk * is aware of.
7157bd4a6f5Skk */
7166323db19SKrishnendu Sadhukhan - Sun Microsystems num_ffc = known_ffc_num - 1;
7177bd4a6f5Skk }
7187bd4a6f5Skk
7197bd4a6f5Skk mask_ffc = BITMASK_XBITS(width_ffc);
720e7334537SKrishnendu Sadhukhan - Sun Microsystems control_ffc = BITMASK_XBITS(num_ffc);
7217bd4a6f5Skk
722e7334537SKrishnendu Sadhukhan - Sun Microsystems /*
723e7334537SKrishnendu Sadhukhan - Sun Microsystems * General Purpose Counters (GPC)
724e7334537SKrishnendu Sadhukhan - Sun Microsystems */
7257bd4a6f5Skk num_gpc = (cp.cp_eax >> 8) & 0xFF;
7267bd4a6f5Skk width_gpc = (cp.cp_eax >> 16) & 0xFF;
7277bd4a6f5Skk
7287bd4a6f5Skk if (num_gpc >= 64)
7297bd4a6f5Skk return (-1);
7307bd4a6f5Skk
7317bd4a6f5Skk mask_gpc = BITMASK_XBITS(width_gpc);
7327bd4a6f5Skk
7337bd4a6f5Skk control_gpc = BITMASK_XBITS(num_gpc);
7347bd4a6f5Skk
7357bd4a6f5Skk control_mask = (control_ffc << 32) | control_gpc;
7367bd4a6f5Skk
737e7334537SKrishnendu Sadhukhan - Sun Microsystems total_pmc = num_gpc + num_ffc;
7387bd4a6f5Skk if (total_pmc > 64) {
7397bd4a6f5Skk /* Too wide for the overflow bitmap */
7407bd4a6f5Skk return (-1);
7417bd4a6f5Skk }
7427bd4a6f5Skk
743560e0ee2SKuriakose Kuruvilla /* FFC names */
744560e0ee2SKuriakose Kuruvilla ffc_allnames = kmem_alloc(num_ffc * sizeof (char *), KM_SLEEP);
745560e0ee2SKuriakose Kuruvilla for (i = 0; i < num_ffc; i++) {
746560e0ee2SKuriakose Kuruvilla ffc_allnames[i] = kmem_alloc(
747560e0ee2SKuriakose Kuruvilla strlen(ffc_names[i]) + strlen(ffc_genericnames[i]) + 2,
748560e0ee2SKuriakose Kuruvilla KM_SLEEP);
749560e0ee2SKuriakose Kuruvilla
750560e0ee2SKuriakose Kuruvilla ffc_allnames[i][0] = '\0';
751560e0ee2SKuriakose Kuruvilla (void) strcat(ffc_allnames[i], ffc_names[i]);
752560e0ee2SKuriakose Kuruvilla
753560e0ee2SKuriakose Kuruvilla /* Check if this ffc has a generic name */
754560e0ee2SKuriakose Kuruvilla if (strcmp(ffc_genericnames[i], "") != 0) {
755560e0ee2SKuriakose Kuruvilla (void) strcat(ffc_allnames[i], ",");
756560e0ee2SKuriakose Kuruvilla (void) strcat(ffc_allnames[i], ffc_genericnames[i]);
757560e0ee2SKuriakose Kuruvilla }
758560e0ee2SKuriakose Kuruvilla }
759560e0ee2SKuriakose Kuruvilla
760560e0ee2SKuriakose Kuruvilla /* GPC events for Family 6 Models 15, 23 and 29 only */
761a18ddb3cSKuriakose Kuruvilla if ((cpuid_getfamily(CPU) == 6) &&
762afb806e6SKuriakose Kuruvilla ((cpuid_getmodel(CPU) == 15) || (cpuid_getmodel(CPU) == 23) ||
763afb806e6SKuriakose Kuruvilla (cpuid_getmodel(CPU) == 29))) {
764a18ddb3cSKuriakose Kuruvilla (void) snprintf(core_impl_name, IMPL_NAME_LEN,
765a18ddb3cSKuriakose Kuruvilla "Core Microarchitecture");
766afb806e6SKuriakose Kuruvilla pcbe_init_core_uarch();
767a18ddb3cSKuriakose Kuruvilla return (0);
768a18ddb3cSKuriakose Kuruvilla }
769a18ddb3cSKuriakose Kuruvilla
770a18ddb3cSKuriakose Kuruvilla (void) snprintf(core_impl_name, IMPL_NAME_LEN,
771a18ddb3cSKuriakose Kuruvilla "Intel Arch PerfMon v%d on Family %d Model %d",
772a18ddb3cSKuriakose Kuruvilla versionid, cpuid_getfamily(CPU), cpuid_getmodel(CPU));
773a18ddb3cSKuriakose Kuruvilla
774e7334537SKrishnendu Sadhukhan - Sun Microsystems /*
775e7334537SKrishnendu Sadhukhan - Sun Microsystems * Architectural events
776e7334537SKrishnendu Sadhukhan - Sun Microsystems */
777a18ddb3cSKuriakose Kuruvilla arch_events_vector_length = (cp.cp_eax >> 24) & 0xFF;
778a18ddb3cSKuriakose Kuruvilla
779a18ddb3cSKuriakose Kuruvilla ASSERT(known_arch_events == arch_events_vector_length);
780a18ddb3cSKuriakose Kuruvilla
781a18ddb3cSKuriakose Kuruvilla /*
782a18ddb3cSKuriakose Kuruvilla * To handle the case where a new performance monitoring setup is run
783a18ddb3cSKuriakose Kuruvilla * on a non-debug kernel
784a18ddb3cSKuriakose Kuruvilla */
785a18ddb3cSKuriakose Kuruvilla if (known_arch_events > arch_events_vector_length) {
786a18ddb3cSKuriakose Kuruvilla known_arch_events = arch_events_vector_length;
787a18ddb3cSKuriakose Kuruvilla } else {
788a18ddb3cSKuriakose Kuruvilla arch_events_vector_length = known_arch_events;
789a18ddb3cSKuriakose Kuruvilla }
790a18ddb3cSKuriakose Kuruvilla
791a18ddb3cSKuriakose Kuruvilla arch_events_vector = cp.cp_ebx &
792a18ddb3cSKuriakose Kuruvilla BITMASK_XBITS(arch_events_vector_length);
793a18ddb3cSKuriakose Kuruvilla
794e7334537SKrishnendu Sadhukhan - Sun Microsystems /*
795e7334537SKrishnendu Sadhukhan - Sun Microsystems * Process architectural and non-architectural events using GPC
796e7334537SKrishnendu Sadhukhan - Sun Microsystems */
7977bd4a6f5Skk if (num_gpc > 0) {
798a18ddb3cSKuriakose Kuruvilla
7997bd4a6f5Skk gpc_names = kmem_alloc(num_gpc * sizeof (char *), KM_SLEEP);
8007bd4a6f5Skk
801a18ddb3cSKuriakose Kuruvilla /* Calculate space required for the architectural gpc events */
802a18ddb3cSKuriakose Kuruvilla arch_events_string_length = 0;
803a18ddb3cSKuriakose Kuruvilla for (i = 0; i < known_arch_events; i++) {
804a18ddb3cSKuriakose Kuruvilla if (((1U << i) & arch_events_vector) == 0) {
805a18ddb3cSKuriakose Kuruvilla arch_events_string_length +=
806a18ddb3cSKuriakose Kuruvilla strlen(arch_events_table[i].name) + 1;
807560e0ee2SKuriakose Kuruvilla if (strcmp(arch_genevents_table[i], "") != 0) {
808560e0ee2SKuriakose Kuruvilla arch_events_string_length +=
809560e0ee2SKuriakose Kuruvilla strlen(arch_genevents_table[i]) + 1;
810560e0ee2SKuriakose Kuruvilla }
811a18ddb3cSKuriakose Kuruvilla }
812a18ddb3cSKuriakose Kuruvilla }
813a18ddb3cSKuriakose Kuruvilla
814e7334537SKrishnendu Sadhukhan - Sun Microsystems /* Non-architectural events list */
81503dbaac7SKuriakose Kuruvilla model = cpuid_getmodel(CPU);
816c18e9bc3SRobert Mustacchi stepping = cpuid_getstep(CPU);
817c18e9bc3SRobert Mustacchi events_table = core_cpcgen_table(model, stepping);
8187bd4a6f5Skk
8197bd4a6f5Skk for (i = 0; i < num_gpc; i++) {
820a18ddb3cSKuriakose Kuruvilla
821e7334537SKrishnendu Sadhukhan - Sun Microsystems /*
822e7334537SKrishnendu Sadhukhan - Sun Microsystems * Determine length of all supported event names
823e7334537SKrishnendu Sadhukhan - Sun Microsystems * (architectural + non-architectural)
824e7334537SKrishnendu Sadhukhan - Sun Microsystems */
825a18ddb3cSKuriakose Kuruvilla size = arch_events_string_length;
826a18ddb3cSKuriakose Kuruvilla for (j = 0; events_table != NULL &&
827a18ddb3cSKuriakose Kuruvilla events_table[j].eventselect != NT_END;
828a18ddb3cSKuriakose Kuruvilla j++) {
829a18ddb3cSKuriakose Kuruvilla if (C(i) & events_table[j].supported_counters) {
830a18ddb3cSKuriakose Kuruvilla size += strlen(events_table[j].name) +
831a18ddb3cSKuriakose Kuruvilla 1;
8327bd4a6f5Skk }
8337bd4a6f5Skk }
8347bd4a6f5Skk
835a18ddb3cSKuriakose Kuruvilla /* Allocate memory for this pics list */
836a18ddb3cSKuriakose Kuruvilla gpc_names[i] = kmem_alloc(size + 1, KM_SLEEP);
8377bd4a6f5Skk gpc_names[i][0] = '\0';
838a18ddb3cSKuriakose Kuruvilla if (size == 0) {
839a18ddb3cSKuriakose Kuruvilla continue;
840a18ddb3cSKuriakose Kuruvilla }
841a18ddb3cSKuriakose Kuruvilla
842e7334537SKrishnendu Sadhukhan - Sun Microsystems /*
843e7334537SKrishnendu Sadhukhan - Sun Microsystems * Create the list of all supported events
844e7334537SKrishnendu Sadhukhan - Sun Microsystems * (architectural + non-architectural)
845e7334537SKrishnendu Sadhukhan - Sun Microsystems */
846a18ddb3cSKuriakose Kuruvilla for (j = 0; j < known_arch_events; j++) {
847a18ddb3cSKuriakose Kuruvilla if (((1U << j) & arch_events_vector) == 0) {
848a18ddb3cSKuriakose Kuruvilla (void) strcat(gpc_names[i],
849a18ddb3cSKuriakose Kuruvilla arch_events_table[j].name);
8507bd4a6f5Skk (void) strcat(gpc_names[i], ",");
851560e0ee2SKuriakose Kuruvilla if (strcmp(
852560e0ee2SKuriakose Kuruvilla arch_genevents_table[j], "")
853560e0ee2SKuriakose Kuruvilla != 0) {
854560e0ee2SKuriakose Kuruvilla (void) strcat(gpc_names[i],
855560e0ee2SKuriakose Kuruvilla arch_genevents_table[j]);
856560e0ee2SKuriakose Kuruvilla (void) strcat(gpc_names[i],
857560e0ee2SKuriakose Kuruvilla ",");
858560e0ee2SKuriakose Kuruvilla }
8597bd4a6f5Skk }
8607bd4a6f5Skk }
861a18ddb3cSKuriakose Kuruvilla
862a18ddb3cSKuriakose Kuruvilla for (j = 0; events_table != NULL &&
863a18ddb3cSKuriakose Kuruvilla events_table[j].eventselect != NT_END;
864a18ddb3cSKuriakose Kuruvilla j++) {
865a18ddb3cSKuriakose Kuruvilla if (C(i) & events_table[j].supported_counters) {
866a18ddb3cSKuriakose Kuruvilla (void) strcat(gpc_names[i],
867a18ddb3cSKuriakose Kuruvilla events_table[j].name);
868a18ddb3cSKuriakose Kuruvilla (void) strcat(gpc_names[i], ",");
869a18ddb3cSKuriakose Kuruvilla }
8707bd4a6f5Skk }
871e7334537SKrishnendu Sadhukhan - Sun Microsystems
872e7334537SKrishnendu Sadhukhan - Sun Microsystems /* Remove trailing comma */
873a18ddb3cSKuriakose Kuruvilla gpc_names[i][size - 1] = '\0';
8747bd4a6f5Skk }
8757bd4a6f5Skk }
876560e0ee2SKuriakose Kuruvilla
8777bd4a6f5Skk return (0);
8787bd4a6f5Skk }
8797bd4a6f5Skk
core_pcbe_ncounters()8807bd4a6f5Skk static uint_t core_pcbe_ncounters()
8817bd4a6f5Skk {
8827bd4a6f5Skk return (total_pmc);
8837bd4a6f5Skk }
8847bd4a6f5Skk
core_pcbe_impl_name(void)8857bd4a6f5Skk static const char *core_pcbe_impl_name(void)
8867bd4a6f5Skk {
8877bd4a6f5Skk return (core_impl_name);
8887bd4a6f5Skk }
8897bd4a6f5Skk
core_pcbe_cpuref(void)8907bd4a6f5Skk static const char *core_pcbe_cpuref(void)
8917bd4a6f5Skk {
8927bd4a6f5Skk return (core_cpuref);
8937bd4a6f5Skk }
8947bd4a6f5Skk
core_pcbe_list_events(uint_t picnum)8957bd4a6f5Skk static char *core_pcbe_list_events(uint_t picnum)
8967bd4a6f5Skk {
8977bd4a6f5Skk ASSERT(picnum < cpc_ncounters);
8987bd4a6f5Skk
8997bd4a6f5Skk if (picnum < num_gpc) {
9007bd4a6f5Skk return (gpc_names[picnum]);
9017bd4a6f5Skk } else {
902560e0ee2SKuriakose Kuruvilla return (ffc_allnames[picnum - num_gpc]);
9037bd4a6f5Skk }
9047bd4a6f5Skk }
9057bd4a6f5Skk
core_pcbe_list_attrs(void)9067bd4a6f5Skk static char *core_pcbe_list_attrs(void)
9077bd4a6f5Skk {
908a18ddb3cSKuriakose Kuruvilla if (versionid >= 3) {
909a18ddb3cSKuriakose Kuruvilla return ("edge,inv,umask,cmask,anythr");
910a18ddb3cSKuriakose Kuruvilla } else {
911a18ddb3cSKuriakose Kuruvilla return ("edge,pc,inv,umask,cmask");
912a18ddb3cSKuriakose Kuruvilla }
9137bd4a6f5Skk }
9147bd4a6f5Skk
915afb806e6SKuriakose Kuruvilla static const struct nametable_core_uarch *
find_gpcevent_core_uarch(char * name,const struct nametable_core_uarch * nametable)916afb806e6SKuriakose Kuruvilla find_gpcevent_core_uarch(char *name,
917afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *nametable)
9187bd4a6f5Skk {
919afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *n;
920e7334537SKrishnendu Sadhukhan - Sun Microsystems int compare_result = -1;
9217bd4a6f5Skk
9227bd4a6f5Skk for (n = nametable; n->event_num != NT_END; n++) {
9237bd4a6f5Skk compare_result = strcmp(name, n->name);
9247bd4a6f5Skk if (compare_result <= 0) {
9257bd4a6f5Skk break;
9267bd4a6f5Skk }
9277bd4a6f5Skk }
9287bd4a6f5Skk
9297bd4a6f5Skk if (compare_result == 0) {
9307bd4a6f5Skk return (n);
9317bd4a6f5Skk }
9327bd4a6f5Skk
9337bd4a6f5Skk return (NULL);
9347bd4a6f5Skk }
9357bd4a6f5Skk
936560e0ee2SKuriakose Kuruvilla static const struct generic_events *
find_generic_events(char * name,const struct generic_events * table)937560e0ee2SKuriakose Kuruvilla find_generic_events(char *name, const struct generic_events *table)
938560e0ee2SKuriakose Kuruvilla {
939560e0ee2SKuriakose Kuruvilla const struct generic_events *n;
940560e0ee2SKuriakose Kuruvilla
941560e0ee2SKuriakose Kuruvilla for (n = table; n->event_num != NT_END; n++) {
942560e0ee2SKuriakose Kuruvilla if (strcmp(name, n->name) == 0) {
943560e0ee2SKuriakose Kuruvilla return (n);
944560e0ee2SKuriakose Kuruvilla };
945560e0ee2SKuriakose Kuruvilla }
946560e0ee2SKuriakose Kuruvilla
947560e0ee2SKuriakose Kuruvilla return (NULL);
948560e0ee2SKuriakose Kuruvilla }
949560e0ee2SKuriakose Kuruvilla
950a18ddb3cSKuriakose Kuruvilla static const struct events_table_t *
find_gpcevent(char * name)951a18ddb3cSKuriakose Kuruvilla find_gpcevent(char *name)
952a18ddb3cSKuriakose Kuruvilla {
953a18ddb3cSKuriakose Kuruvilla int i;
954a18ddb3cSKuriakose Kuruvilla
955e7334537SKrishnendu Sadhukhan - Sun Microsystems /* Search architectural events */
956a18ddb3cSKuriakose Kuruvilla for (i = 0; i < known_arch_events; i++) {
957560e0ee2SKuriakose Kuruvilla if (strcmp(name, arch_events_table[i].name) == 0 ||
958560e0ee2SKuriakose Kuruvilla strcmp(name, arch_genevents_table[i]) == 0) {
959a18ddb3cSKuriakose Kuruvilla if (((1U << i) & arch_events_vector) == 0) {
960a18ddb3cSKuriakose Kuruvilla return (&arch_events_table[i]);
961a18ddb3cSKuriakose Kuruvilla }
962a18ddb3cSKuriakose Kuruvilla }
963a18ddb3cSKuriakose Kuruvilla }
964a18ddb3cSKuriakose Kuruvilla
965e7334537SKrishnendu Sadhukhan - Sun Microsystems /* Search non-architectural events */
966e7334537SKrishnendu Sadhukhan - Sun Microsystems if (events_table != NULL) {
967e7334537SKrishnendu Sadhukhan - Sun Microsystems for (i = 0; events_table[i].eventselect != NT_END; i++) {
968e7334537SKrishnendu Sadhukhan - Sun Microsystems if (strcmp(name, events_table[i].name) == 0) {
969e7334537SKrishnendu Sadhukhan - Sun Microsystems return (&events_table[i]);
970e7334537SKrishnendu Sadhukhan - Sun Microsystems }
971a18ddb3cSKuriakose Kuruvilla }
972a18ddb3cSKuriakose Kuruvilla }
973a18ddb3cSKuriakose Kuruvilla
974a18ddb3cSKuriakose Kuruvilla return (NULL);
975a18ddb3cSKuriakose Kuruvilla }
976560e0ee2SKuriakose Kuruvilla
9777bd4a6f5Skk static uint64_t
core_pcbe_event_coverage(char * event)9787bd4a6f5Skk core_pcbe_event_coverage(char *event)
9797bd4a6f5Skk {
9807bd4a6f5Skk uint64_t bitmap;
9817bd4a6f5Skk uint64_t bitmask;
982a18ddb3cSKuriakose Kuruvilla const struct events_table_t *n;
9837bd4a6f5Skk int i;
9847bd4a6f5Skk
9857bd4a6f5Skk bitmap = 0;
9867bd4a6f5Skk
9877bd4a6f5Skk /* Is it an event that a GPC can track? */
988a18ddb3cSKuriakose Kuruvilla if (versionid >= 3) {
989a18ddb3cSKuriakose Kuruvilla n = find_gpcevent(event);
990a18ddb3cSKuriakose Kuruvilla if (n != NULL) {
991a18ddb3cSKuriakose Kuruvilla bitmap |= (n->supported_counters &
992a18ddb3cSKuriakose Kuruvilla BITMASK_XBITS(num_gpc));
993a18ddb3cSKuriakose Kuruvilla }
994a18ddb3cSKuriakose Kuruvilla } else {
995560e0ee2SKuriakose Kuruvilla if (find_generic_events(event, cmn_generic_events) != NULL) {
996560e0ee2SKuriakose Kuruvilla bitmap |= BITMASK_XBITS(num_gpc);
997*a1e3874eSJohn Levon } else if (find_generic_events(event,
998*a1e3874eSJohn Levon generic_events_pic0) != NULL) {
999560e0ee2SKuriakose Kuruvilla bitmap |= 1ULL;
1000560e0ee2SKuriakose Kuruvilla } else if (find_gpcevent_core_uarch(event,
1001560e0ee2SKuriakose Kuruvilla cmn_gpc_events_core_uarch) != NULL) {
1002a18ddb3cSKuriakose Kuruvilla bitmap |= BITMASK_XBITS(num_gpc);
1003afb806e6SKuriakose Kuruvilla } else if (find_gpcevent_core_uarch(event, pic0_events) !=
1004afb806e6SKuriakose Kuruvilla NULL) {
1005a18ddb3cSKuriakose Kuruvilla bitmap |= 1ULL;
1006afb806e6SKuriakose Kuruvilla } else if (find_gpcevent_core_uarch(event, pic1_events) !=
1007afb806e6SKuriakose Kuruvilla NULL) {
1008a18ddb3cSKuriakose Kuruvilla bitmap |= 1ULL << 1;
1009a18ddb3cSKuriakose Kuruvilla }
10107bd4a6f5Skk }
10117bd4a6f5Skk
10127bd4a6f5Skk /* Check if the event can be counted in the fixed-function counters */
10137bd4a6f5Skk if (num_ffc > 0) {
10147bd4a6f5Skk bitmask = 1ULL << num_gpc;
10157bd4a6f5Skk for (i = 0; i < num_ffc; i++) {
10167bd4a6f5Skk if (strcmp(event, ffc_names[i]) == 0) {
10177bd4a6f5Skk bitmap |= bitmask;
1018560e0ee2SKuriakose Kuruvilla } else if (strcmp(event, ffc_genericnames[i]) == 0) {
1019560e0ee2SKuriakose Kuruvilla bitmap |= bitmask;
10207bd4a6f5Skk }
10217bd4a6f5Skk bitmask = bitmask << 1;
10227bd4a6f5Skk }
10237bd4a6f5Skk }
10247bd4a6f5Skk
10257bd4a6f5Skk return (bitmap);
10267bd4a6f5Skk }
10277bd4a6f5Skk
10287bd4a6f5Skk static uint64_t
core_pcbe_overflow_bitmap(void)10297bd4a6f5Skk core_pcbe_overflow_bitmap(void)
10307bd4a6f5Skk {
10317bd4a6f5Skk uint64_t interrupt_status;
10327bd4a6f5Skk uint64_t intrbits_ffc;
10337bd4a6f5Skk uint64_t intrbits_gpc;
10347bd4a6f5Skk extern int kcpc_hw_overflow_intr_installed;
10357bd4a6f5Skk uint64_t overflow_bitmap;
10367bd4a6f5Skk
10377bd4a6f5Skk RDMSR(PERF_GLOBAL_STATUS, interrupt_status);
10387bd4a6f5Skk WRMSR(PERF_GLOBAL_OVF_CTRL, interrupt_status);
10397bd4a6f5Skk
10407bd4a6f5Skk interrupt_status = interrupt_status & control_mask;
10417bd4a6f5Skk intrbits_ffc = (interrupt_status >> 32) & control_ffc;
10427bd4a6f5Skk intrbits_gpc = interrupt_status & control_gpc;
10437bd4a6f5Skk overflow_bitmap = (intrbits_ffc << num_gpc) | intrbits_gpc;
10447bd4a6f5Skk
10457bd4a6f5Skk ASSERT(kcpc_hw_overflow_intr_installed);
10467bd4a6f5Skk (*kcpc_hw_enable_cpc_intr)();
10477bd4a6f5Skk
10487bd4a6f5Skk return (overflow_bitmap);
10497bd4a6f5Skk }
10507bd4a6f5Skk
10517bd4a6f5Skk static int
check_cpc_securitypolicy(core_pcbe_config_t * conf,const struct nametable_core_uarch * n)1052a18ddb3cSKuriakose Kuruvilla check_cpc_securitypolicy(core_pcbe_config_t *conf,
1053afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *n)
10547bd4a6f5Skk {
10557bd4a6f5Skk if (conf->core_ctl & n->restricted_bits) {
10567bd4a6f5Skk if (secpolicy_cpc_cpu(crgetcred()) != 0) {
10577bd4a6f5Skk return (CPC_ATTR_REQUIRES_PRIVILEGE);
10587bd4a6f5Skk }
10597bd4a6f5Skk }
10607bd4a6f5Skk return (0);
10617bd4a6f5Skk }
10627bd4a6f5Skk
10637bd4a6f5Skk static int
configure_gpc(uint_t picnum,char * event,uint64_t preset,uint32_t flags,uint_t nattrs,kcpc_attr_t * attrs,void ** data)10647bd4a6f5Skk configure_gpc(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
10657bd4a6f5Skk uint_t nattrs, kcpc_attr_t *attrs, void **data)
10667bd4a6f5Skk {
10677bd4a6f5Skk core_pcbe_config_t conf;
1068afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *n;
1069560e0ee2SKuriakose Kuruvilla const struct generic_events *k = NULL;
1070afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *m;
1071afb806e6SKuriakose Kuruvilla const struct nametable_core_uarch *picspecific_events;
1072afb806e6SKuriakose Kuruvilla struct nametable_core_uarch nt_raw = { "", 0x0, 0x0 };
10737bd4a6f5Skk uint_t i;
10747bd4a6f5Skk long event_num;
1075a18ddb3cSKuriakose Kuruvilla const struct events_table_t *eventcode;
10767bd4a6f5Skk
10777bd4a6f5Skk if (((preset & BITS_EXTENDED_FROM_31) != 0) &&
10787bd4a6f5Skk ((preset & BITS_EXTENDED_FROM_31) !=
10797bd4a6f5Skk BITS_EXTENDED_FROM_31)) {
10807bd4a6f5Skk
10817bd4a6f5Skk /*
10827bd4a6f5Skk * Bits beyond bit-31 in the general-purpose counters can only
10837bd4a6f5Skk * be written to by extension of bit 31. We cannot preset
10847bd4a6f5Skk * these bits to any value other than all 1s or all 0s.
10857bd4a6f5Skk */
10867bd4a6f5Skk return (CPC_ATTRIBUTE_OUT_OF_RANGE);
10877bd4a6f5Skk }
10887bd4a6f5Skk
1089a18ddb3cSKuriakose Kuruvilla if (versionid >= 3) {
1090a18ddb3cSKuriakose Kuruvilla eventcode = find_gpcevent(event);
1091a18ddb3cSKuriakose Kuruvilla if (eventcode != NULL) {
1092a18ddb3cSKuriakose Kuruvilla if ((C(picnum) & eventcode->supported_counters) == 0) {
1093a18ddb3cSKuriakose Kuruvilla return (CPC_PIC_NOT_CAPABLE);
1094a18ddb3cSKuriakose Kuruvilla }
1095560e0ee2SKuriakose Kuruvilla if (nattrs > 0 &&
1096560e0ee2SKuriakose Kuruvilla (strncmp("PAPI_", event, 5) == 0)) {
1097560e0ee2SKuriakose Kuruvilla return (CPC_ATTRIBUTE_OUT_OF_RANGE);
1098560e0ee2SKuriakose Kuruvilla }
1099a18ddb3cSKuriakose Kuruvilla conf.core_ctl = eventcode->eventselect;
1100a18ddb3cSKuriakose Kuruvilla conf.core_ctl |= eventcode->unitmask <<
1101a18ddb3cSKuriakose Kuruvilla CORE_UMASK_SHIFT;
1102a18ddb3cSKuriakose Kuruvilla } else {
1103a18ddb3cSKuriakose Kuruvilla /* Event specified as raw event code */
1104a18ddb3cSKuriakose Kuruvilla if (ddi_strtol(event, NULL, 0, &event_num) != 0) {
1105a18ddb3cSKuriakose Kuruvilla return (CPC_INVALID_EVENT);
1106a18ddb3cSKuriakose Kuruvilla }
1107a18ddb3cSKuriakose Kuruvilla conf.core_ctl = event_num & 0xFF;
11087bd4a6f5Skk }
1109a18ddb3cSKuriakose Kuruvilla } else {
1110560e0ee2SKuriakose Kuruvilla if ((k = find_generic_events(event, cmn_generic_events)) !=
1111560e0ee2SKuriakose Kuruvilla NULL ||
1112560e0ee2SKuriakose Kuruvilla (picnum == 0 &&
1113560e0ee2SKuriakose Kuruvilla (k = find_generic_events(event, generic_events_pic0)) !=
1114560e0ee2SKuriakose Kuruvilla NULL)) {
1115560e0ee2SKuriakose Kuruvilla if (nattrs > 0) {
1116560e0ee2SKuriakose Kuruvilla return (CPC_ATTRIBUTE_OUT_OF_RANGE);
1117a18ddb3cSKuriakose Kuruvilla }
1118560e0ee2SKuriakose Kuruvilla conf.core_ctl = k->event_num;
1119560e0ee2SKuriakose Kuruvilla conf.core_ctl |= k->umask << CORE_UMASK_SHIFT;
1120560e0ee2SKuriakose Kuruvilla } else {
1121560e0ee2SKuriakose Kuruvilla /* Not a generic event */
1122560e0ee2SKuriakose Kuruvilla
1123560e0ee2SKuriakose Kuruvilla n = find_gpcevent_core_uarch(event,
1124560e0ee2SKuriakose Kuruvilla cmn_gpc_events_core_uarch);
1125560e0ee2SKuriakose Kuruvilla if (n == NULL) {
1126560e0ee2SKuriakose Kuruvilla switch (picnum) {
1127560e0ee2SKuriakose Kuruvilla case 0:
1128560e0ee2SKuriakose Kuruvilla picspecific_events =
1129560e0ee2SKuriakose Kuruvilla pic0_events;
1130560e0ee2SKuriakose Kuruvilla break;
1131560e0ee2SKuriakose Kuruvilla case 1:
1132560e0ee2SKuriakose Kuruvilla picspecific_events =
1133560e0ee2SKuriakose Kuruvilla pic1_events;
1134560e0ee2SKuriakose Kuruvilla break;
1135560e0ee2SKuriakose Kuruvilla default:
1136560e0ee2SKuriakose Kuruvilla picspecific_events = NULL;
1137560e0ee2SKuriakose Kuruvilla break;
1138560e0ee2SKuriakose Kuruvilla }
1139560e0ee2SKuriakose Kuruvilla if (picspecific_events != NULL) {
1140560e0ee2SKuriakose Kuruvilla n = find_gpcevent_core_uarch(event,
1141560e0ee2SKuriakose Kuruvilla picspecific_events);
1142560e0ee2SKuriakose Kuruvilla }
1143a18ddb3cSKuriakose Kuruvilla }
1144560e0ee2SKuriakose Kuruvilla if (n == NULL) {
1145560e0ee2SKuriakose Kuruvilla
1146560e0ee2SKuriakose Kuruvilla /*
1147560e0ee2SKuriakose Kuruvilla * Check if this is a case where the event was
1148560e0ee2SKuriakose Kuruvilla * specified directly by its event number
1149560e0ee2SKuriakose Kuruvilla * instead of its name string.
1150560e0ee2SKuriakose Kuruvilla */
1151560e0ee2SKuriakose Kuruvilla if (ddi_strtol(event, NULL, 0, &event_num) !=
1152560e0ee2SKuriakose Kuruvilla 0) {
1153560e0ee2SKuriakose Kuruvilla return (CPC_INVALID_EVENT);
1154560e0ee2SKuriakose Kuruvilla }
11557bd4a6f5Skk
1156560e0ee2SKuriakose Kuruvilla event_num = event_num & 0xFF;
1157560e0ee2SKuriakose Kuruvilla
1158560e0ee2SKuriakose Kuruvilla /*
1159560e0ee2SKuriakose Kuruvilla * Search the event table to find out if the
1160560e0ee2SKuriakose Kuruvilla * event specified has an privilege
1161560e0ee2SKuriakose Kuruvilla * requirements. Currently none of the
1162560e0ee2SKuriakose Kuruvilla * pic-specific counters have any privilege
1163560e0ee2SKuriakose Kuruvilla * requirements. Hence only the table
1164560e0ee2SKuriakose Kuruvilla * cmn_gpc_events_core_uarch is searched.
1165560e0ee2SKuriakose Kuruvilla */
1166560e0ee2SKuriakose Kuruvilla for (m = cmn_gpc_events_core_uarch;
1167560e0ee2SKuriakose Kuruvilla m->event_num != NT_END;
1168560e0ee2SKuriakose Kuruvilla m++) {
1169560e0ee2SKuriakose Kuruvilla if (event_num == m->event_num) {
1170560e0ee2SKuriakose Kuruvilla break;
1171560e0ee2SKuriakose Kuruvilla }
1172560e0ee2SKuriakose Kuruvilla }
1173560e0ee2SKuriakose Kuruvilla if (m->event_num == NT_END) {
1174560e0ee2SKuriakose Kuruvilla nt_raw.event_num = (uint8_t)event_num;
1175560e0ee2SKuriakose Kuruvilla n = &nt_raw;
1176560e0ee2SKuriakose Kuruvilla } else {
1177560e0ee2SKuriakose Kuruvilla n = m;
11787bd4a6f5Skk }
11797bd4a6f5Skk }
1180560e0ee2SKuriakose Kuruvilla conf.core_ctl = n->event_num; /* Event Select */
11817bd4a6f5Skk }
11827bd4a6f5Skk }
11837bd4a6f5Skk
1184a18ddb3cSKuriakose Kuruvilla
11857bd4a6f5Skk conf.core_picno = picnum;
11867bd4a6f5Skk conf.core_pictype = CORE_GPC;
11877bd4a6f5Skk conf.core_rawpic = preset & mask_gpc;
11887bd4a6f5Skk
11897bd4a6f5Skk conf.core_pes = GPC_BASE_PES + picnum;
11907bd4a6f5Skk conf.core_pmc = GPC_BASE_PMC + picnum;
11917bd4a6f5Skk
11927bd4a6f5Skk for (i = 0; i < nattrs; i++) {
11937bd4a6f5Skk if (strncmp(attrs[i].ka_name, "umask", 6) == 0) {
119434fdb700SKuriakose Kuruvilla if ((attrs[i].ka_val | CORE_UMASK_MASK) !=
119534fdb700SKuriakose Kuruvilla CORE_UMASK_MASK) {
11967bd4a6f5Skk return (CPC_ATTRIBUTE_OUT_OF_RANGE);
11977bd4a6f5Skk }
119834fdb700SKuriakose Kuruvilla /* Clear out the default umask */
119934fdb700SKuriakose Kuruvilla conf.core_ctl &= ~ (CORE_UMASK_MASK <<
120034fdb700SKuriakose Kuruvilla CORE_UMASK_SHIFT);
120134fdb700SKuriakose Kuruvilla /* Use the user provided umask */
12027bd4a6f5Skk conf.core_ctl |= attrs[i].ka_val <<
12037bd4a6f5Skk CORE_UMASK_SHIFT;
1204a18ddb3cSKuriakose Kuruvilla } else if (strncmp(attrs[i].ka_name, "edge", 6) == 0) {
12057bd4a6f5Skk if (attrs[i].ka_val != 0)
12067bd4a6f5Skk conf.core_ctl |= CORE_EDGE;
12077bd4a6f5Skk } else if (strncmp(attrs[i].ka_name, "inv", 4) == 0) {
12087bd4a6f5Skk if (attrs[i].ka_val != 0)
12097bd4a6f5Skk conf.core_ctl |= CORE_INV;
12107bd4a6f5Skk } else if (strncmp(attrs[i].ka_name, "cmask", 6) == 0) {
12117bd4a6f5Skk if ((attrs[i].ka_val | CORE_CMASK_MASK) !=
12127bd4a6f5Skk CORE_CMASK_MASK) {
12137bd4a6f5Skk return (CPC_ATTRIBUTE_OUT_OF_RANGE);
12147bd4a6f5Skk }
1215a18ddb3cSKuriakose Kuruvilla conf.core_ctl |= attrs[i].ka_val <<
1216a18ddb3cSKuriakose Kuruvilla CORE_CMASK_SHIFT;
1217a18ddb3cSKuriakose Kuruvilla } else if (strncmp(attrs[i].ka_name, "anythr", 7) ==
1218a18ddb3cSKuriakose Kuruvilla 0) {
1219a18ddb3cSKuriakose Kuruvilla if (versionid < 3)
1220a18ddb3cSKuriakose Kuruvilla return (CPC_INVALID_ATTRIBUTE);
1221a18ddb3cSKuriakose Kuruvilla if (secpolicy_cpc_cpu(crgetcred()) != 0) {
1222a18ddb3cSKuriakose Kuruvilla return (CPC_ATTR_REQUIRES_PRIVILEGE);
1223a18ddb3cSKuriakose Kuruvilla }
1224a18ddb3cSKuriakose Kuruvilla if (attrs[i].ka_val != 0)
1225a18ddb3cSKuriakose Kuruvilla conf.core_ctl |= CORE_ANYTHR;
12267bd4a6f5Skk } else {
12277bd4a6f5Skk return (CPC_INVALID_ATTRIBUTE);
12287bd4a6f5Skk }
12297bd4a6f5Skk }
12307bd4a6f5Skk
12317bd4a6f5Skk if (flags & CPC_COUNT_USER)
12327bd4a6f5Skk conf.core_ctl |= CORE_USR;
12337bd4a6f5Skk if (flags & CPC_COUNT_SYSTEM)
12347bd4a6f5Skk conf.core_ctl |= CORE_OS;
12357bd4a6f5Skk if (flags & CPC_OVF_NOTIFY_EMT)
12367bd4a6f5Skk conf.core_ctl |= CORE_INT;
12377bd4a6f5Skk conf.core_ctl |= CORE_EN;
12387bd4a6f5Skk
1239560e0ee2SKuriakose Kuruvilla if (versionid < 3 && k == NULL) {
1240a18ddb3cSKuriakose Kuruvilla if (check_cpc_securitypolicy(&conf, n) != 0) {
1241a18ddb3cSKuriakose Kuruvilla return (CPC_ATTR_REQUIRES_PRIVILEGE);
1242a18ddb3cSKuriakose Kuruvilla }
12437bd4a6f5Skk }
12447bd4a6f5Skk
12457bd4a6f5Skk *data = kmem_alloc(sizeof (core_pcbe_config_t), KM_SLEEP);
12467bd4a6f5Skk *((core_pcbe_config_t *)*data) = conf;
12477bd4a6f5Skk
12487bd4a6f5Skk return (0);
12497bd4a6f5Skk }
12507bd4a6f5Skk
12517bd4a6f5Skk static int
configure_ffc(uint_t picnum,char * event,uint64_t preset,uint32_t flags,uint_t nattrs,kcpc_attr_t * attrs,void ** data)12527bd4a6f5Skk configure_ffc(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
1253a18ddb3cSKuriakose Kuruvilla uint_t nattrs, kcpc_attr_t *attrs, void **data)
12547bd4a6f5Skk {
12557bd4a6f5Skk core_pcbe_config_t *conf;
1256a18ddb3cSKuriakose Kuruvilla uint_t i;
12577bd4a6f5Skk
12587bd4a6f5Skk if (picnum - num_gpc >= num_ffc) {
12597bd4a6f5Skk return (CPC_INVALID_PICNUM);
12607bd4a6f5Skk }
1261a18ddb3cSKuriakose Kuruvilla
1262560e0ee2SKuriakose Kuruvilla if ((strcmp(ffc_names[picnum-num_gpc], event) != 0) &&
1263560e0ee2SKuriakose Kuruvilla (strcmp(ffc_genericnames[picnum-num_gpc], event) != 0)) {
12647bd4a6f5Skk return (CPC_INVALID_EVENT);
12657bd4a6f5Skk }
12667bd4a6f5Skk
1267a18ddb3cSKuriakose Kuruvilla if ((versionid < 3) && (nattrs != 0)) {
12687bd4a6f5Skk return (CPC_INVALID_ATTRIBUTE);
12697bd4a6f5Skk }
12707bd4a6f5Skk
12717bd4a6f5Skk conf = kmem_alloc(sizeof (core_pcbe_config_t), KM_SLEEP);
1272a18ddb3cSKuriakose Kuruvilla conf->core_ctl = 0;
1273a18ddb3cSKuriakose Kuruvilla
1274a18ddb3cSKuriakose Kuruvilla for (i = 0; i < nattrs; i++) {
1275a18ddb3cSKuriakose Kuruvilla if (strncmp(attrs[i].ka_name, "anythr", 7) == 0) {
1276a18ddb3cSKuriakose Kuruvilla if (secpolicy_cpc_cpu(crgetcred()) != 0) {
127796992ee7SEthindra Ramamurthy kmem_free(conf, sizeof (core_pcbe_config_t));
1278a18ddb3cSKuriakose Kuruvilla return (CPC_ATTR_REQUIRES_PRIVILEGE);
1279a18ddb3cSKuriakose Kuruvilla }
1280a18ddb3cSKuriakose Kuruvilla if (attrs[i].ka_val != 0) {
1281a18ddb3cSKuriakose Kuruvilla conf->core_ctl |= CORE_FFC_ANYTHR;
1282a18ddb3cSKuriakose Kuruvilla }
1283a18ddb3cSKuriakose Kuruvilla } else {
1284a18ddb3cSKuriakose Kuruvilla kmem_free(conf, sizeof (core_pcbe_config_t));
1285a18ddb3cSKuriakose Kuruvilla return (CPC_INVALID_ATTRIBUTE);
1286a18ddb3cSKuriakose Kuruvilla }
1287a18ddb3cSKuriakose Kuruvilla }
12887bd4a6f5Skk
12897bd4a6f5Skk conf->core_picno = picnum;
12907bd4a6f5Skk conf->core_pictype = CORE_FFC;
12917bd4a6f5Skk conf->core_rawpic = preset & mask_ffc;
12927bd4a6f5Skk conf->core_pmc = FFC_BASE_PMC + (picnum - num_gpc);
12937bd4a6f5Skk
12947bd4a6f5Skk /* All fixed-function counters have the same control register */
12957bd4a6f5Skk conf->core_pes = PERF_FIXED_CTR_CTRL;
12967bd4a6f5Skk
12977bd4a6f5Skk if (flags & CPC_COUNT_USER)
12987bd4a6f5Skk conf->core_ctl |= CORE_FFC_USR_EN;
12997bd4a6f5Skk if (flags & CPC_COUNT_SYSTEM)
13007bd4a6f5Skk conf->core_ctl |= CORE_FFC_OS_EN;
13017bd4a6f5Skk if (flags & CPC_OVF_NOTIFY_EMT)
13027bd4a6f5Skk conf->core_ctl |= CORE_FFC_PMI;
13037bd4a6f5Skk
13047bd4a6f5Skk *data = conf;
13057bd4a6f5Skk return (0);
13067bd4a6f5Skk }
13077bd4a6f5Skk
13087bd4a6f5Skk /*ARGSUSED*/
13097bd4a6f5Skk static int
core_pcbe_configure(uint_t picnum,char * event,uint64_t preset,uint32_t flags,uint_t nattrs,kcpc_attr_t * attrs,void ** data,void * token)13107bd4a6f5Skk core_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
13117bd4a6f5Skk uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
13127bd4a6f5Skk void *token)
13137bd4a6f5Skk {
13147bd4a6f5Skk int ret;
13157bd4a6f5Skk core_pcbe_config_t *conf;
13167bd4a6f5Skk
13177bd4a6f5Skk /*
13187bd4a6f5Skk * If we've been handed an existing configuration, we need only preset
13197bd4a6f5Skk * the counter value.
13207bd4a6f5Skk */
13217bd4a6f5Skk if (*data != NULL) {
13227bd4a6f5Skk conf = *data;
13237bd4a6f5Skk ASSERT(conf->core_pictype == CORE_GPC ||
13247bd4a6f5Skk conf->core_pictype == CORE_FFC);
13257bd4a6f5Skk if (conf->core_pictype == CORE_GPC)
13267bd4a6f5Skk conf->core_rawpic = preset & mask_gpc;
13277bd4a6f5Skk else /* CORE_FFC */
13287bd4a6f5Skk conf->core_rawpic = preset & mask_ffc;
13297bd4a6f5Skk return (0);
13307bd4a6f5Skk }
13317bd4a6f5Skk
13327bd4a6f5Skk if (picnum >= total_pmc) {
13337bd4a6f5Skk return (CPC_INVALID_PICNUM);
13347bd4a6f5Skk }
13357bd4a6f5Skk
13367bd4a6f5Skk if (picnum < num_gpc) {
13377bd4a6f5Skk ret = configure_gpc(picnum, event, preset, flags,
13387bd4a6f5Skk nattrs, attrs, data);
13397bd4a6f5Skk } else {
13407bd4a6f5Skk ret = configure_ffc(picnum, event, preset, flags,
1341a18ddb3cSKuriakose Kuruvilla nattrs, attrs, data);
13427bd4a6f5Skk }
13437bd4a6f5Skk return (ret);
13447bd4a6f5Skk }
13457bd4a6f5Skk
13467bd4a6f5Skk static void
core_pcbe_program(void * token)13477bd4a6f5Skk core_pcbe_program(void *token)
13487bd4a6f5Skk {
13497bd4a6f5Skk core_pcbe_config_t *cfg;
13507bd4a6f5Skk uint64_t perf_global_ctrl;
13517bd4a6f5Skk uint64_t perf_fixed_ctr_ctrl;
13527bd4a6f5Skk uint64_t curcr4;
13537bd4a6f5Skk
13547bd4a6f5Skk core_pcbe_allstop();
13557bd4a6f5Skk
13567bd4a6f5Skk curcr4 = getcr4();
13577bd4a6f5Skk if (kcpc_allow_nonpriv(token))
13587bd4a6f5Skk /* Allow RDPMC at any ring level */
13597bd4a6f5Skk setcr4(curcr4 | CR4_PCE);
13607bd4a6f5Skk else
13617bd4a6f5Skk /* Allow RDPMC only at ring 0 */
13627bd4a6f5Skk setcr4(curcr4 & ~CR4_PCE);
13637bd4a6f5Skk
13647bd4a6f5Skk /* Clear any overflow indicators before programming the counters */
13657bd4a6f5Skk WRMSR(PERF_GLOBAL_OVF_CTRL, MASK_CONDCHGD_OVFBUFFER | control_mask);
13667bd4a6f5Skk
13677bd4a6f5Skk cfg = NULL;
13687bd4a6f5Skk perf_global_ctrl = 0;
13697bd4a6f5Skk perf_fixed_ctr_ctrl = 0;
13707bd4a6f5Skk cfg = (core_pcbe_config_t *)kcpc_next_config(token, cfg, NULL);
13717bd4a6f5Skk while (cfg != NULL) {
13727bd4a6f5Skk ASSERT(cfg->core_pictype == CORE_GPC ||
13737bd4a6f5Skk cfg->core_pictype == CORE_FFC);
13747bd4a6f5Skk
13757bd4a6f5Skk if (cfg->core_pictype == CORE_GPC) {
13767bd4a6f5Skk /*
13777bd4a6f5Skk * General-purpose counter registers have write
13787bd4a6f5Skk * restrictions where only the lower 32-bits can be
13797bd4a6f5Skk * written to. The rest of the relevant bits are
13807bd4a6f5Skk * written to by extension from bit 31 (all ZEROS if
13817bd4a6f5Skk * bit-31 is ZERO and all ONE if bit-31 is ONE). This
13827bd4a6f5Skk * makes it possible to write to the counter register
13837bd4a6f5Skk * only values that have all ONEs or all ZEROs in the
13847bd4a6f5Skk * higher bits.
13857bd4a6f5Skk */
13867bd4a6f5Skk if (((cfg->core_rawpic & BITS_EXTENDED_FROM_31) == 0) ||
13877bd4a6f5Skk ((cfg->core_rawpic & BITS_EXTENDED_FROM_31) ==
13887bd4a6f5Skk BITS_EXTENDED_FROM_31)) {
13897bd4a6f5Skk /*
13907bd4a6f5Skk * Straighforward case where the higher bits
13917bd4a6f5Skk * are all ZEROs or all ONEs.
13927bd4a6f5Skk */
13937bd4a6f5Skk WRMSR(cfg->core_pmc,
13947bd4a6f5Skk (cfg->core_rawpic & mask_gpc));
13957bd4a6f5Skk } else {
13967bd4a6f5Skk /*
13977bd4a6f5Skk * The high order bits are not all the same.
13987bd4a6f5Skk * We save what is currently in the registers
13997bd4a6f5Skk * and do not write to it. When we want to do
14007bd4a6f5Skk * a read from this register later (in
14017bd4a6f5Skk * core_pcbe_sample()), we subtract the value
14027bd4a6f5Skk * we save here to get the actual event count.
14037bd4a6f5Skk *
14047bd4a6f5Skk * NOTE: As a result, we will not get overflow
14057bd4a6f5Skk * interrupts as expected.
14067bd4a6f5Skk */
14077bd4a6f5Skk RDMSR(cfg->core_pmc, cfg->core_rawpic);
14087bd4a6f5Skk cfg->core_rawpic = cfg->core_rawpic & mask_gpc;
14097bd4a6f5Skk }
14107bd4a6f5Skk WRMSR(cfg->core_pes, cfg->core_ctl);
14117bd4a6f5Skk perf_global_ctrl |= 1ull << cfg->core_picno;
14127bd4a6f5Skk } else {
14137bd4a6f5Skk /*
14147bd4a6f5Skk * Unlike the general-purpose counters, all relevant
14157bd4a6f5Skk * bits of fixed-function counters can be written to.
14167bd4a6f5Skk */
14177bd4a6f5Skk WRMSR(cfg->core_pmc, cfg->core_rawpic & mask_ffc);
14187bd4a6f5Skk
14197bd4a6f5Skk /*
14207bd4a6f5Skk * Collect the control bits for all the
14217bd4a6f5Skk * fixed-function counters and write it at one shot
14227bd4a6f5Skk * later in this function
14237bd4a6f5Skk */
14247bd4a6f5Skk perf_fixed_ctr_ctrl |= cfg->core_ctl <<
14257bd4a6f5Skk ((cfg->core_picno - num_gpc) * CORE_FFC_ATTR_SIZE);
14267bd4a6f5Skk perf_global_ctrl |=
14277bd4a6f5Skk 1ull << (cfg->core_picno - num_gpc + 32);
14287bd4a6f5Skk }
14297bd4a6f5Skk
14307bd4a6f5Skk cfg = (core_pcbe_config_t *)
14317bd4a6f5Skk kcpc_next_config(token, cfg, NULL);
14327bd4a6f5Skk }
14337bd4a6f5Skk
14347bd4a6f5Skk /* Enable all the counters */
14357bd4a6f5Skk WRMSR(PERF_FIXED_CTR_CTRL, perf_fixed_ctr_ctrl);
14367bd4a6f5Skk WRMSR(PERF_GLOBAL_CTRL, perf_global_ctrl);
14377bd4a6f5Skk }
14387bd4a6f5Skk
14397bd4a6f5Skk static void
core_pcbe_allstop(void)14407bd4a6f5Skk core_pcbe_allstop(void)
14417bd4a6f5Skk {
14427bd4a6f5Skk /* Disable all the counters together */
14437bd4a6f5Skk WRMSR(PERF_GLOBAL_CTRL, ALL_STOPPED);
14447bd4a6f5Skk
14457bd4a6f5Skk setcr4(getcr4() & ~CR4_PCE);
14467bd4a6f5Skk }
14477bd4a6f5Skk
14487bd4a6f5Skk static void
core_pcbe_sample(void * token)14497bd4a6f5Skk core_pcbe_sample(void *token)
14507bd4a6f5Skk {
14517bd4a6f5Skk uint64_t *daddr;
14527bd4a6f5Skk uint64_t curpic;
14537bd4a6f5Skk core_pcbe_config_t *cfg;
14547bd4a6f5Skk uint64_t counter_mask;
14557bd4a6f5Skk
14567bd4a6f5Skk cfg = (core_pcbe_config_t *)kcpc_next_config(token, NULL, &daddr);
14577bd4a6f5Skk while (cfg != NULL) {
14587bd4a6f5Skk ASSERT(cfg->core_pictype == CORE_GPC ||
14597bd4a6f5Skk cfg->core_pictype == CORE_FFC);
14607bd4a6f5Skk
14617bd4a6f5Skk curpic = rdmsr(cfg->core_pmc);
14627bd4a6f5Skk
14637bd4a6f5Skk DTRACE_PROBE4(core__pcbe__sample,
14647bd4a6f5Skk uint64_t, cfg->core_pmc,
14657bd4a6f5Skk uint64_t, curpic,
14667bd4a6f5Skk uint64_t, cfg->core_rawpic,
14677bd4a6f5Skk uint64_t, *daddr);
14687bd4a6f5Skk
14697bd4a6f5Skk if (cfg->core_pictype == CORE_GPC) {
14707bd4a6f5Skk counter_mask = mask_gpc;
14717bd4a6f5Skk } else {
14727bd4a6f5Skk counter_mask = mask_ffc;
14737bd4a6f5Skk }
14747bd4a6f5Skk curpic = curpic & counter_mask;
14757bd4a6f5Skk if (curpic >= cfg->core_rawpic) {
14767bd4a6f5Skk *daddr += curpic - cfg->core_rawpic;
14777bd4a6f5Skk } else {
14787bd4a6f5Skk /* Counter overflowed since our last sample */
14797bd4a6f5Skk *daddr += counter_mask - (cfg->core_rawpic - curpic) +
14807bd4a6f5Skk 1;
14817bd4a6f5Skk }
14827bd4a6f5Skk cfg->core_rawpic = *daddr & counter_mask;
14837bd4a6f5Skk
14847bd4a6f5Skk cfg =
14857bd4a6f5Skk (core_pcbe_config_t *)kcpc_next_config(token, cfg, &daddr);
14867bd4a6f5Skk }
14877bd4a6f5Skk }
14887bd4a6f5Skk
14897bd4a6f5Skk static void
core_pcbe_free(void * config)14907bd4a6f5Skk core_pcbe_free(void *config)
14917bd4a6f5Skk {
14927bd4a6f5Skk kmem_free(config, sizeof (core_pcbe_config_t));
14937bd4a6f5Skk }
14947bd4a6f5Skk
14957bd4a6f5Skk static struct modlpcbe core_modlpcbe = {
14967bd4a6f5Skk &mod_pcbeops,
1497820c9f58Skk "Core Performance Counters",
14987bd4a6f5Skk &core_pcbe_ops
14997bd4a6f5Skk };
15007bd4a6f5Skk
15017bd4a6f5Skk static struct modlinkage core_modl = {
15027bd4a6f5Skk MODREV_1,
15037bd4a6f5Skk &core_modlpcbe,
15047bd4a6f5Skk };
15057bd4a6f5Skk
15067bd4a6f5Skk int
_init(void)15077bd4a6f5Skk _init(void)
15087bd4a6f5Skk {
15097bd4a6f5Skk if (core_pcbe_init() != 0) {
15107bd4a6f5Skk return (ENOTSUP);
15117bd4a6f5Skk }
15127bd4a6f5Skk return (mod_install(&core_modl));
15137bd4a6f5Skk }
15147bd4a6f5Skk
15157bd4a6f5Skk int
_fini(void)15167bd4a6f5Skk _fini(void)
15177bd4a6f5Skk {
15187bd4a6f5Skk return (mod_remove(&core_modl));
15197bd4a6f5Skk }
15207bd4a6f5Skk
15217bd4a6f5Skk int
_info(struct modinfo * mi)15227bd4a6f5Skk _info(struct modinfo *mi)
15237bd4a6f5Skk {
15247bd4a6f5Skk return (mod_info(&core_modl, mi));
15257bd4a6f5Skk }
1526