125cf1a30Sjl /*
225cf1a30Sjl * CDDL HEADER START
325cf1a30Sjl *
425cf1a30Sjl * The contents of this file are subject to the terms of the
525cf1a30Sjl * Common Development and Distribution License (the "License").
625cf1a30Sjl * You may not use this file except in compliance with the License.
725cf1a30Sjl *
825cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl * See the License for the specific language governing permissions
1125cf1a30Sjl * and limitations under the License.
1225cf1a30Sjl *
1325cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl *
1925cf1a30Sjl * CDDL HEADER END
2025cf1a30Sjl */
2125cf1a30Sjl /*
2231632b73Swh * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2325cf1a30Sjl * Use is subject to license terms.
2425cf1a30Sjl */
2525cf1a30Sjl
2625cf1a30Sjl /*
27*c7a079a8SJonathan Haslam * This file contains preset event names from the Performance Application
28*c7a079a8SJonathan Haslam * Programming Interface v3.5 which included the following notice:
29*c7a079a8SJonathan Haslam *
30*c7a079a8SJonathan Haslam * Copyright (c) 2005,6
31*c7a079a8SJonathan Haslam * Innovative Computing Labs
32*c7a079a8SJonathan Haslam * Computer Science Department,
33*c7a079a8SJonathan Haslam * University of Tennessee,
34*c7a079a8SJonathan Haslam * Knoxville, TN.
35*c7a079a8SJonathan Haslam * All Rights Reserved.
36*c7a079a8SJonathan Haslam *
37*c7a079a8SJonathan Haslam *
38*c7a079a8SJonathan Haslam * Redistribution and use in source and binary forms, with or without
39*c7a079a8SJonathan Haslam * modification, are permitted provided that the following conditions are met:
40*c7a079a8SJonathan Haslam *
41*c7a079a8SJonathan Haslam * * Redistributions of source code must retain the above copyright notice,
42*c7a079a8SJonathan Haslam * this list of conditions and the following disclaimer.
43*c7a079a8SJonathan Haslam * * Redistributions in binary form must reproduce the above copyright
44*c7a079a8SJonathan Haslam * notice, this list of conditions and the following disclaimer in the
45*c7a079a8SJonathan Haslam * documentation and/or other materials provided with the distribution.
46*c7a079a8SJonathan Haslam * * Neither the name of the University of Tennessee nor the names of its
47*c7a079a8SJonathan Haslam * contributors may be used to endorse or promote products derived from
48*c7a079a8SJonathan Haslam * this software without specific prior written permission.
49*c7a079a8SJonathan Haslam *
50*c7a079a8SJonathan Haslam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51*c7a079a8SJonathan Haslam * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52*c7a079a8SJonathan Haslam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53*c7a079a8SJonathan Haslam * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
54*c7a079a8SJonathan Haslam * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55*c7a079a8SJonathan Haslam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56*c7a079a8SJonathan Haslam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57*c7a079a8SJonathan Haslam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58*c7a079a8SJonathan Haslam * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59*c7a079a8SJonathan Haslam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60*c7a079a8SJonathan Haslam * POSSIBILITY OF SUCH DAMAGE.
61*c7a079a8SJonathan Haslam *
62*c7a079a8SJonathan Haslam *
63*c7a079a8SJonathan Haslam * This open source software license conforms to the BSD License template.
6425cf1a30Sjl */
6525cf1a30Sjl
66*c7a079a8SJonathan Haslam /*
67*c7a079a8SJonathan Haslam * SPARC64 VI & VII Performance Counter Backend
68*c7a079a8SJonathan Haslam */
6925cf1a30Sjl
7025cf1a30Sjl #include <sys/cpuvar.h>
7125cf1a30Sjl #include <sys/systm.h>
7225cf1a30Sjl #include <sys/cmn_err.h>
7325cf1a30Sjl #include <sys/cpc_impl.h>
7425cf1a30Sjl #include <sys/cpc_pcbe.h>
7525cf1a30Sjl #include <sys/modctl.h>
7625cf1a30Sjl #include <sys/machsystm.h>
7725cf1a30Sjl #include <sys/sdt.h>
7825cf1a30Sjl #include <sys/cpu_impl.h>
7925cf1a30Sjl
8025cf1a30Sjl static int opl_pcbe_init(void);
8125cf1a30Sjl static uint_t opl_pcbe_ncounters(void);
8225cf1a30Sjl static const char *opl_pcbe_impl_name(void);
8325cf1a30Sjl static const char *opl_pcbe_cpuref(void);
8425cf1a30Sjl static char *opl_pcbe_list_events(uint_t picnum);
8525cf1a30Sjl static char *opl_pcbe_list_attrs(void);
8625cf1a30Sjl static uint64_t opl_pcbe_event_coverage(char *event);
8725cf1a30Sjl static uint64_t opl_pcbe_overflow_bitmap(void);
8825cf1a30Sjl static int opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
8925cf1a30Sjl uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
9025cf1a30Sjl void *token);
9125cf1a30Sjl static void opl_pcbe_program(void *token);
9225cf1a30Sjl static void opl_pcbe_allstop(void);
9325cf1a30Sjl static void opl_pcbe_sample(void *token);
9425cf1a30Sjl static void opl_pcbe_free(void *config);
9525cf1a30Sjl
9625cf1a30Sjl extern void ultra_setpcr(uint64_t);
9725cf1a30Sjl extern uint64_t ultra_getpcr(void);
9825cf1a30Sjl extern void ultra_setpic(uint64_t);
9925cf1a30Sjl extern uint64_t ultra_getpic(void);
10025cf1a30Sjl extern uint64_t ultra_gettick(void);
10125cf1a30Sjl
10225cf1a30Sjl pcbe_ops_t opl_pcbe_ops = {
10325cf1a30Sjl PCBE_VER_1,
10425cf1a30Sjl CPC_CAP_OVERFLOW_INTERRUPT,
10525cf1a30Sjl opl_pcbe_ncounters,
10625cf1a30Sjl opl_pcbe_impl_name,
10725cf1a30Sjl opl_pcbe_cpuref,
10825cf1a30Sjl opl_pcbe_list_events,
10925cf1a30Sjl opl_pcbe_list_attrs,
11025cf1a30Sjl opl_pcbe_event_coverage,
11125cf1a30Sjl opl_pcbe_overflow_bitmap,
11225cf1a30Sjl opl_pcbe_configure,
11325cf1a30Sjl opl_pcbe_program,
11425cf1a30Sjl opl_pcbe_allstop,
11525cf1a30Sjl opl_pcbe_sample,
11625cf1a30Sjl opl_pcbe_free
11725cf1a30Sjl };
11825cf1a30Sjl
11925cf1a30Sjl typedef struct _opl_pcbe_config {
12025cf1a30Sjl uint8_t opl_picno; /* From 0 to 7 */
12125cf1a30Sjl uint32_t opl_bits; /* %pcr event code unshifted */
12225cf1a30Sjl uint32_t opl_flags; /* user/system/priv */
12325cf1a30Sjl uint32_t opl_pic; /* unshifted raw %pic value */
12425cf1a30Sjl } opl_pcbe_config_t;
12525cf1a30Sjl
12625cf1a30Sjl struct nametable {
12725cf1a30Sjl const uint8_t bits;
12825cf1a30Sjl const char *name;
12925cf1a30Sjl };
13025cf1a30Sjl
131*c7a079a8SJonathan Haslam typedef struct _opl_generic_event {
132*c7a079a8SJonathan Haslam char *name;
133*c7a079a8SJonathan Haslam char *event;
134*c7a079a8SJonathan Haslam } opl_generic_event_t;
135*c7a079a8SJonathan Haslam
136d1e4508aSsubhan /*
137d1e4508aSsubhan * Performance Control Register (PCR)
138d1e4508aSsubhan *
139d1e4508aSsubhan * +----------+-----+-----+------+----+
140d1e4508aSsubhan * | 0 | OVF | 0 | OVR0 | 0 |
141d1e4508aSsubhan * +----------+-----+-----+------+----+
142d1e4508aSsubhan * 63 48 47:32 31:27 26 25
143d1e4508aSsubhan *
144d1e4508aSsubhan * +----+----+--- -+----+-----+---+-----+-----+----+----+----+
145d1e4508aSsubhan * | NC | 0 | SC | 0 | SU | 0 | SL |ULRO | UT | ST |PRIV|
146d1e4508aSsubhan * +----+----+-----+----+-----+---+-----+-----+----+----+----+
147d1e4508aSsubhan * 24:22 21 20:18 17 16:11 10 9:4 3 2 1 0
148d1e4508aSsubhan *
1495a1b32ccSsubhan * ULRO and OVRO bits should be on upon accessing pcr unless
1505a1b32ccSsubhan * those fields need to be updated.
1515a1b32ccSsubhan * Turn off these bits when updating SU/SL or OVF field
1525a1b32ccSsubhan * (during initialization, etc.).
1535a1b32ccSsubhan *
154d1e4508aSsubhan *
155d1e4508aSsubhan * Performance Instrumentation Counter (PIC)
156e98fafb9Sjl * Four PICs are implemented in SPARC64 VI and VII,
157d1e4508aSsubhan * each PIC is accessed using PCR.SC as a select field.
158d1e4508aSsubhan *
159d1e4508aSsubhan * +------------------------+--------------------------+
160d1e4508aSsubhan * | PICU | PICL |
161d1e4508aSsubhan * +------------------------+--------------------------+
162d1e4508aSsubhan * 63 32 31 0
163d1e4508aSsubhan */
164d1e4508aSsubhan
16525cf1a30Sjl #define PIC_MASK (((uint64_t)1 << 32) - 1)
16625cf1a30Sjl
167d1e4508aSsubhan #define SPARC64_VI_PCR_PRIVPIC UINT64_C(0)
16825cf1a30Sjl
16925cf1a30Sjl #define CPC_SPARC64_VI_PCR_SYS_SHIFT 1
170d1e4508aSsubhan #define CPC_SPARC64_VI_PCR_USR_SHIFT 2
17125cf1a30Sjl
17225cf1a30Sjl #define CPC_SPARC64_VI_PCR_PICL_SHIFT 4
17325cf1a30Sjl #define CPC_SPARC64_VI_PCR_PICU_SHIFT 11
174d1e4508aSsubhan #define CPC_SPARC64_VI_PCR_PIC_MASK UINT64_C(0x3F)
17525cf1a30Sjl
17625cf1a30Sjl #define CPC_SPARC64_VI_NPIC 8
17725cf1a30Sjl
17825cf1a30Sjl #define CPC_SPARC64_VI_PCR_ULRO_SHIFT 3
17925cf1a30Sjl #define CPC_SPARC64_VI_PCR_SC_SHIFT 18
18025cf1a30Sjl #define CPC_SPARC64_VI_PCR_SC_MASK UINT64_C(0x7)
18125cf1a30Sjl #define CPC_SPARC64_VI_PCR_NC_SHIFT 22
18225cf1a30Sjl #define CPC_SPARC64_VI_PCR_NC_MASK UINT64_C(0x7)
18325cf1a30Sjl #define CPC_SPARC64_VI_PCR_OVRO_SHIFT 26
18425cf1a30Sjl #define CPC_SPARC64_VI_PCR_OVF_SHIFT 32
18525cf1a30Sjl #define CPC_SPARC64_VI_PCR_OVF_MASK UINT64_C(0xffff)
18625cf1a30Sjl
18725cf1a30Sjl #define SPARC64_VI_PCR_SYS (UINT64_C(1) << CPC_SPARC64_VI_PCR_SYS_SHIFT)
18825cf1a30Sjl #define SPARC64_VI_PCR_USR (UINT64_C(1) << CPC_SPARC64_VI_PCR_USR_SHIFT)
18925cf1a30Sjl #define SPARC64_VI_PCR_ULRO (UINT64_C(1) << CPC_SPARC64_VI_PCR_ULRO_SHIFT)
19025cf1a30Sjl #define SPARC64_VI_PCR_OVRO (UINT64_C(1) << CPC_SPARC64_VI_PCR_OVRO_SHIFT)
19125cf1a30Sjl #define SPARC64_VI_PCR_OVF (CPC_SPARC64_VI_PCR_OVF_MASK << \
19225cf1a30Sjl CPC_SPARC64_VI_PCR_OVF_SHIFT)
19325cf1a30Sjl
19425cf1a30Sjl #define SPARC64_VI_NUM_PIC_PAIRS 4
19525cf1a30Sjl
19625cf1a30Sjl #define SPARC64_VI_PCR_SEL_PIC(pcr, picno) { \
19725cf1a30Sjl pcr &= ~((CPC_SPARC64_VI_PCR_SC_MASK \
19825cf1a30Sjl << CPC_SPARC64_VI_PCR_SC_SHIFT)); \
19925cf1a30Sjl \
20025cf1a30Sjl pcr |= (((picno) & CPC_SPARC64_VI_PCR_SC_MASK) \
20125cf1a30Sjl << CPC_SPARC64_VI_PCR_SC_SHIFT); \
20225cf1a30Sjl }
20325cf1a30Sjl
20425cf1a30Sjl #define SPARC64_VI_PCR_SEL_EVENT(pcr, sl, su) { \
20525cf1a30Sjl pcr &= ~((CPC_SPARC64_VI_PCR_PIC_MASK \
20625cf1a30Sjl << CPC_SPARC64_VI_PCR_PICL_SHIFT) \
20725cf1a30Sjl | (CPC_SPARC64_VI_PCR_PIC_MASK \
20825cf1a30Sjl << CPC_SPARC64_VI_PCR_PICU_SHIFT)); \
20925cf1a30Sjl \
21025cf1a30Sjl pcr |= (((sl) & CPC_SPARC64_VI_PCR_PIC_MASK) \
21125cf1a30Sjl << CPC_SPARC64_VI_PCR_PICL_SHIFT); \
21225cf1a30Sjl pcr |= (((su) & CPC_SPARC64_VI_PCR_PIC_MASK) \
21325cf1a30Sjl << CPC_SPARC64_VI_PCR_PICU_SHIFT); \
21425cf1a30Sjl }
21525cf1a30Sjl
2165a1b32ccSsubhan #define SPARC64_VI_CHK_OVF(pcr, picno) \
2175a1b32ccSsubhan ((pcr) & (UINT64_C(1) << (CPC_SPARC64_VI_PCR_OVF_SHIFT + picno)))
2185a1b32ccSsubhan
2195a1b32ccSsubhan #define SPARC64_VI_CLR_OVF(pcr, picno) { \
2205a1b32ccSsubhan pcr &= ~(UINT64_C(1) << (CPC_SPARC64_VI_PCR_OVF_SHIFT + picno)); \
2215a1b32ccSsubhan }
2225a1b32ccSsubhan
22325cf1a30Sjl #define NT_END 0xFF
224*c7a079a8SJonathan Haslam #define CPC_GEN_END { NULL, NULL }
22525cf1a30Sjl
22625cf1a30Sjl static const uint64_t allstopped = SPARC64_VI_PCR_PRIVPIC |
22725cf1a30Sjl SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO;
22825cf1a30Sjl
2295a1b32ccSsubhan #define SPARC64_VI_EVENTS_comm_0 \
23025cf1a30Sjl {0x0, "cycle_counts"}, \
2315a1b32ccSsubhan {0x1, "instruction_counts"}
2325a1b32ccSsubhan
2335a1b32ccSsubhan #define SPARC64_VI_EVENTS_comm_1 \
2345a1b32ccSsubhan {0x5, "op_stv_wait"}, \
23525cf1a30Sjl {0x8, "load_store_instructions"}, \
23625cf1a30Sjl {0x9, "branch_instructions"}, \
23725cf1a30Sjl {0xa, "floating_instructions"}, \
23825cf1a30Sjl {0xb, "impdep2_instructions"}, \
23925cf1a30Sjl {0xc, "prefetch_instructions"}
24025cf1a30Sjl
2415a1b32ccSsubhan #define SPARC64_VI_EVENTS_comm_2 \
2425a1b32ccSsubhan {0x1a, "active_cycle_count"}
2435a1b32ccSsubhan
24425cf1a30Sjl static const struct nametable SPARC64_VI_names_l0[] = {
2455a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
246e98fafb9Sjl {0x2, "only_this_thread_active"},
247e98fafb9Sjl {0x3, "w_cse_window_empty"},
248e98fafb9Sjl {0x4, "w_op_stv_wait_nc_pend"},
2495a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
2505a1b32ccSsubhan {0x12, "flush_rs"},
2515a1b32ccSsubhan {0x13, "2iid_use"},
252caf02165Ssubhan {0x15, "toq_rsbr_phantom"},
25325cf1a30Sjl {0x16, "trap_int_vector"},
2545a1b32ccSsubhan {0x18, "ts_by_sxmiss"},
255e98fafb9Sjl {0x18, "both_threads_active"},
2565a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
2575a1b32ccSsubhan {0x1d, "op_stv_wait_sxmiss"},
258caf02165Ssubhan {0x1e, "eu_comp_wait"},
259e98fafb9Sjl {0x23, "op_l1_thrashing"},
2605a1b32ccSsubhan {0x24, "swpf_fail_all"},
26125cf1a30Sjl {0x30, "sx_miss_wait_pf"},
26225cf1a30Sjl {0x31, "jbus_cpi_count"},
2635a1b32ccSsubhan {0x36, "jbus_reqbus1_busy"},
26425cf1a30Sjl {NT_END, ""}
26525cf1a30Sjl };
26625cf1a30Sjl
26725cf1a30Sjl static const struct nametable SPARC64_VI_names_u0[] = {
2685a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
2695a1b32ccSsubhan {0x2, "instruction_flow_counts"},
2705a1b32ccSsubhan {0x3, "iwr_empty"},
2715a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
2725a1b32ccSsubhan {0x12, "rs1"},
2735a1b32ccSsubhan {0x13, "1iid_use"},
27425cf1a30Sjl {0x16, "trap_all"},
2755a1b32ccSsubhan {0x18, "thread_switch_all"},
276e98fafb9Sjl {0x18, "only_this_thread_active"},
2775a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
27831632b73Swh {0x1b, "rsf_pmmi"},
2795a1b32ccSsubhan {0x1d, "act_thread_suspend"},
2805a1b32ccSsubhan {0x1e, "cse_window_empty"},
2815a1b32ccSsubhan {0x1f, "inh_cmit_gpr_2write"},
282e98fafb9Sjl {0x23, "if_l1_thrashing"},
2835a1b32ccSsubhan {0x24, "swpf_success_all"},
28425cf1a30Sjl {0x30, "sx_miss_wait_dm"},
28525cf1a30Sjl {0x31, "jbus_bi_count"},
2865a1b32ccSsubhan {0x34, "lost_softpf_pfp_full"},
2875a1b32ccSsubhan {0x36, "jbus_reqbus0_busy"},
28825cf1a30Sjl {NT_END, ""}
28925cf1a30Sjl };
29025cf1a30Sjl
29125cf1a30Sjl static const struct nametable SPARC64_VI_names_l1[] = {
2925a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
293e98fafb9Sjl {0x2, "single_mode_instructions"},
294e98fafb9Sjl {0x3, "w_branch_comp_wait"},
295e98fafb9Sjl {0x4, "w_op_stv_wait_sxmiss_ex"},
2965a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
2975a1b32ccSsubhan {0x13, "4iid_use"},
2985a1b32ccSsubhan {0x15, "flush_rs"},
29925cf1a30Sjl {0x16, "trap_spill"},
3005a1b32ccSsubhan {0x18, "ts_by_timer"},
3015a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
3025a1b32ccSsubhan {0x1b, "0iid_use"},
3035a1b32ccSsubhan {0x1d, "op_stv_wait_nc_pend"},
3045a1b32ccSsubhan {0x1e, "0endop"},
30525cf1a30Sjl {0x20, "write_op_uTLB"},
30625cf1a30Sjl {0x30, "sx_miss_count_pf"},
30725cf1a30Sjl {0x31, "jbus_cpd_count"},
3085a1b32ccSsubhan {0x32, "snres_64"},
3095a1b32ccSsubhan {0x36, "jbus_reqbus3_busy"},
31025cf1a30Sjl {NT_END, ""}
31125cf1a30Sjl };
31225cf1a30Sjl
31325cf1a30Sjl static const struct nametable SPARC64_VI_names_u1[] = {
3145a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
315e98fafb9Sjl {0x2, "single_mode_cycle_counts"},
316e98fafb9Sjl {0x3, "w_eu_comp_wait"},
317e98fafb9Sjl {0x4, "w_op_stv_wait_sxmiss"},
3185a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
3195a1b32ccSsubhan {0x13, "3iid_use"},
32025cf1a30Sjl {0x16, "trap_int_level"},
3215a1b32ccSsubhan {0x18, "ts_by_data_arrive"},
322e98fafb9Sjl {0x18, "both_threads_empty"},
3235a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
3245a1b32ccSsubhan {0x1b, "op_stv_wait_nc_pend"},
3255a1b32ccSsubhan {0x1d, "op_stv_wait_sxmiss_ex"},
326caf02165Ssubhan {0x1e, "branch_comp_wait"},
32725cf1a30Sjl {0x20, "write_if_uTLB"},
32825cf1a30Sjl {0x30, "sx_miss_count_dm"},
32925cf1a30Sjl {0x31, "jbus_cpb_count"},
3305a1b32ccSsubhan {0x32, "snres_256"},
3315a1b32ccSsubhan {0x34, "lost_softpf_by_abort"},
3325a1b32ccSsubhan {0x36, "jbus_reqbus2_busy"},
33325cf1a30Sjl {NT_END, ""}
33425cf1a30Sjl };
33525cf1a30Sjl
33625cf1a30Sjl static const struct nametable SPARC64_VI_names_l2[] = {
3375a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
338e98fafb9Sjl {0x2, "d_move_wait"},
339e98fafb9Sjl {0x3, "w_op_stv_wait"},
340e98fafb9Sjl {0x4, "w_fl_comp_wait"},
3415a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
3425a1b32ccSsubhan {0x13, "sync_intlk"},
34325cf1a30Sjl {0x16, "trap_trap_inst"},
3445a1b32ccSsubhan {0x18, "ts_by_if"},
3455a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
3465a1b32ccSsubhan {0x1e, "fl_comp_wait"},
34725cf1a30Sjl {0x20, "op_r_iu_req_mi_go"},
34825cf1a30Sjl {0x30, "sx_read_count_pf"},
349caf02165Ssubhan {0x31, "jbus_odrbus_busy"},
3505a1b32ccSsubhan {0x33, "sx_miss_count_dm_if"},
3515a1b32ccSsubhan {0x36, "jbus_odrbus1_busy"},
35225cf1a30Sjl {NT_END, ""}
35325cf1a30Sjl };
35425cf1a30Sjl
35525cf1a30Sjl static const struct nametable SPARC64_VI_names_u2[] = {
3565a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
3575a1b32ccSsubhan {0x2, "instruction_flow_counts"},
3585a1b32ccSsubhan {0x3, "iwr_empty"},
3595a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
36025cf1a30Sjl {0x16, "trap_fill"},
3615a1b32ccSsubhan {0x18, "ts_by_intr"},
3625a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
3635a1b32ccSsubhan {0x1b, "flush_rs"},
3645a1b32ccSsubhan {0x1d, "cse_window_empty_sp_full"},
3655a1b32ccSsubhan {0x1e, "op_stv_wait_ex"},
3665a1b32ccSsubhan {0x1f, "3endop"},
36725cf1a30Sjl {0x20, "if_r_iu_req_mi_go"},
3685a1b32ccSsubhan {0x24, "swpf_lbs_hit"},
36925cf1a30Sjl {0x30, "sx_read_count_dm"},
3705a1b32ccSsubhan {0x31, "jbus_reqbus_busy"},
3715a1b32ccSsubhan {0x33, "sx_btc_count"},
3725a1b32ccSsubhan {0x36, "jbus_odrbus0_busy"},
37325cf1a30Sjl {NT_END, ""}
37425cf1a30Sjl };
37525cf1a30Sjl
37625cf1a30Sjl static const struct nametable SPARC64_VI_names_l3[] = {
3775a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
378e98fafb9Sjl {0x2, "xma_inst"},
379e98fafb9Sjl {0x3, "w_0endop"},
380e98fafb9Sjl {0x4, "w_op_stv_wait_ex"},
3815a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
38225cf1a30Sjl {0x16, "trap_DMMU_miss"},
3835a1b32ccSsubhan {0x18, "ts_by_suspend"},
3845a1b32ccSsubhan {0x19, "ts_by_other"},
3855a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
3865a1b32ccSsubhan {0x1b, "decall_intlk"},
3875a1b32ccSsubhan {0x1e, "2endop"},
3885a1b32ccSsubhan {0x1f, "op_stv_wait_sxmiss"},
38925cf1a30Sjl {0x20, "op_wait_all"},
39025cf1a30Sjl {0x30, "dvp_count_pf"},
3915a1b32ccSsubhan {0x33, "sx_miss_count_dm_opex"},
3925a1b32ccSsubhan {0x36, "jbus_odrbus3_busy"},
39325cf1a30Sjl {NT_END, ""}
39425cf1a30Sjl };
39525cf1a30Sjl
39625cf1a30Sjl static const struct nametable SPARC64_VI_names_u3[] = {
3975a1b32ccSsubhan SPARC64_VI_EVENTS_comm_0,
398e98fafb9Sjl {0x2, "cse_priority_wait"},
399e98fafb9Sjl {0x3, "w_d_move"},
400e98fafb9Sjl {0x4, "w_cse_window_empty_sp_full"},
4015a1b32ccSsubhan SPARC64_VI_EVENTS_comm_1,
4025a1b32ccSsubhan {0x13, "regwin_intlk"},
4035a1b32ccSsubhan {0x15, "rs1"},
40425cf1a30Sjl {0x16, "trap_IMMU_miss"},
4055a1b32ccSsubhan SPARC64_VI_EVENTS_comm_2,
406e98fafb9Sjl {0x1d, "both_threads_suspended"},
4075a1b32ccSsubhan {0x1e, "1endop"},
4085a1b32ccSsubhan {0x1f, "op_stv_wait_sxmiss_ex"},
40925cf1a30Sjl {0x20, "if_wait_all"},
41025cf1a30Sjl {0x30, "dvp_count_dm"},
4115a1b32ccSsubhan {0x33, "sx_miss_count_dm_opsh"},
4125a1b32ccSsubhan {0x36, "jbus_odrbus2_busy"},
41325cf1a30Sjl {NT_END, ""}
41425cf1a30Sjl };
41525cf1a30Sjl
4165a1b32ccSsubhan #undef SPARC64_VI_EVENTS_comm_0
4175a1b32ccSsubhan #undef SPARC64_VI_EVENTS_comm_1
4185a1b32ccSsubhan #undef SPARC64_VI_EVENTS_comm_2
41925cf1a30Sjl
42025cf1a30Sjl static const struct nametable *SPARC64_VI_names[CPC_SPARC64_VI_NPIC] = {
42125cf1a30Sjl SPARC64_VI_names_l0,
42225cf1a30Sjl SPARC64_VI_names_u0,
42325cf1a30Sjl SPARC64_VI_names_l1,
42425cf1a30Sjl SPARC64_VI_names_u1,
42525cf1a30Sjl SPARC64_VI_names_l2,
42625cf1a30Sjl SPARC64_VI_names_u2,
42725cf1a30Sjl SPARC64_VI_names_l3,
42825cf1a30Sjl SPARC64_VI_names_u3
42925cf1a30Sjl };
43025cf1a30Sjl
43125cf1a30Sjl opl_pcbe_config_t nullpic[CPC_SPARC64_VI_NPIC] = {
43225cf1a30Sjl {0, 0x3f, 0, 0},
43325cf1a30Sjl {1, 0x3f, 0, 0},
43425cf1a30Sjl {2, 0x3f, 0, 0},
43525cf1a30Sjl {3, 0x3f, 0, 0},
43625cf1a30Sjl {4, 0x3f, 0, 0},
43725cf1a30Sjl {5, 0x3f, 0, 0},
43825cf1a30Sjl {6, 0x3f, 0, 0},
43925cf1a30Sjl {7, 0x3f, 0, 0}
44025cf1a30Sjl };
44125cf1a30Sjl
442*c7a079a8SJonathan Haslam #define SPARC64_VI_GENERIC_EVENTS_comm \
443*c7a079a8SJonathan Haslam { "PAPI_tot_cyc", "cycle_counts" }, \
444*c7a079a8SJonathan Haslam { "PAPI_tot_ins", "instruction_counts" }, \
445*c7a079a8SJonathan Haslam { "PAPI_br_tkn", "branch_instructions" }, \
446*c7a079a8SJonathan Haslam { "PAPI_fp_ops", "floating_instructions" }, \
447*c7a079a8SJonathan Haslam { "PAPI_fma_ins", "impdep2_instructions" }
448*c7a079a8SJonathan Haslam
449*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_l0[] = {
450*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
451*c7a079a8SJonathan Haslam CPC_GEN_END
452*c7a079a8SJonathan Haslam };
453*c7a079a8SJonathan Haslam
454*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_u0[] = {
455*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
456*c7a079a8SJonathan Haslam CPC_GEN_END
457*c7a079a8SJonathan Haslam };
458*c7a079a8SJonathan Haslam
459*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_l1[] = {
460*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
461*c7a079a8SJonathan Haslam CPC_GEN_END
462*c7a079a8SJonathan Haslam };
463*c7a079a8SJonathan Haslam
464*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_u1[] = {
465*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
466*c7a079a8SJonathan Haslam CPC_GEN_END
467*c7a079a8SJonathan Haslam };
468*c7a079a8SJonathan Haslam
469*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_l2[] = {
470*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
471*c7a079a8SJonathan Haslam { "PAPI_l1_dcm", "op_r_iu_req_mi_go" },
472*c7a079a8SJonathan Haslam CPC_GEN_END
473*c7a079a8SJonathan Haslam };
474*c7a079a8SJonathan Haslam
475*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_u2[] = {
476*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
477*c7a079a8SJonathan Haslam { "PAPI_l1_icm", "if_r_iu_req_mi_go" },
478*c7a079a8SJonathan Haslam CPC_GEN_END
479*c7a079a8SJonathan Haslam };
480*c7a079a8SJonathan Haslam
481*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_l3[] = {
482*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
483*c7a079a8SJonathan Haslam { "PAPI_tlb_dm", "trap_DMMU_miss" },
484*c7a079a8SJonathan Haslam CPC_GEN_END
485*c7a079a8SJonathan Haslam };
486*c7a079a8SJonathan Haslam
487*c7a079a8SJonathan Haslam static const opl_generic_event_t SPARC64_VI_generic_names_u3[] = {
488*c7a079a8SJonathan Haslam SPARC64_VI_GENERIC_EVENTS_comm,
489*c7a079a8SJonathan Haslam { "PAPI_tlb_im", "trap_IMMU_miss" },
490*c7a079a8SJonathan Haslam CPC_GEN_END
491*c7a079a8SJonathan Haslam };
492*c7a079a8SJonathan Haslam
493*c7a079a8SJonathan Haslam static const opl_generic_event_t
494*c7a079a8SJonathan Haslam *SPARC64_VI_generic_names[CPC_SPARC64_VI_NPIC] = {
495*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_l0,
496*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_u0,
497*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_l1,
498*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_u1,
499*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_l2,
500*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_u2,
501*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_l3,
502*c7a079a8SJonathan Haslam SPARC64_VI_generic_names_u3
503*c7a079a8SJonathan Haslam };
504*c7a079a8SJonathan Haslam
50525cf1a30Sjl static const struct nametable **events;
506*c7a079a8SJonathan Haslam static const opl_generic_event_t **generic_events;
50725cf1a30Sjl static const char *opl_impl_name;
50825cf1a30Sjl static const char *opl_cpuref;
50925cf1a30Sjl static char *pic_events[CPC_SPARC64_VI_NPIC];
51025cf1a30Sjl
511e98fafb9Sjl static const char *sp_6_ref = "See the \"SPARC64 VI extensions\" and "
512e98fafb9Sjl "\"SPARC64 VII extensions\" for descriptions of these events.";
51325cf1a30Sjl
51425cf1a30Sjl static int
opl_pcbe_init(void)51525cf1a30Sjl opl_pcbe_init(void)
51625cf1a30Sjl {
517*c7a079a8SJonathan Haslam const struct nametable *n;
518*c7a079a8SJonathan Haslam const opl_generic_event_t *gevp;
519*c7a079a8SJonathan Haslam int i;
520*c7a079a8SJonathan Haslam size_t size;
52125cf1a30Sjl
52225cf1a30Sjl /*
52325cf1a30Sjl * Discover type of CPU
52425cf1a30Sjl *
52525cf1a30Sjl * Point nametable to that CPU's table
52625cf1a30Sjl */
52725cf1a30Sjl switch (ULTRA_VER_IMPL(ultra_getver())) {
52825cf1a30Sjl case OLYMPUS_C_IMPL:
529e98fafb9Sjl case JUPITER_IMPL:
53025cf1a30Sjl events = SPARC64_VI_names;
531*c7a079a8SJonathan Haslam generic_events = SPARC64_VI_generic_names;
532e98fafb9Sjl opl_impl_name = "SPARC64 VI & VII";
53325cf1a30Sjl opl_cpuref = sp_6_ref;
53425cf1a30Sjl break;
53525cf1a30Sjl default:
53625cf1a30Sjl return (-1);
53725cf1a30Sjl }
53825cf1a30Sjl
53925cf1a30Sjl /*
54025cf1a30Sjl * Initialize the list of events for each PIC.
54125cf1a30Sjl * Do two passes: one to compute the size necessary and another
54225cf1a30Sjl * to copy the strings. Need room for event, comma, and NULL terminator.
54325cf1a30Sjl */
54425cf1a30Sjl for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
54525cf1a30Sjl size = 0;
54625cf1a30Sjl for (n = events[i]; n->bits != NT_END; n++)
54725cf1a30Sjl size += strlen(n->name) + 1;
548*c7a079a8SJonathan Haslam for (gevp = generic_events[i]; gevp->name != NULL; gevp++)
549*c7a079a8SJonathan Haslam size += strlen(gevp->name) + 1;
55025cf1a30Sjl pic_events[i] = kmem_alloc(size + 1, KM_SLEEP);
55125cf1a30Sjl *pic_events[i] = '\0';
55225cf1a30Sjl for (n = events[i]; n->bits != NT_END; n++) {
55325cf1a30Sjl (void) strcat(pic_events[i], n->name);
55425cf1a30Sjl (void) strcat(pic_events[i], ",");
55525cf1a30Sjl }
556*c7a079a8SJonathan Haslam for (gevp = generic_events[i]; gevp->name != NULL; gevp++) {
557*c7a079a8SJonathan Haslam (void) strcat(pic_events[i], gevp->name);
558*c7a079a8SJonathan Haslam (void) strcat(pic_events[i], ",");
559*c7a079a8SJonathan Haslam }
560*c7a079a8SJonathan Haslam
56125cf1a30Sjl /*
56225cf1a30Sjl * Remove trailing comma.
56325cf1a30Sjl */
56425cf1a30Sjl pic_events[i][size - 1] = '\0';
56525cf1a30Sjl }
56625cf1a30Sjl
56725cf1a30Sjl return (0);
56825cf1a30Sjl }
56925cf1a30Sjl
57025cf1a30Sjl static uint_t
opl_pcbe_ncounters(void)57125cf1a30Sjl opl_pcbe_ncounters(void)
57225cf1a30Sjl {
57325cf1a30Sjl return (CPC_SPARC64_VI_NPIC);
57425cf1a30Sjl }
57525cf1a30Sjl
57625cf1a30Sjl static const char *
opl_pcbe_impl_name(void)57725cf1a30Sjl opl_pcbe_impl_name(void)
57825cf1a30Sjl {
57925cf1a30Sjl return (opl_impl_name);
58025cf1a30Sjl }
58125cf1a30Sjl
58225cf1a30Sjl static const char *
opl_pcbe_cpuref(void)58325cf1a30Sjl opl_pcbe_cpuref(void)
58425cf1a30Sjl {
58525cf1a30Sjl return (opl_cpuref);
58625cf1a30Sjl }
58725cf1a30Sjl
58825cf1a30Sjl static char *
opl_pcbe_list_events(uint_t picnum)58925cf1a30Sjl opl_pcbe_list_events(uint_t picnum)
59025cf1a30Sjl {
59125cf1a30Sjl ASSERT(picnum >= 0 && picnum < cpc_ncounters);
59225cf1a30Sjl
59325cf1a30Sjl return (pic_events[picnum]);
59425cf1a30Sjl }
59525cf1a30Sjl
59625cf1a30Sjl static char *
opl_pcbe_list_attrs(void)59725cf1a30Sjl opl_pcbe_list_attrs(void)
59825cf1a30Sjl {
59925cf1a30Sjl return ("");
60025cf1a30Sjl }
60125cf1a30Sjl
602*c7a079a8SJonathan Haslam static const opl_generic_event_t *
find_generic_event(int regno,char * name)603*c7a079a8SJonathan Haslam find_generic_event(int regno, char *name)
604*c7a079a8SJonathan Haslam {
605*c7a079a8SJonathan Haslam const opl_generic_event_t *gevp;
606*c7a079a8SJonathan Haslam
607*c7a079a8SJonathan Haslam for (gevp = generic_events[regno]; gevp->name != NULL; gevp++)
608*c7a079a8SJonathan Haslam if (strcmp(name, gevp->name) == 0)
609*c7a079a8SJonathan Haslam return (gevp);
610*c7a079a8SJonathan Haslam
611*c7a079a8SJonathan Haslam return (NULL);
612*c7a079a8SJonathan Haslam }
613*c7a079a8SJonathan Haslam
61425cf1a30Sjl static const struct nametable *
find_event(int regno,char * name)61525cf1a30Sjl find_event(int regno, char *name)
61625cf1a30Sjl {
61725cf1a30Sjl const struct nametable *n;
61825cf1a30Sjl
61925cf1a30Sjl n = events[regno];
62025cf1a30Sjl
62125cf1a30Sjl for (; n->bits != NT_END; n++)
62225cf1a30Sjl if (strcmp(name, n->name) == 0)
62325cf1a30Sjl return (n);
62425cf1a30Sjl
62525cf1a30Sjl return (NULL);
62625cf1a30Sjl }
62725cf1a30Sjl
62825cf1a30Sjl static uint64_t
opl_pcbe_event_coverage(char * event)62925cf1a30Sjl opl_pcbe_event_coverage(char *event)
63025cf1a30Sjl {
63125cf1a30Sjl uint64_t bitmap = 0;
63225cf1a30Sjl
63325cf1a30Sjl int i;
63425cf1a30Sjl for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
635*c7a079a8SJonathan Haslam if ((find_event(i, event) != NULL) ||
636*c7a079a8SJonathan Haslam (find_generic_event(i, event) != NULL))
63725cf1a30Sjl bitmap |= (1 << i);
63825cf1a30Sjl }
63925cf1a30Sjl
64025cf1a30Sjl return (bitmap);
64125cf1a30Sjl }
64225cf1a30Sjl
64325cf1a30Sjl /*
644d1e4508aSsubhan * Check if counter overflow and clear it.
64525cf1a30Sjl */
64625cf1a30Sjl static uint64_t
opl_pcbe_overflow_bitmap(void)64725cf1a30Sjl opl_pcbe_overflow_bitmap(void)
64825cf1a30Sjl {
6495a1b32ccSsubhan uint64_t pcr;
65025cf1a30Sjl
65125cf1a30Sjl pcr = ultra_getpcr();
652d1e4508aSsubhan DTRACE_PROBE1(sparc64__getpcr, uint64_t, pcr);
653d1e4508aSsubhan
6545a1b32ccSsubhan return ((pcr & SPARC64_VI_PCR_OVF) >> CPC_SPARC64_VI_PCR_OVF_SHIFT);
65525cf1a30Sjl }
65625cf1a30Sjl
65725cf1a30Sjl /*ARGSUSED*/
65825cf1a30Sjl static int
opl_pcbe_configure(uint_t picnum,char * event,uint64_t preset,uint32_t flags,uint_t nattrs,kcpc_attr_t * attrs,void ** data,void * token)65925cf1a30Sjl opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
66025cf1a30Sjl uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
66125cf1a30Sjl {
662*c7a079a8SJonathan Haslam opl_pcbe_config_t *conf;
663*c7a079a8SJonathan Haslam const struct nametable *n;
664*c7a079a8SJonathan Haslam const opl_generic_event_t *gevp;
665*c7a079a8SJonathan Haslam opl_pcbe_config_t *other_config;
66625cf1a30Sjl
66725cf1a30Sjl /*
66825cf1a30Sjl * If we've been handed an existing configuration, we need only preset
66925cf1a30Sjl * the counter value.
67025cf1a30Sjl */
67125cf1a30Sjl if (*data != NULL) {
67225cf1a30Sjl conf = *data;
67325cf1a30Sjl conf->opl_pic = (uint32_t)preset;
67425cf1a30Sjl return (0);
67525cf1a30Sjl }
67625cf1a30Sjl
67725cf1a30Sjl if (picnum < 0 || picnum >= CPC_SPARC64_VI_NPIC)
67825cf1a30Sjl return (CPC_INVALID_PICNUM);
67925cf1a30Sjl
68025cf1a30Sjl if (nattrs != 0)
68125cf1a30Sjl return (CPC_INVALID_ATTRIBUTE);
68225cf1a30Sjl
68325cf1a30Sjl /*
68425cf1a30Sjl * Find other requests that will be programmed with this one, and ensure
68525cf1a30Sjl * the flags don't conflict.
68625cf1a30Sjl */
68725cf1a30Sjl if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
68825cf1a30Sjl (other_config->opl_flags != flags))
68925cf1a30Sjl return (CPC_CONFLICTING_REQS);
69025cf1a30Sjl
691*c7a079a8SJonathan Haslam if ((n = find_event(picnum, event)) == NULL) {
692*c7a079a8SJonathan Haslam if ((gevp = find_generic_event(picnum, event)) != NULL) {
693*c7a079a8SJonathan Haslam n = find_event(picnum, gevp->event);
694*c7a079a8SJonathan Haslam ASSERT(n != NULL);
695*c7a079a8SJonathan Haslam } else {
696*c7a079a8SJonathan Haslam return (CPC_INVALID_EVENT);
697*c7a079a8SJonathan Haslam }
698*c7a079a8SJonathan Haslam }
69925cf1a30Sjl
70025cf1a30Sjl conf = kmem_alloc(sizeof (opl_pcbe_config_t), KM_SLEEP);
70125cf1a30Sjl
70225cf1a30Sjl conf->opl_picno = picnum;
70325cf1a30Sjl conf->opl_bits = (uint32_t)n->bits;
70425cf1a30Sjl conf->opl_flags = flags;
70525cf1a30Sjl conf->opl_pic = (uint32_t)preset;
70625cf1a30Sjl
70725cf1a30Sjl *data = conf;
70825cf1a30Sjl return (0);
70925cf1a30Sjl }
71025cf1a30Sjl
71125cf1a30Sjl static void
opl_pcbe_program(void * token)71225cf1a30Sjl opl_pcbe_program(void *token)
71325cf1a30Sjl {
71425cf1a30Sjl opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC];
71525cf1a30Sjl opl_pcbe_config_t *firstconfig;
71625cf1a30Sjl opl_pcbe_config_t *tmp;
71725cf1a30Sjl uint64_t pcr;
71825cf1a30Sjl uint64_t curpic;
71925cf1a30Sjl uint8_t bitmap = 0; /* for used pic config */
72025cf1a30Sjl int i;
72125cf1a30Sjl opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC];
72225cf1a30Sjl
72325cf1a30Sjl /* Get next pic config */
72425cf1a30Sjl firstconfig = tmp = kcpc_next_config(token, NULL, NULL);
72525cf1a30Sjl
72625cf1a30Sjl while (tmp != NULL) {
72725cf1a30Sjl ASSERT(tmp->opl_picno < CPC_SPARC64_VI_NPIC);
72825cf1a30Sjl ASSERT(firstconfig->opl_flags == tmp->opl_flags);
72925cf1a30Sjl pic[tmp->opl_picno] = tmp;
73025cf1a30Sjl bitmap |= (uint8_t)(1 << tmp->opl_picno);
73125cf1a30Sjl tmp = kcpc_next_config(token, tmp, NULL);
73225cf1a30Sjl }
73325cf1a30Sjl if (bitmap == 0)
73425cf1a30Sjl panic("opl_pcbe: token %p has no configs", token);
73525cf1a30Sjl
73625cf1a30Sjl /* Fill in unused pic config */
73725cf1a30Sjl for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
73825cf1a30Sjl if (bitmap & (1 << i))
73925cf1a30Sjl continue;
74025cf1a30Sjl
74125cf1a30Sjl dummypic[i] = nullpic[i];
74225cf1a30Sjl dummypic[i].opl_flags = firstconfig->opl_flags;
743d1e4508aSsubhan pic[i] = &dummypic[i];
74425cf1a30Sjl }
74525cf1a30Sjl
74625cf1a30Sjl /*
74725cf1a30Sjl * For each counter pair, initialize event settings and
74825cf1a30Sjl * counter values.
74925cf1a30Sjl */
75025cf1a30Sjl ultra_setpcr(allstopped);
75125cf1a30Sjl pcr = allstopped;
75225cf1a30Sjl pcr &= ~SPARC64_VI_PCR_ULRO;
75325cf1a30Sjl for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
75425cf1a30Sjl SPARC64_VI_PCR_SEL_PIC(pcr, i);
75525cf1a30Sjl SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
75625cf1a30Sjl pic[i*2 + 1]->opl_bits);
75725cf1a30Sjl
75825cf1a30Sjl ultra_setpcr(pcr);
75925cf1a30Sjl curpic = (uint64_t)(pic[i*2]->opl_pic |
76025cf1a30Sjl ((uint64_t)pic[i*2 + 1]->opl_pic << 32));
76125cf1a30Sjl ultra_setpic(curpic);
76225cf1a30Sjl }
76325cf1a30Sjl
76425cf1a30Sjl /*
76525cf1a30Sjl * For each counter pair, enable the trace flags to start
76625cf1a30Sjl * counting. Re-read the counters to sample the counter value now
76725cf1a30Sjl * and use that as the baseline for future samples.
76825cf1a30Sjl */
76925cf1a30Sjl
770d1e4508aSsubhan /* Get PCR */
77125cf1a30Sjl pcr = ultra_getpcr();
7725a1b32ccSsubhan pcr |= SPARC64_VI_PCR_ULRO;
7735a1b32ccSsubhan pcr &= ~(SPARC64_VI_PCR_OVRO | SPARC64_VI_PCR_OVF);
774d1e4508aSsubhan
77525cf1a30Sjl if (pic[0]->opl_flags & CPC_COUNT_USER)
77625cf1a30Sjl pcr |= SPARC64_VI_PCR_USR;
77725cf1a30Sjl if (pic[0]->opl_flags & CPC_COUNT_SYSTEM)
77825cf1a30Sjl pcr |= SPARC64_VI_PCR_SYS;
77925cf1a30Sjl
78025cf1a30Sjl /* Set counter values */
781d1e4508aSsubhan
78225cf1a30Sjl for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
78325cf1a30Sjl SPARC64_VI_PCR_SEL_PIC(pcr, i);
78425cf1a30Sjl SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
78525cf1a30Sjl pic[i*2 + 1]->opl_bits);
78625cf1a30Sjl
78725cf1a30Sjl ultra_setpcr(pcr);
788d1e4508aSsubhan DTRACE_PROBE1(sparc64__setpcr, uint64_t, pcr);
789d1e4508aSsubhan
79025cf1a30Sjl curpic = ultra_getpic();
791d1e4508aSsubhan DTRACE_PROBE1(sparc64__newpic, uint64_t, curpic);
79225cf1a30Sjl pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK);
79325cf1a30Sjl pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32);
79425cf1a30Sjl }
7955a1b32ccSsubhan pcr |= SPARC64_VI_PCR_OVRO;
7965a1b32ccSsubhan ultra_setpcr(pcr);
79725cf1a30Sjl }
79825cf1a30Sjl
79925cf1a30Sjl static void
opl_pcbe_allstop(void)80025cf1a30Sjl opl_pcbe_allstop(void)
80125cf1a30Sjl {
80225cf1a30Sjl ultra_setpcr(allstopped);
80325cf1a30Sjl }
80425cf1a30Sjl
80525cf1a30Sjl
80625cf1a30Sjl static void
opl_pcbe_sample(void * token)80725cf1a30Sjl opl_pcbe_sample(void *token)
80825cf1a30Sjl {
80925cf1a30Sjl uint64_t curpic;
81025cf1a30Sjl uint64_t pcr;
8115a1b32ccSsubhan uint64_t overflow;
81225cf1a30Sjl int64_t diff;
81325cf1a30Sjl uint64_t *pic_data[CPC_SPARC64_VI_NPIC];
81425cf1a30Sjl uint64_t *dtmp;
81525cf1a30Sjl opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC];
81625cf1a30Sjl opl_pcbe_config_t *ctmp;
81725cf1a30Sjl opl_pcbe_config_t *firstconfig;
81825cf1a30Sjl uint8_t bitmap = 0; /* for used pic config */
81925cf1a30Sjl int i;
82025cf1a30Sjl opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC];
82125cf1a30Sjl uint64_t dummypic_data[CPC_SPARC64_VI_NPIC];
82225cf1a30Sjl
82325cf1a30Sjl /* Get next pic config */
82425cf1a30Sjl firstconfig = ctmp = kcpc_next_config(token, NULL, &dtmp);
82525cf1a30Sjl
82625cf1a30Sjl while (ctmp != NULL) {
82725cf1a30Sjl ASSERT(ctmp->opl_picno < CPC_SPARC64_VI_NPIC);
82825cf1a30Sjl ASSERT(firstconfig->opl_flags == ctmp->opl_flags);
82925cf1a30Sjl pic[ctmp->opl_picno] = ctmp;
83025cf1a30Sjl pic_data[ctmp->opl_picno] = dtmp;
83125cf1a30Sjl bitmap |= (uint8_t)(1 << ctmp->opl_picno);
83225cf1a30Sjl ctmp = kcpc_next_config(token, ctmp, &dtmp);
83325cf1a30Sjl }
83425cf1a30Sjl if (bitmap == 0)
83525cf1a30Sjl panic("opl_pcbe: token %p has no configs", token);
83625cf1a30Sjl
83725cf1a30Sjl /* Fill in unuse pic config */
83825cf1a30Sjl for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
83925cf1a30Sjl if (bitmap & (1 << i))
84025cf1a30Sjl continue;
84125cf1a30Sjl
84225cf1a30Sjl dummypic[i] = nullpic[i];
84325cf1a30Sjl dummypic[i].opl_flags = firstconfig->opl_flags;
84425cf1a30Sjl pic[i] = &dummypic[i];
84525cf1a30Sjl
84625cf1a30Sjl dummypic_data[i] = 0;
84725cf1a30Sjl pic_data[i] = &dummypic_data[i];
84825cf1a30Sjl }
84925cf1a30Sjl
85025cf1a30Sjl pcr = ultra_getpcr();
8515a1b32ccSsubhan pcr &= ~SPARC64_VI_PCR_OVRO;
8525a1b32ccSsubhan pcr |= SPARC64_VI_PCR_ULRO;
85325cf1a30Sjl
85425cf1a30Sjl for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
85525cf1a30Sjl SPARC64_VI_PCR_SEL_PIC(pcr, i);
85625cf1a30Sjl SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
85725cf1a30Sjl pic[i*2 + 1]->opl_bits);
85825cf1a30Sjl
85925cf1a30Sjl ultra_setpcr(pcr);
860d1e4508aSsubhan
86125cf1a30Sjl curpic = ultra_getpic();
862d1e4508aSsubhan DTRACE_PROBE1(sparc64__getpic, unit64_t, curpic);
86325cf1a30Sjl
8645a1b32ccSsubhan diff = (curpic & PIC_MASK) - (uint64_t)pic[i*2]->opl_pic;
8655a1b32ccSsubhan overflow = SPARC64_VI_CHK_OVF(pcr, i*2);
8665a1b32ccSsubhan if (overflow || (diff < 0)) {
8675a1b32ccSsubhan SPARC64_VI_CLR_OVF(pcr, i*2);
8685a1b32ccSsubhan ultra_setpcr(pcr);
86925cf1a30Sjl diff += (1ll << 32);
8705a1b32ccSsubhan }
87125cf1a30Sjl *pic_data[i*2] += diff;
87225cf1a30Sjl
8735a1b32ccSsubhan diff = (curpic >> 32) - (uint64_t)pic[i*2 + 1]->opl_pic;
8745a1b32ccSsubhan overflow = SPARC64_VI_CHK_OVF(pcr, i*2 + 1);
8755a1b32ccSsubhan if (overflow || (diff < 0)) {
8765a1b32ccSsubhan SPARC64_VI_CLR_OVF(pcr, i*2 + 1);
8775a1b32ccSsubhan ultra_setpcr(pcr);
87825cf1a30Sjl diff += (1ll << 32);
8795a1b32ccSsubhan }
88025cf1a30Sjl *pic_data[i*2 + 1] += diff;
88125cf1a30Sjl
88225cf1a30Sjl pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK);
88325cf1a30Sjl pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32);
88425cf1a30Sjl }
8855a1b32ccSsubhan pcr = ultra_getpcr();
8865a1b32ccSsubhan pcr |= SPARC64_VI_PCR_OVRO;
8875a1b32ccSsubhan ultra_setpcr(pcr);
88825cf1a30Sjl }
88925cf1a30Sjl
89025cf1a30Sjl static void
opl_pcbe_free(void * config)89125cf1a30Sjl opl_pcbe_free(void *config)
89225cf1a30Sjl {
89325cf1a30Sjl kmem_free(config, sizeof (opl_pcbe_config_t));
89425cf1a30Sjl }
89525cf1a30Sjl
89625cf1a30Sjl
89725cf1a30Sjl static struct modlpcbe modlpcbe = {
89825cf1a30Sjl &mod_pcbeops,
899820c9f58Skk "SPARC64 VI&VII Perf Cntrs",
90025cf1a30Sjl &opl_pcbe_ops
90125cf1a30Sjl };
90225cf1a30Sjl
90325cf1a30Sjl static struct modlinkage modl = {
90425cf1a30Sjl MODREV_1,
90525cf1a30Sjl &modlpcbe,
90625cf1a30Sjl };
90725cf1a30Sjl
90825cf1a30Sjl int
_init(void)90925cf1a30Sjl _init(void)
91025cf1a30Sjl {
91125cf1a30Sjl if (opl_pcbe_init() != 0)
91225cf1a30Sjl return (ENOTSUP);
91325cf1a30Sjl return (mod_install(&modl));
91425cf1a30Sjl }
91525cf1a30Sjl
91625cf1a30Sjl int
_fini(void)91725cf1a30Sjl _fini(void)
91825cf1a30Sjl {
91925cf1a30Sjl return (mod_remove(&modl));
92025cf1a30Sjl }
92125cf1a30Sjl
92225cf1a30Sjl int
_info(struct modinfo * mi)92325cf1a30Sjl _info(struct modinfo *mi)
92425cf1a30Sjl {
92525cf1a30Sjl return (mod_info(&modl, mi));
92625cf1a30Sjl }
927