1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <string.h>
31*7c478bd9Sstevel@tonic-gate #include <alloca.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <libintl.h>
35*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include "libcpc.h"
38*7c478bd9Sstevel@tonic-gate #include "libcpc_impl.h"
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate /*
41*7c478bd9Sstevel@tonic-gate  * Configuration data for UltraSPARC performance counters.
42*7c478bd9Sstevel@tonic-gate  *
43*7c478bd9Sstevel@tonic-gate  * Definitions taken from [1], [2], [3]  and [4].  See the references to
44*7c478bd9Sstevel@tonic-gate  * understand what any of these settings actually means.
45*7c478bd9Sstevel@tonic-gate  *
46*7c478bd9Sstevel@tonic-gate  * Note that in the current draft of [2], there is some re-use
47*7c478bd9Sstevel@tonic-gate  * of existing bit assignments in the various fields of the %pcr
48*7c478bd9Sstevel@tonic-gate  * register - this may change before FCS.
49*7c478bd9Sstevel@tonic-gate  *
50*7c478bd9Sstevel@tonic-gate  * The following are the Internal Documents. Customers need to be
51*7c478bd9Sstevel@tonic-gate  * told about the Public docs in cpc_getcpuref().
52*7c478bd9Sstevel@tonic-gate  * [1] "UltraSPARC I & II User's Manual," January 1997.
53*7c478bd9Sstevel@tonic-gate  * [2] "UltraSPARC-III Programmer's Reference Manual," April 1999.
54*7c478bd9Sstevel@tonic-gate  * [3] "Cheetah+ Programmer's Reference Manual," November 2000.
55*7c478bd9Sstevel@tonic-gate  * [4] "UltraSPARC-IIIi Programmer's Reference Manual," November 2000.
56*7c478bd9Sstevel@tonic-gate  */
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #define	V_US12		(1u << 0)	/* specific to UltraSPARC 1 and 2 */
59*7c478bd9Sstevel@tonic-gate #define	V_US3		(1u << 1)	/* specific to UltraSPARC 3 */
60*7c478bd9Sstevel@tonic-gate #define	V_US3_PLUS	(1u << 2)	/* specific to UltraSPARC 3 PLUS */
61*7c478bd9Sstevel@tonic-gate #define	V_US3_I		(1u << 3)	/* specific to UltraSPARC-IIIi */
62*7c478bd9Sstevel@tonic-gate #define	V_END		(1u << 31)
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * map from "cpu version" to flag bits
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate static const uint_t cpuvermap[] = {
68*7c478bd9Sstevel@tonic-gate 	V_US12,			/* CPC_ULTRA1 */
69*7c478bd9Sstevel@tonic-gate 	V_US12,			/* CPC_ULTRA2 */
70*7c478bd9Sstevel@tonic-gate 	V_US3,			/* CPC_ULTRA3 */
71*7c478bd9Sstevel@tonic-gate 	V_US3_PLUS,		/* CPC_ULTRA3_PLUS */
72*7c478bd9Sstevel@tonic-gate 	V_US3_I			/* CPC_ULTRA3I */
73*7c478bd9Sstevel@tonic-gate };
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate struct nametable {
76*7c478bd9Sstevel@tonic-gate 	const uint_t	ver;
77*7c478bd9Sstevel@tonic-gate 	const uint8_t	bits;
78*7c478bd9Sstevel@tonic-gate 	const char	*name;
79*7c478bd9Sstevel@tonic-gate };
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * Definitions for counter 0
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #define	USall_EVENTS_0(v)					\
86*7c478bd9Sstevel@tonic-gate 	{v,		0x0,	"Cycle_cnt"},			\
87*7c478bd9Sstevel@tonic-gate 	{v,		0x1,	"Instr_cnt"},			\
88*7c478bd9Sstevel@tonic-gate 	{v,		0x2,	"Dispatch0_IC_miss"},		\
89*7c478bd9Sstevel@tonic-gate 	{v,		0x8,	"IC_ref"},			\
90*7c478bd9Sstevel@tonic-gate 	{v,		0x9,	"DC_rd"},			\
91*7c478bd9Sstevel@tonic-gate 	{v,		0xa,	"DC_wr"},			\
92*7c478bd9Sstevel@tonic-gate 	{v,		0xc,	"EC_ref"},			\
93*7c478bd9Sstevel@tonic-gate 	{v,		0xe,	"EC_snoop_inv"}
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate static const struct nametable US12_names0[] = {
96*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_0(V_US12),
97*7c478bd9Sstevel@tonic-gate 	{V_US12,	0x3,	"Dispatch0_storeBuf"},
98*7c478bd9Sstevel@tonic-gate 	{V_US12,	0xb,	"Load_use"},
99*7c478bd9Sstevel@tonic-gate 	{V_US12,	0xd,	"EC_write_hit_RDO"},
100*7c478bd9Sstevel@tonic-gate 	{V_US12,	0xf,	"EC_rd_hit"},
101*7c478bd9Sstevel@tonic-gate 	{V_END}
102*7c478bd9Sstevel@tonic-gate };
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate #define	US3all_EVENTS_0(v)					\
105*7c478bd9Sstevel@tonic-gate 	{v,		0x3,	"Dispatch0_br_target"},		\
106*7c478bd9Sstevel@tonic-gate 	{v,		0x4,	"Dispatch0_2nd_br"},		\
107*7c478bd9Sstevel@tonic-gate 	{v,		0x5,	"Rstall_storeQ"},		\
108*7c478bd9Sstevel@tonic-gate 	{v,		0x6,	"Rstall_IU_use"},		\
109*7c478bd9Sstevel@tonic-gate 	{v,		0xd,	"EC_write_hit_RTO"},		\
110*7c478bd9Sstevel@tonic-gate 	{v,		0xf,	"EC_rd_miss"},			\
111*7c478bd9Sstevel@tonic-gate 	{v,		0x10,	"PC_port0_rd"},			\
112*7c478bd9Sstevel@tonic-gate 	{v,		0x11,	"SI_snoop"},			\
113*7c478bd9Sstevel@tonic-gate 	{v,		0x12,	"SI_ciq_flow"},			\
114*7c478bd9Sstevel@tonic-gate 	{v,		0x13,	"SI_owned"},			\
115*7c478bd9Sstevel@tonic-gate 	{v,		0x14,	"SW_count_0"},			\
116*7c478bd9Sstevel@tonic-gate 	{v,		0x15,	"IU_Stat_Br_miss_taken"},	\
117*7c478bd9Sstevel@tonic-gate 	{v,		0x16,	"IU_Stat_Br_count_taken"},	\
118*7c478bd9Sstevel@tonic-gate 	{v,		0x17,	"Dispatch_rs_mispred"},		\
119*7c478bd9Sstevel@tonic-gate 	{v,		0x18,	"FA_pipe_completion"}
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate #define	US3_MC_EVENTS_0(v)					\
122*7c478bd9Sstevel@tonic-gate 	{v,		0x20,	"MC_reads_0"},			\
123*7c478bd9Sstevel@tonic-gate 	{v,		0x21,	"MC_reads_1"},			\
124*7c478bd9Sstevel@tonic-gate 	{v,		0x22,	"MC_reads_2"},			\
125*7c478bd9Sstevel@tonic-gate 	{v,		0x23,	"MC_reads_3"},			\
126*7c478bd9Sstevel@tonic-gate 	{v,		0x24,	"MC_stalls_0"},			\
127*7c478bd9Sstevel@tonic-gate 	{v,		0x25,	"MC_stalls_2"}
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate #define	US3_I_MC_EVENTS_0(v)					\
130*7c478bd9Sstevel@tonic-gate 	{v,		0x20,	"MC_read_dispatched"},		\
131*7c478bd9Sstevel@tonic-gate 	{v,		0x21,	"MC_write_dispatched"},		\
132*7c478bd9Sstevel@tonic-gate 	{v,		0x22,	"MC_read_returned_to_JBU"},	\
133*7c478bd9Sstevel@tonic-gate 	{v,		0x23,	"MC_msl_busy_stall"},		\
134*7c478bd9Sstevel@tonic-gate 	{v,		0x24,	"MC_mdb_overflow_stall"},	\
135*7c478bd9Sstevel@tonic-gate 	{v,		0x25,	"MC_miu_spec_request"}
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate static const struct nametable US3_names0[] = {
138*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_0(V_US3),
139*7c478bd9Sstevel@tonic-gate 	US3all_EVENTS_0(V_US3),
140*7c478bd9Sstevel@tonic-gate 	US3_MC_EVENTS_0(V_US3),
141*7c478bd9Sstevel@tonic-gate 	{V_END}
142*7c478bd9Sstevel@tonic-gate };
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate static const struct nametable US3_PLUS_names0[] = {
145*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_0(V_US3_PLUS),
146*7c478bd9Sstevel@tonic-gate 	US3all_EVENTS_0(V_US3_PLUS),
147*7c478bd9Sstevel@tonic-gate 	US3_MC_EVENTS_0(V_US3_PLUS),
148*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x19,	"EC_wb_remote"},
149*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x1a,	"EC_miss_local"},
150*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x1b,	"EC_miss_mtag_remote"},
151*7c478bd9Sstevel@tonic-gate 	{V_END}
152*7c478bd9Sstevel@tonic-gate };
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate static const struct nametable US3_I_names0[] = {
155*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_0(V_US3_I),
156*7c478bd9Sstevel@tonic-gate 	US3all_EVENTS_0(V_US3_I),
157*7c478bd9Sstevel@tonic-gate 	US3_I_MC_EVENTS_0(V_US3_I),
158*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x19,	"EC_wb_remote"},
159*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x1a,	"EC_miss_local"},
160*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x1b,	"EC_miss_mtag_remote"},
161*7c478bd9Sstevel@tonic-gate 	{V_END}
162*7c478bd9Sstevel@tonic-gate };
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate #undef	USall_EVENTS_0
165*7c478bd9Sstevel@tonic-gate #undef	US3all_EVENTS_0
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate #define	USall_EVENTS_1(v)					\
168*7c478bd9Sstevel@tonic-gate 	{v,		0x0,	"Cycle_cnt"},			\
169*7c478bd9Sstevel@tonic-gate 	{v,		0x1,	"Instr_cnt"},			\
170*7c478bd9Sstevel@tonic-gate 	{v,		0x2,	"Dispatch0_mispred"},		\
171*7c478bd9Sstevel@tonic-gate 	{v,		0xd,	"EC_wb"},			\
172*7c478bd9Sstevel@tonic-gate 	{v,		0xe,	"EC_snoop_cb"}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate static const struct nametable US12_names1[] = {
175*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_1(V_US12),
176*7c478bd9Sstevel@tonic-gate 	{V_US12,	0x3,	"Dispatch0_FP_use"},
177*7c478bd9Sstevel@tonic-gate 	{V_US12,	0x8,	"IC_hit"},
178*7c478bd9Sstevel@tonic-gate 	{V_US12,	0x9,	"DC_rd_hit"},
179*7c478bd9Sstevel@tonic-gate 	{V_US12,	0xa,	"DC_wr_hit"},
180*7c478bd9Sstevel@tonic-gate 	{V_US12,	0xb,	"Load_use_RAW"},
181*7c478bd9Sstevel@tonic-gate 	{V_US12,	0xc,	"EC_hit"},
182*7c478bd9Sstevel@tonic-gate 	{V_US12,	0xf,	"EC_ic_hit"},
183*7c478bd9Sstevel@tonic-gate 	{V_END}
184*7c478bd9Sstevel@tonic-gate };
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate #define	US3all_EVENTS_1(v)					\
187*7c478bd9Sstevel@tonic-gate 	{v,		0x3,	"IC_miss_cancelled"},		\
188*7c478bd9Sstevel@tonic-gate 	{v,		0x5,	"Re_FPU_bypass"},		\
189*7c478bd9Sstevel@tonic-gate 	{v,		0x6,	"Re_DC_miss"},			\
190*7c478bd9Sstevel@tonic-gate 	{v,		0x7,	"Re_EC_miss"},			\
191*7c478bd9Sstevel@tonic-gate 	{v,		0x8,	"IC_miss"},			\
192*7c478bd9Sstevel@tonic-gate 	{v,		0x9,	"DC_rd_miss"},			\
193*7c478bd9Sstevel@tonic-gate 	{v,		0xa,	"DC_wr_miss"},			\
194*7c478bd9Sstevel@tonic-gate 	{v,		0xb,	"Rstall_FP_use"},		\
195*7c478bd9Sstevel@tonic-gate 	{v,		0xc,	"EC_misses"},			\
196*7c478bd9Sstevel@tonic-gate 	{v,		0xf,	"EC_ic_miss"},			\
197*7c478bd9Sstevel@tonic-gate 	{v,		0x10,	"Re_PC_miss"},			\
198*7c478bd9Sstevel@tonic-gate 	{v,		0x11,	"ITLB_miss"},			\
199*7c478bd9Sstevel@tonic-gate 	{v,		0x12,	"DTLB_miss"},			\
200*7c478bd9Sstevel@tonic-gate 	{v,		0x13,	"WC_miss"},			\
201*7c478bd9Sstevel@tonic-gate 	{v,		0x14,	"WC_snoop_cb"},			\
202*7c478bd9Sstevel@tonic-gate 	{v,		0x15,	"WC_scrubbed"},			\
203*7c478bd9Sstevel@tonic-gate 	{v,		0x16,	"WC_wb_wo_read"},		\
204*7c478bd9Sstevel@tonic-gate 	{v,		0x18,	"PC_soft_hit"},			\
205*7c478bd9Sstevel@tonic-gate 	{v,		0x19,	"PC_snoop_inv"},		\
206*7c478bd9Sstevel@tonic-gate 	{v,		0x1a,	"PC_hard_hit"},			\
207*7c478bd9Sstevel@tonic-gate 	{v,		0x1b,	"PC_port1_rd"},			\
208*7c478bd9Sstevel@tonic-gate 	{v,		0x1c,	"SW_count_1"},			\
209*7c478bd9Sstevel@tonic-gate 	{v,		0x1d,	"IU_Stat_Br_miss_untaken"},	\
210*7c478bd9Sstevel@tonic-gate 	{v,		0x1e,	"IU_Stat_Br_count_untaken"},	\
211*7c478bd9Sstevel@tonic-gate 	{v,		0x1f,	"PC_MS_misses"},		\
212*7c478bd9Sstevel@tonic-gate 	{v,		0x26,	"Re_RAW_miss"},			\
213*7c478bd9Sstevel@tonic-gate 	{v,		0x27,	"FM_pipe_completion"}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate #define	US3_MC_EVENTS_1(v)					\
216*7c478bd9Sstevel@tonic-gate 	{v,		0x20,	"MC_writes_0"},			\
217*7c478bd9Sstevel@tonic-gate 	{v,		0x21,	"MC_writes_1"},			\
218*7c478bd9Sstevel@tonic-gate 	{v,		0x22,	"MC_writes_2"},			\
219*7c478bd9Sstevel@tonic-gate 	{v,		0x23,	"MC_writes_3"},			\
220*7c478bd9Sstevel@tonic-gate 	{v,		0x24,	"MC_stalls_1"},			\
221*7c478bd9Sstevel@tonic-gate 	{v,		0x25,	"MC_stalls_3"}
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate #define	US3_I_MC_EVENTS_1(v)					\
224*7c478bd9Sstevel@tonic-gate 	{v,		0x20,	"MC_open_bank_cmds"},		\
225*7c478bd9Sstevel@tonic-gate 	{v,		0x21,	"MC_reads"},			\
226*7c478bd9Sstevel@tonic-gate 	{v,		0x22,	"MC_writes"},			\
227*7c478bd9Sstevel@tonic-gate 	{v,		0x23,	"MC_page_close_stall"}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate static const struct nametable US3_names1[] = {
230*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_1(V_US3),
231*7c478bd9Sstevel@tonic-gate 	US3all_EVENTS_1(V_US3),
232*7c478bd9Sstevel@tonic-gate 	US3_MC_EVENTS_1(V_US3),
233*7c478bd9Sstevel@tonic-gate 	{V_US3,		0x4,	"Re_endian_miss"},
234*7c478bd9Sstevel@tonic-gate 	{V_END}
235*7c478bd9Sstevel@tonic-gate };
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate static const struct nametable US3_PLUS_names1[] = {
238*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_1(V_US3_PLUS),
239*7c478bd9Sstevel@tonic-gate 	US3all_EVENTS_1(V_US3_PLUS),
240*7c478bd9Sstevel@tonic-gate 	US3_MC_EVENTS_1(V_US3_PLUS),
241*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x4,	"Re_DC_missovhd"},
242*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x28,	"EC_miss_mtag_remote"},
243*7c478bd9Sstevel@tonic-gate 	{V_US3_PLUS,	0x29,	"EC_miss_remote"},
244*7c478bd9Sstevel@tonic-gate 	{V_END}
245*7c478bd9Sstevel@tonic-gate };
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate static const struct nametable US3_I_names1[] = {
248*7c478bd9Sstevel@tonic-gate 	USall_EVENTS_1(V_US3_I),
249*7c478bd9Sstevel@tonic-gate 	US3all_EVENTS_1(V_US3_I),
250*7c478bd9Sstevel@tonic-gate 	US3_I_MC_EVENTS_1(V_US3_I),
251*7c478bd9Sstevel@tonic-gate 	{V_US3_I,	0x4,	"Re_DC_missovhd"},
252*7c478bd9Sstevel@tonic-gate 	{V_END}
253*7c478bd9Sstevel@tonic-gate };
254*7c478bd9Sstevel@tonic-gate #undef	USall_EVENTS_1
255*7c478bd9Sstevel@tonic-gate #undef	US3all_EVENTS_1
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate static const struct nametable *US12_names[2] = {
258*7c478bd9Sstevel@tonic-gate 	US12_names0,
259*7c478bd9Sstevel@tonic-gate 	US12_names1
260*7c478bd9Sstevel@tonic-gate };
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate static const struct nametable *US3_names[2] = {
263*7c478bd9Sstevel@tonic-gate 	US3_names0,
264*7c478bd9Sstevel@tonic-gate 	US3_names1
265*7c478bd9Sstevel@tonic-gate };
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate static const struct nametable *US3_PLUS_names[2] = {
268*7c478bd9Sstevel@tonic-gate 	US3_PLUS_names0,
269*7c478bd9Sstevel@tonic-gate 	US3_PLUS_names1
270*7c478bd9Sstevel@tonic-gate };
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate static const struct nametable *US3_I_names[2] = {
273*7c478bd9Sstevel@tonic-gate 	US3_I_names0,
274*7c478bd9Sstevel@tonic-gate 	US3_I_names1
275*7c478bd9Sstevel@tonic-gate };
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate #define	MAPCPUVER(cpuver)	(cpuvermap[(cpuver) - CPC_ULTRA1])
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate static int
280*7c478bd9Sstevel@tonic-gate validargs(int cpuver, int regno)
281*7c478bd9Sstevel@tonic-gate {
282*7c478bd9Sstevel@tonic-gate 	if (regno < 0 || regno > 1)
283*7c478bd9Sstevel@tonic-gate 		return (0);
284*7c478bd9Sstevel@tonic-gate 	cpuver -= CPC_ULTRA1;
285*7c478bd9Sstevel@tonic-gate 	if (cpuver < 0 ||
286*7c478bd9Sstevel@tonic-gate 	    cpuver >= sizeof (cpuvermap) / sizeof (cpuvermap[0]))
287*7c478bd9Sstevel@tonic-gate 		return (0);
288*7c478bd9Sstevel@tonic-gate 	return (1);
289*7c478bd9Sstevel@tonic-gate }
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
292*7c478bd9Sstevel@tonic-gate static int
293*7c478bd9Sstevel@tonic-gate versionmatch(int cpuver, int regno, const struct nametable *n)
294*7c478bd9Sstevel@tonic-gate {
295*7c478bd9Sstevel@tonic-gate 	if (!validargs(cpuver, regno) || n->ver != MAPCPUVER(cpuver))
296*7c478bd9Sstevel@tonic-gate 		return (0);
297*7c478bd9Sstevel@tonic-gate 	return (1);
298*7c478bd9Sstevel@tonic-gate }
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate static const struct nametable *
301*7c478bd9Sstevel@tonic-gate getnametable(int cpuver, int regno)
302*7c478bd9Sstevel@tonic-gate {
303*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	if (!validargs(cpuver, regno))
306*7c478bd9Sstevel@tonic-gate 		return (NULL);
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	switch (MAPCPUVER(cpuver)) {
309*7c478bd9Sstevel@tonic-gate 	case V_US12:
310*7c478bd9Sstevel@tonic-gate 		n = US12_names[regno];
311*7c478bd9Sstevel@tonic-gate 		break;
312*7c478bd9Sstevel@tonic-gate 	case V_US3:
313*7c478bd9Sstevel@tonic-gate 		n = US3_names[regno];
314*7c478bd9Sstevel@tonic-gate 		break;
315*7c478bd9Sstevel@tonic-gate 	case V_US3_PLUS:
316*7c478bd9Sstevel@tonic-gate 		n = US3_PLUS_names[regno];
317*7c478bd9Sstevel@tonic-gate 		break;
318*7c478bd9Sstevel@tonic-gate 	case V_US3_I:
319*7c478bd9Sstevel@tonic-gate 		n = US3_I_names[regno];
320*7c478bd9Sstevel@tonic-gate 		break;
321*7c478bd9Sstevel@tonic-gate 	default:
322*7c478bd9Sstevel@tonic-gate 		n = NULL;
323*7c478bd9Sstevel@tonic-gate 		break;
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 	return (n);
326*7c478bd9Sstevel@tonic-gate }
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate void
329*7c478bd9Sstevel@tonic-gate cpc_walk_names(int cpuver, int regno, void *arg,
330*7c478bd9Sstevel@tonic-gate     void (*action)(void *, int, const char *, uint8_t))
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	if ((n = getnametable(cpuver, regno)) == NULL)
335*7c478bd9Sstevel@tonic-gate 		return;
336*7c478bd9Sstevel@tonic-gate 	for (; n->ver != V_END; n++)
337*7c478bd9Sstevel@tonic-gate 		if (versionmatch(cpuver, regno, n))
338*7c478bd9Sstevel@tonic-gate 			action(arg, regno, n->name, n->bits);
339*7c478bd9Sstevel@tonic-gate }
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate const char *
342*7c478bd9Sstevel@tonic-gate __cpc_reg_to_name(int cpuver, int regno, uint8_t bits)
343*7c478bd9Sstevel@tonic-gate {
344*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	if ((n = getnametable(cpuver, regno)) == NULL)
347*7c478bd9Sstevel@tonic-gate 		return (NULL);
348*7c478bd9Sstevel@tonic-gate 	for (; n->ver != V_END; n++)
349*7c478bd9Sstevel@tonic-gate 		if (bits == n->bits && versionmatch(cpuver, regno, n))
350*7c478bd9Sstevel@tonic-gate 			return (n->name);
351*7c478bd9Sstevel@tonic-gate 	return (NULL);
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate /*
355*7c478bd9Sstevel@tonic-gate  * Register names can be specified as strings or even as numbers
356*7c478bd9Sstevel@tonic-gate  */
357*7c478bd9Sstevel@tonic-gate int
358*7c478bd9Sstevel@tonic-gate __cpc_name_to_reg(int cpuver, int regno, const char *name, uint8_t *bits)
359*7c478bd9Sstevel@tonic-gate {
360*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
361*7c478bd9Sstevel@tonic-gate 	char *eptr = NULL;
362*7c478bd9Sstevel@tonic-gate 	long value;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	if ((n = getnametable(cpuver, regno)) == NULL || name == NULL)
365*7c478bd9Sstevel@tonic-gate 		return (-1);
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	for (; n->ver != V_END; n++)
368*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, n->name) == 0 &&
369*7c478bd9Sstevel@tonic-gate 		    versionmatch(cpuver, regno, n)) {
370*7c478bd9Sstevel@tonic-gate 			*bits = n->bits;
371*7c478bd9Sstevel@tonic-gate 			return (0);
372*7c478bd9Sstevel@tonic-gate 		}
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	value = strtol(name, &eptr, 0);
375*7c478bd9Sstevel@tonic-gate 	if (name != eptr && value >= 0 && value <= UINT8_MAX) {
376*7c478bd9Sstevel@tonic-gate 		*bits = (uint8_t)value;
377*7c478bd9Sstevel@tonic-gate 		return (0);
378*7c478bd9Sstevel@tonic-gate 	}
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	return (-1);
381*7c478bd9Sstevel@tonic-gate }
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate const char *
384*7c478bd9Sstevel@tonic-gate cpc_getcciname(int cpuver)
385*7c478bd9Sstevel@tonic-gate {
386*7c478bd9Sstevel@tonic-gate 	if (validargs(cpuver, 0))
387*7c478bd9Sstevel@tonic-gate 		switch (MAPCPUVER(cpuver)) {
388*7c478bd9Sstevel@tonic-gate 		case V_US12:
389*7c478bd9Sstevel@tonic-gate 			return ("UltraSPARC I&II");
390*7c478bd9Sstevel@tonic-gate 		case V_US3:
391*7c478bd9Sstevel@tonic-gate 			return ("UltraSPARC III");
392*7c478bd9Sstevel@tonic-gate 		case V_US3_PLUS:
393*7c478bd9Sstevel@tonic-gate 			return ("UltraSPARC III+ & IV");
394*7c478bd9Sstevel@tonic-gate 		case V_US3_I:
395*7c478bd9Sstevel@tonic-gate 			return ("UltraSPARC IIIi & IIIi+");
396*7c478bd9Sstevel@tonic-gate 		default:
397*7c478bd9Sstevel@tonic-gate 			break;
398*7c478bd9Sstevel@tonic-gate 		}
399*7c478bd9Sstevel@tonic-gate 	return (NULL);
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate #define	CPU_REF_URL " Documentation for Sun processors can be found at: " \
403*7c478bd9Sstevel@tonic-gate 			"http://www.sun.com/processors/manuals"
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate const char *
406*7c478bd9Sstevel@tonic-gate cpc_getcpuref(int cpuver)
407*7c478bd9Sstevel@tonic-gate {
408*7c478bd9Sstevel@tonic-gate 	if (validargs(cpuver, 0))
409*7c478bd9Sstevel@tonic-gate 		switch (MAPCPUVER(cpuver)) {
410*7c478bd9Sstevel@tonic-gate 		case V_US12:
411*7c478bd9Sstevel@tonic-gate 			return (gettext(
412*7c478bd9Sstevel@tonic-gate 			    "See the \"UltraSPARC I/II User\'s Manual\" "
413*7c478bd9Sstevel@tonic-gate 			    "(Part No. 802-7220-02) "
414*7c478bd9Sstevel@tonic-gate 			    "for descriptions of these events." CPU_REF_URL));
415*7c478bd9Sstevel@tonic-gate 		case V_US3:
416*7c478bd9Sstevel@tonic-gate 		case V_US3_PLUS:
417*7c478bd9Sstevel@tonic-gate 			return (gettext(
418*7c478bd9Sstevel@tonic-gate 			    "See the \"UltraSPARC III Cu User's Manual\" "
419*7c478bd9Sstevel@tonic-gate 			    "for descriptions of these events." CPU_REF_URL));
420*7c478bd9Sstevel@tonic-gate 		case V_US3_I:
421*7c478bd9Sstevel@tonic-gate 			return (gettext(
422*7c478bd9Sstevel@tonic-gate 			    "See the \"UltraSPARC IIIi User's Manual\"  "
423*7c478bd9Sstevel@tonic-gate 			    "for descriptions of these events." CPU_REF_URL));
424*7c478bd9Sstevel@tonic-gate 		default:
425*7c478bd9Sstevel@tonic-gate 			break;
426*7c478bd9Sstevel@tonic-gate 		}
427*7c478bd9Sstevel@tonic-gate 	return (NULL);
428*7c478bd9Sstevel@tonic-gate }
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate /*
431*7c478bd9Sstevel@tonic-gate  * This is a functional interface to allow CPUs with fewer %pic registers
432*7c478bd9Sstevel@tonic-gate  * to share the same data structure as those with more %pic registers
433*7c478bd9Sstevel@tonic-gate  * within the same instruction family.
434*7c478bd9Sstevel@tonic-gate  */
435*7c478bd9Sstevel@tonic-gate uint_t
436*7c478bd9Sstevel@tonic-gate cpc_getnpic(int cpuver)
437*7c478bd9Sstevel@tonic-gate {
438*7c478bd9Sstevel@tonic-gate 	/*LINTED*/
439*7c478bd9Sstevel@tonic-gate 	cpc_event_t *event;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	switch (cpuver) {
442*7c478bd9Sstevel@tonic-gate 	case CPC_ULTRA1:
443*7c478bd9Sstevel@tonic-gate 	case CPC_ULTRA2:
444*7c478bd9Sstevel@tonic-gate 	case CPC_ULTRA3:
445*7c478bd9Sstevel@tonic-gate 	case CPC_ULTRA3_PLUS:
446*7c478bd9Sstevel@tonic-gate 	case CPC_ULTRA3_I:
447*7c478bd9Sstevel@tonic-gate 		return (sizeof (event->ce_pic) / sizeof (event->ce_pic[0]));
448*7c478bd9Sstevel@tonic-gate 	default:
449*7c478bd9Sstevel@tonic-gate 		return (0);
450*7c478bd9Sstevel@tonic-gate 	}
451*7c478bd9Sstevel@tonic-gate }
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate /*
454*7c478bd9Sstevel@tonic-gate  * Compares the given string against the list of all known CPU node names, and
455*7c478bd9Sstevel@tonic-gate  * returns the CPC CPU version code if there is a match. If there is no match,
456*7c478bd9Sstevel@tonic-gate  * returns -1.
457*7c478bd9Sstevel@tonic-gate  */
458*7c478bd9Sstevel@tonic-gate static int
459*7c478bd9Sstevel@tonic-gate node2ver(char *node)
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	if (strcmp(node, "SUNW,UltraSPARC") == 0 ||
462*7c478bd9Sstevel@tonic-gate 	    strcmp(node, "SUNW,UltraSPARC-II") == 0 ||
463*7c478bd9Sstevel@tonic-gate 	    strcmp(node, "SUNW,UltraSPARC-IIi") == 0 ||
464*7c478bd9Sstevel@tonic-gate 	    strcmp(node, "SUNW,UltraSPARC-IIe") == 0) {
465*7c478bd9Sstevel@tonic-gate 		return (CPC_ULTRA1);
466*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(node, "SUNW,UltraSPARC-III") == 0)
467*7c478bd9Sstevel@tonic-gate 		return (CPC_ULTRA3);
468*7c478bd9Sstevel@tonic-gate 	else if (strcmp(node, "SUNW,UltraSPARC-III+") == 0 ||
469*7c478bd9Sstevel@tonic-gate 	    strcmp(node, "SUNW,UltraSPARC-IV") == 0 ||
470*7c478bd9Sstevel@tonic-gate 	    strcmp(node, "SUNW,UltraSPARC-IV+") == 0)
471*7c478bd9Sstevel@tonic-gate 		return (CPC_ULTRA3_PLUS);
472*7c478bd9Sstevel@tonic-gate 	else if (strcmp(node, "SUNW,UltraSPARC-IIIi") == 0 ||
473*7c478bd9Sstevel@tonic-gate 	    strcmp(node, "SUNW,UltraSPARC-IIIi+") == 0)
474*7c478bd9Sstevel@tonic-gate 		return (CPC_ULTRA3_I);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	return (-1);
477*7c478bd9Sstevel@tonic-gate }
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate static int
480*7c478bd9Sstevel@tonic-gate cpc_get_cpu_ver(di_node_t di_node, void *arg)
481*7c478bd9Sstevel@tonic-gate {
482*7c478bd9Sstevel@tonic-gate 	char		*node_name, *compatible_array;
483*7c478bd9Sstevel@tonic-gate 	int		n_names, i, found = 0;
484*7c478bd9Sstevel@tonic-gate 	int		*ver = arg;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	node_name = di_node_name(di_node);
487*7c478bd9Sstevel@tonic-gate 	if (node_name != NULL) {
488*7c478bd9Sstevel@tonic-gate 		if ((*ver = node2ver(node_name)) != -1)
489*7c478bd9Sstevel@tonic-gate 			found = 1;
490*7c478bd9Sstevel@tonic-gate 		else if (strncmp(node_name, "cpu", 4) == 0) {
491*7c478bd9Sstevel@tonic-gate 			/*
492*7c478bd9Sstevel@tonic-gate 			 * CPU nodes associated with CMP use the generic name
493*7c478bd9Sstevel@tonic-gate 			 * of "cpu".  We must look at the compatible property
494*7c478bd9Sstevel@tonic-gate 			 * in order to find the implementation specific name.
495*7c478bd9Sstevel@tonic-gate 			 */
496*7c478bd9Sstevel@tonic-gate 			if ((n_names = di_compatible_names(di_node,
497*7c478bd9Sstevel@tonic-gate 			    &compatible_array)) > 0) {
498*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < n_names; i++) {
499*7c478bd9Sstevel@tonic-gate 					if ((*ver = node2ver(compatible_array))
500*7c478bd9Sstevel@tonic-gate 					    != -1) {
501*7c478bd9Sstevel@tonic-gate 						found = 1;
502*7c478bd9Sstevel@tonic-gate 						break;
503*7c478bd9Sstevel@tonic-gate 					}
504*7c478bd9Sstevel@tonic-gate 					compatible_array +=
505*7c478bd9Sstevel@tonic-gate 					    strlen(compatible_array) + 1;
506*7c478bd9Sstevel@tonic-gate 				}
507*7c478bd9Sstevel@tonic-gate 			}
508*7c478bd9Sstevel@tonic-gate 		}
509*7c478bd9Sstevel@tonic-gate 	}
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	if (found == 0)
512*7c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	return (DI_WALK_TERMINATE);
515*7c478bd9Sstevel@tonic-gate }
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate /*
518*7c478bd9Sstevel@tonic-gate  * Return the version of the current processor.
519*7c478bd9Sstevel@tonic-gate  *
520*7c478bd9Sstevel@tonic-gate  * Version -1 is defined as 'not performance counter capable'
521*7c478bd9Sstevel@tonic-gate  *
522*7c478bd9Sstevel@tonic-gate  * XXX  A better solution would be to use the di_prom_props for the cpu
523*7c478bd9Sstevel@tonic-gate  * devinfo nodes. That way we could look at the 'device-type', 'sparc-version'
524*7c478bd9Sstevel@tonic-gate  * and 'implementation#' properties in order to determine which version of
525*7c478bd9Sstevel@tonic-gate  * UltraSPARC we are running on.
526*7c478bd9Sstevel@tonic-gate  *
527*7c478bd9Sstevel@tonic-gate  * The problem with this is that di_prom_init() requires root access to
528*7c478bd9Sstevel@tonic-gate  * open /dev/openprom and cputrack is not a root-only application so
529*7c478bd9Sstevel@tonic-gate  * we have to settle for the di_props that we can see as non-root users.
530*7c478bd9Sstevel@tonic-gate  */
531*7c478bd9Sstevel@tonic-gate int
532*7c478bd9Sstevel@tonic-gate cpc_getcpuver(void)
533*7c478bd9Sstevel@tonic-gate {
534*7c478bd9Sstevel@tonic-gate 	static int ver = -1;
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	if (ver == -1) {
537*7c478bd9Sstevel@tonic-gate 		di_node_t	di_root_node;
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 		if ((di_root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL)
540*7c478bd9Sstevel@tonic-gate 			return (-1);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 		(void) di_walk_node(di_root_node, DI_WALK_CLDFIRST,
543*7c478bd9Sstevel@tonic-gate 			(void *)&ver, cpc_get_cpu_ver);
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 		di_fini(di_root_node);
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 	return (ver);
548*7c478bd9Sstevel@tonic-gate }
549