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 2004 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 #include <sys/types.h>
28*7c478bd9Sstevel@tonic-gate #include <string.h>
29*7c478bd9Sstevel@tonic-gate #include <alloca.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <libintl.h>
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include "libcpc.h"
35*7c478bd9Sstevel@tonic-gate #include "libcpc_impl.h"
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate /*
38*7c478bd9Sstevel@tonic-gate  * Configuration data for Pentium Pro performance counters.
39*7c478bd9Sstevel@tonic-gate  *
40*7c478bd9Sstevel@tonic-gate  * Definitions taken from [3].  See the reference to
41*7c478bd9Sstevel@tonic-gate  * understand what any of these settings actually means.
42*7c478bd9Sstevel@tonic-gate  *
43*7c478bd9Sstevel@tonic-gate  * [3] "Pentium Pro Family Developer's Manual, Volume 3:
44*7c478bd9Sstevel@tonic-gate  *     Operating Systems Writer's Manual," January 1996
45*7c478bd9Sstevel@tonic-gate  */
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #define	V_P5	(1u << 0)		/* specific to Pentium cpus */
48*7c478bd9Sstevel@tonic-gate #define	V_P5mmx	(1u << 1)		/* " MMX instructions */
49*7c478bd9Sstevel@tonic-gate #define	V_P6	(1u << 2)		/* specific to Pentium II cpus */
50*7c478bd9Sstevel@tonic-gate #define	V_P6mmx	(1u << 3)		/* " MMX instructions */
51*7c478bd9Sstevel@tonic-gate #define	V_END	0
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * map from "cpu version" to flag bits
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate static const uint_t cpuvermap[] = {
57*7c478bd9Sstevel@tonic-gate 	V_P5,		/* CPC_PENTIUM */
58*7c478bd9Sstevel@tonic-gate 	V_P5 | V_P5mmx,	/* CPC_PENTIUM_MMX */
59*7c478bd9Sstevel@tonic-gate 	V_P6,		/* CPC_PENTIUM_PRO */
60*7c478bd9Sstevel@tonic-gate 	V_P6 | V_P6mmx,	/* CPC_PENTIUM_PRO_MMX */
61*7c478bd9Sstevel@tonic-gate };
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate struct nametable {
64*7c478bd9Sstevel@tonic-gate 	const uint_t	ver;
65*7c478bd9Sstevel@tonic-gate 	const uint8_t	bits;
66*7c478bd9Sstevel@tonic-gate 	const char	*name;
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /*
70*7c478bd9Sstevel@tonic-gate  * Basic Pentium events
71*7c478bd9Sstevel@tonic-gate  */
72*7c478bd9Sstevel@tonic-gate #define	P5_EVENTS(v)						\
73*7c478bd9Sstevel@tonic-gate 	{v,		0x0,	"data_read"},			\
74*7c478bd9Sstevel@tonic-gate 	{v,		0x1,	"data_write"},			\
75*7c478bd9Sstevel@tonic-gate 	{v,		0x2,	"data_tlb_miss"},		\
76*7c478bd9Sstevel@tonic-gate 	{v,		0x3,	"data_read_miss"},		\
77*7c478bd9Sstevel@tonic-gate 	{v,		0x4,	"data_write_miss"},		\
78*7c478bd9Sstevel@tonic-gate 	{v,		0x5,	"write_hit_to_M_or_E"},		\
79*7c478bd9Sstevel@tonic-gate 	{v,		0x6,	"dcache_lines_wrback"},		\
80*7c478bd9Sstevel@tonic-gate 	{v,		0x7,	"external_snoops"},		\
81*7c478bd9Sstevel@tonic-gate 	{v,		0x8,	"external_dcache_snoop_hits"},	\
82*7c478bd9Sstevel@tonic-gate 	{v,		0x9,	"memory_access_in_both_pipes"},	\
83*7c478bd9Sstevel@tonic-gate 	{v,		0xa,	"bank_conflicts"},		\
84*7c478bd9Sstevel@tonic-gate 	{v,		0xb,	"misaligned_ref"},		\
85*7c478bd9Sstevel@tonic-gate 	{v,		0xc,	"code_read"},			\
86*7c478bd9Sstevel@tonic-gate 	{v,		0xd,	"code_tlb_miss"},		\
87*7c478bd9Sstevel@tonic-gate 	{v,		0xe,	"code_cache_miss"},		\
88*7c478bd9Sstevel@tonic-gate 	{v,		0xf,	"any_segreg_loaded"},		\
89*7c478bd9Sstevel@tonic-gate 	{v,		0x12,	"branches"},			\
90*7c478bd9Sstevel@tonic-gate 	{v,		0x13,	"btb_hits"},			\
91*7c478bd9Sstevel@tonic-gate 	{v,		0x14,	"taken_or_btb_hit"},		\
92*7c478bd9Sstevel@tonic-gate 	{v,		0x15,	"pipeline_flushes"},		\
93*7c478bd9Sstevel@tonic-gate 	{v,		0x16,	"instr_exec"},			\
94*7c478bd9Sstevel@tonic-gate 	{v,		0x17,	"instr_exec_V_pipe"},		\
95*7c478bd9Sstevel@tonic-gate 	{v,		0x18,	"clks_bus_cycle"},		\
96*7c478bd9Sstevel@tonic-gate 	{v,		0x19,	"clks_full_wbufs"},		\
97*7c478bd9Sstevel@tonic-gate 	{v,		0x1a,	"pipe_stall_read"},		\
98*7c478bd9Sstevel@tonic-gate 	{v,		0x1b,	"stall_on_write_ME"},		\
99*7c478bd9Sstevel@tonic-gate 	{v,		0x1c,	"locked_bus_cycle"},		\
100*7c478bd9Sstevel@tonic-gate 	{v,		0x1d,	"io_rw_cycles"},		\
101*7c478bd9Sstevel@tonic-gate 	{v,		0x1e,	"reads_noncache_mem"},		\
102*7c478bd9Sstevel@tonic-gate 	{v,		0x1f,	"pipeline_agi_stalls"},		\
103*7c478bd9Sstevel@tonic-gate 	{v,		0x22,	"flops"},			\
104*7c478bd9Sstevel@tonic-gate 	{v,		0x23,	"bp_match_dr0"},		\
105*7c478bd9Sstevel@tonic-gate 	{v,		0x24,	"bp_match_dr1"},		\
106*7c478bd9Sstevel@tonic-gate 	{v,		0x25,	"bp_match_dr2"},		\
107*7c478bd9Sstevel@tonic-gate 	{v,		0x26,	"bp_match_dr3"},		\
108*7c478bd9Sstevel@tonic-gate 	{v,		0x27,	"hw_intrs"},			\
109*7c478bd9Sstevel@tonic-gate 	{v,		0x28,	"data_rw"},			\
110*7c478bd9Sstevel@tonic-gate 	{v,		0x29,	"data_rw_miss"}
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate static const struct nametable P5mmx_names0[] = {
113*7c478bd9Sstevel@tonic-gate 	P5_EVENTS(V_P5),
114*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2a,	"bus_ownership_latency"},
115*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2b,	"mmx_instr_upipe"},
116*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2c,	"cache_M_line_sharing"},
117*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2d,	"emms_instr"},
118*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2e,	"bus_util_processor"},
119*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2f,	"sat_mmx_instr"},
120*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x30,	"clks_not_HLT"},
121*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x31,	"mmx_data_read"},
122*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x32,	"clks_fp_stall"},
123*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x33,	"d1_starv_fifo_0"},
124*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x34,	"mmx_data_write"},
125*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x35,	"pipe_flush_wbp"},
126*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x36,	"mmx_misalign_data_refs"},
127*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x37,	"rets_pred_incorrect"},
128*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x38,	"mmx_multiply_unit_interlock"},
129*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x39,	"rets"},
130*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x3a,	"btb_false_entries"},
131*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x3b,	"clocks_stall_full_wb"},
132*7c478bd9Sstevel@tonic-gate 	{V_END}
133*7c478bd9Sstevel@tonic-gate };
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate static const struct nametable P5mmx_names1[] = {
136*7c478bd9Sstevel@tonic-gate 	P5_EVENTS(V_P5),
137*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2a,	"bus_ownership_transfers"},
138*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2b,	"mmx_instr_vpipe"},
139*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2c,	"cache_lint_sharing"},
140*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2d,	"mmx_fp_transitions"},
141*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2e,	"writes_noncache_mem"},
142*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x2f,	"sats_performed"},
143*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x30,	"clks_dcache_tlb_miss"},
144*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x31,	"mmx_data_read_miss"},
145*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x32,	"taken_br"},
146*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x33,	"d1_starv_fifo_1"},
147*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x34,	"mmx_data_write_miss"},
148*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x35,	"pipe_flush_wbp_wb"},
149*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x36,	"mmx_pipe_stall_data_read"},
150*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x37,	"rets_pred"},
151*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x38,	"movd_movq_stall"},
152*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x39,	"rsb_overflow"},
153*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x3a,	"btb_mispred_nt"},
154*7c478bd9Sstevel@tonic-gate 	{V_P5mmx,	0x3b,	"mmx_stall_write_ME"},
155*7c478bd9Sstevel@tonic-gate 	{V_END}
156*7c478bd9Sstevel@tonic-gate };
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate static const struct nametable *P5mmx_names[2] = {
159*7c478bd9Sstevel@tonic-gate 	P5mmx_names0,
160*7c478bd9Sstevel@tonic-gate 	P5mmx_names1
161*7c478bd9Sstevel@tonic-gate };
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate /*
164*7c478bd9Sstevel@tonic-gate  * Pentium Pro and Pentium II events
165*7c478bd9Sstevel@tonic-gate  */
166*7c478bd9Sstevel@tonic-gate static const struct nametable P6_names[] = {
167*7c478bd9Sstevel@tonic-gate 	/*
168*7c478bd9Sstevel@tonic-gate 	 * Data cache unit
169*7c478bd9Sstevel@tonic-gate 	 */
170*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x43,	"data_mem_refs"},
171*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x45,	"dcu_lines_in"},
172*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x46,	"dcu_m_lines_in"},
173*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x47,	"dcu_m_lines_out"},
174*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x48,	"dcu_miss_outstanding"},
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	/*
177*7c478bd9Sstevel@tonic-gate 	 * Instruction fetch unit
178*7c478bd9Sstevel@tonic-gate 	 */
179*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x80,	"ifu_ifetch"},
180*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x81,	"ifu_ifetch_miss"},
181*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x85,	"itlb_miss"},
182*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x86,	"ifu_mem_stall"},
183*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x87,	"ild_stall"},
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	/*
186*7c478bd9Sstevel@tonic-gate 	 * L2 cache
187*7c478bd9Sstevel@tonic-gate 	 */
188*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x28,	"l2_ifetch"},
189*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x29,	"l2_ld"},
190*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x2a,	"l2_st"},
191*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x24,	"l2_lines_in"},
192*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x26,	"l2_lines_out"},
193*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x25,	"l2_m_lines_inm"},
194*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x27,	"l2_m_lines_outm"},
195*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x2e,	"l2_rqsts"},
196*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x21,	"l2_ads"},
197*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x22,	"l2_dbus_busy"},
198*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x23,	"l2_dbus_busy_rd"},
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/*
201*7c478bd9Sstevel@tonic-gate 	 * External bus logic
202*7c478bd9Sstevel@tonic-gate 	 */
203*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x62,	"bus_drdy_clocks"},
204*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x63,	"bus_lock_clocks"},
205*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x60,	"bus_req_outstanding"},
206*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x65,	"bus_tran_brd"},
207*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x66,	"bus_tran_rfo"},
208*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x67,	"bus_trans_wb"},
209*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x68,	"bus_tran_ifetch"},
210*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x69,	"bus_tran_inval"},
211*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x6a,	"bus_tran_pwr"},
212*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x6b,	"bus_trans_p"},
213*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x6c,	"bus_trans_io"},
214*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x6d,	"bus_tran_def"},
215*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x6e,	"bus_tran_burst"},
216*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x70,	"bus_tran_any"},
217*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x6f,	"bus_tran_mem"},
218*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x64,	"bus_data_rcv"},
219*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x61,	"bus_bnr_drv"},
220*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x7a,	"bus_hit_drv"},
221*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x7b,	"bus_hitm_drv"},
222*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x7e,	"bus_snoop_stall"},
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/*
225*7c478bd9Sstevel@tonic-gate 	 * Floating point unit
226*7c478bd9Sstevel@tonic-gate 	 */
227*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc1,	"flops"},		/* 0 only */
228*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x10,	"fp_comp_ops_exe"},	/* 0 only */
229*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x11,	"fp_assist"},		/* 1 only */
230*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x12,	"mul"},			/* 1 only */
231*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x13,	"div"},			/* 1 only */
232*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x14,	"cycles_div_busy"},	/* 0 only */
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/*
235*7c478bd9Sstevel@tonic-gate 	 * Memory ordering
236*7c478bd9Sstevel@tonic-gate 	 */
237*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x3,	"ld_blocks"},
238*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x4,	"sb_drains"},
239*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x5,	"misalign_mem_ref"},
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	/*
242*7c478bd9Sstevel@tonic-gate 	 * Instruction decoding and retirement
243*7c478bd9Sstevel@tonic-gate 	 */
244*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc0,	"inst_retired"},
245*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc2,	"uops_retired"},
246*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xd0,	"inst_decoder"},
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	/*
249*7c478bd9Sstevel@tonic-gate 	 * Interrupts
250*7c478bd9Sstevel@tonic-gate 	 */
251*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc8,	"hw_int_rx"},
252*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc6,	"cycles_int_masked"},
253*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc7,	"cycles_int_pending_and_masked"},
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	/*
256*7c478bd9Sstevel@tonic-gate 	 * Branches
257*7c478bd9Sstevel@tonic-gate 	 */
258*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc4,	"br_inst_retired"},
259*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc5,	"br_miss_pred_retired"},
260*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xc9,	"br_taken_retired"},
261*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xca,	"br_miss_pred_taken_ret"},
262*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xe0,	"br_inst_decoded"},
263*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xe2,	"btb_misses"},
264*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xe4,	"br_bogus"},
265*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xe6,	"baclears"},
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	/*
268*7c478bd9Sstevel@tonic-gate 	 * Stalls
269*7c478bd9Sstevel@tonic-gate 	 */
270*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xa2,	"resource_stalls"},
271*7c478bd9Sstevel@tonic-gate 	{V_P6,		0xd2,	"partial_rat_stalls"},
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	/*
274*7c478bd9Sstevel@tonic-gate 	 * Segment register loads
275*7c478bd9Sstevel@tonic-gate 	 */
276*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x6,	"segment_reg_loads"},
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/*
279*7c478bd9Sstevel@tonic-gate 	 * Clocks
280*7c478bd9Sstevel@tonic-gate 	 */
281*7c478bd9Sstevel@tonic-gate 	{V_P6,		0x79,	"cpu_clk_unhalted"},
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	/*
284*7c478bd9Sstevel@tonic-gate 	 * MMX
285*7c478bd9Sstevel@tonic-gate 	 */
286*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xb0,	"mmx_instr_exec"},
287*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xb1,	"mmx_sat_instr_exec"},
288*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xb2,	"mmx_uops_exec"},
289*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xb3,	"mmx_instr_type_exec"},
290*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xcc,	"fp_mmx_trans"},
291*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xcd,	"mmx_assists"},
292*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xce,	"mmx_instr_ret"},
293*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xd4,	"seg_rename_stalls"},
294*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xd5,	"seg_reg_renames"},
295*7c478bd9Sstevel@tonic-gate 	{V_P6mmx,	0xd6,	"ret_seg_renames"},
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	{V_END}
298*7c478bd9Sstevel@tonic-gate };
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate #define	MAPCPUVER(cpuver)	(cpuvermap[(cpuver) - CPC_PENTIUM])
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate static int
validargs(int cpuver,int regno)303*7c478bd9Sstevel@tonic-gate validargs(int cpuver, int regno)
304*7c478bd9Sstevel@tonic-gate {
305*7c478bd9Sstevel@tonic-gate 	if (regno < 0 || regno > 1)
306*7c478bd9Sstevel@tonic-gate 		return (0);
307*7c478bd9Sstevel@tonic-gate 	cpuver -= CPC_PENTIUM;
308*7c478bd9Sstevel@tonic-gate 	if (cpuver < 0 ||
309*7c478bd9Sstevel@tonic-gate 	    cpuver >= sizeof (cpuvermap) / sizeof (cpuvermap[0]))
310*7c478bd9Sstevel@tonic-gate 		return (0);
311*7c478bd9Sstevel@tonic-gate 	return (1);
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
315*7c478bd9Sstevel@tonic-gate static int
versionmatch(int cpuver,int regno,const struct nametable * n)316*7c478bd9Sstevel@tonic-gate versionmatch(int cpuver, int regno, const struct nametable *n)
317*7c478bd9Sstevel@tonic-gate {
318*7c478bd9Sstevel@tonic-gate 	if (!validargs(cpuver, regno) || (n->ver & MAPCPUVER(cpuver)) == 0)
319*7c478bd9Sstevel@tonic-gate 		return (0);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	switch (MAPCPUVER(cpuver)) {
322*7c478bd9Sstevel@tonic-gate 	case V_P5:
323*7c478bd9Sstevel@tonic-gate 	case V_P5 | V_P5mmx:
324*7c478bd9Sstevel@tonic-gate 		break;
325*7c478bd9Sstevel@tonic-gate 	case V_P6:
326*7c478bd9Sstevel@tonic-gate 	case V_P6 | V_P6mmx:
327*7c478bd9Sstevel@tonic-gate 		switch (n->bits) {
328*7c478bd9Sstevel@tonic-gate 		case 0xc1:	/* flops */
329*7c478bd9Sstevel@tonic-gate 		case 0x10:	/* fp_comp_ops_exe */
330*7c478bd9Sstevel@tonic-gate 		case 0x14:	/* cycles_div_busy */
331*7c478bd9Sstevel@tonic-gate 			/* only reg0 counts these */
332*7c478bd9Sstevel@tonic-gate 			if (regno == 1)
333*7c478bd9Sstevel@tonic-gate 				return (0);
334*7c478bd9Sstevel@tonic-gate 			break;
335*7c478bd9Sstevel@tonic-gate 		case 0x11:	/* fp_assist */
336*7c478bd9Sstevel@tonic-gate 		case 0x12:	/* mul */
337*7c478bd9Sstevel@tonic-gate 		case 0x13:	/* div */
338*7c478bd9Sstevel@tonic-gate 			/* only 1 can count these */
339*7c478bd9Sstevel@tonic-gate 			if (regno == 0)
340*7c478bd9Sstevel@tonic-gate 				return (0);
341*7c478bd9Sstevel@tonic-gate 			break;
342*7c478bd9Sstevel@tonic-gate 		default:
343*7c478bd9Sstevel@tonic-gate 			break;
344*7c478bd9Sstevel@tonic-gate 		}
345*7c478bd9Sstevel@tonic-gate 		break;
346*7c478bd9Sstevel@tonic-gate 	default:
347*7c478bd9Sstevel@tonic-gate 		return (0);
348*7c478bd9Sstevel@tonic-gate 	}
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	return (1);
351*7c478bd9Sstevel@tonic-gate }
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate static const struct nametable *
getnametable(int cpuver,int regno)354*7c478bd9Sstevel@tonic-gate getnametable(int cpuver, int regno)
355*7c478bd9Sstevel@tonic-gate {
356*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	if (!validargs(cpuver, regno))
359*7c478bd9Sstevel@tonic-gate 		return (NULL);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	switch (MAPCPUVER(cpuver)) {
362*7c478bd9Sstevel@tonic-gate 	case V_P5:
363*7c478bd9Sstevel@tonic-gate 	case V_P5 | V_P5mmx:
364*7c478bd9Sstevel@tonic-gate 		n = P5mmx_names[regno];
365*7c478bd9Sstevel@tonic-gate 		break;
366*7c478bd9Sstevel@tonic-gate 	case V_P6:
367*7c478bd9Sstevel@tonic-gate 	case V_P6 | V_P6mmx:
368*7c478bd9Sstevel@tonic-gate 		n = P6_names;
369*7c478bd9Sstevel@tonic-gate 		break;
370*7c478bd9Sstevel@tonic-gate 	default:
371*7c478bd9Sstevel@tonic-gate 		n = NULL;
372*7c478bd9Sstevel@tonic-gate 		break;
373*7c478bd9Sstevel@tonic-gate 	}
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	return (n);
376*7c478bd9Sstevel@tonic-gate }
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate void
cpc_walk_names(int cpuver,int regno,void * arg,void (* action)(void *,int,const char *,uint8_t))379*7c478bd9Sstevel@tonic-gate cpc_walk_names(int cpuver, int regno, void *arg,
380*7c478bd9Sstevel@tonic-gate     void (*action)(void *, int, const char *, uint8_t))
381*7c478bd9Sstevel@tonic-gate {
382*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if ((n = getnametable(cpuver, regno)) == NULL)
385*7c478bd9Sstevel@tonic-gate 		return;
386*7c478bd9Sstevel@tonic-gate 	for (; n->ver != V_END; n++)
387*7c478bd9Sstevel@tonic-gate 		if (versionmatch(cpuver, regno, n))
388*7c478bd9Sstevel@tonic-gate 			action(arg, regno, n->name, n->bits);
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate const char *
__cpc_reg_to_name(int cpuver,int regno,uint8_t bits)392*7c478bd9Sstevel@tonic-gate __cpc_reg_to_name(int cpuver, int regno, uint8_t bits)
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	if ((n = getnametable(cpuver, regno)) == NULL)
397*7c478bd9Sstevel@tonic-gate 		return (NULL);
398*7c478bd9Sstevel@tonic-gate 	for (; n->ver != V_END; n++)
399*7c478bd9Sstevel@tonic-gate 		if (bits == n->bits && versionmatch(cpuver, regno, n))
400*7c478bd9Sstevel@tonic-gate 			return (n->name);
401*7c478bd9Sstevel@tonic-gate 	return (NULL);
402*7c478bd9Sstevel@tonic-gate }
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate /*
405*7c478bd9Sstevel@tonic-gate  * Register names can be specified as strings or even as numbers
406*7c478bd9Sstevel@tonic-gate  */
407*7c478bd9Sstevel@tonic-gate int
__cpc_name_to_reg(int cpuver,int regno,const char * name,uint8_t * bits)408*7c478bd9Sstevel@tonic-gate __cpc_name_to_reg(int cpuver, int regno, const char *name, uint8_t *bits)
409*7c478bd9Sstevel@tonic-gate {
410*7c478bd9Sstevel@tonic-gate 	const struct nametable *n;
411*7c478bd9Sstevel@tonic-gate 	char *eptr = NULL;
412*7c478bd9Sstevel@tonic-gate 	long value;
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	if ((n = getnametable(cpuver, regno)) == NULL || name == NULL)
415*7c478bd9Sstevel@tonic-gate 		return (-1);
416*7c478bd9Sstevel@tonic-gate 	for (; n->ver != V_END; n++)
417*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, n->name) == 0 &&
418*7c478bd9Sstevel@tonic-gate 		    versionmatch(cpuver, regno, n)) {
419*7c478bd9Sstevel@tonic-gate 			*bits = n->bits;
420*7c478bd9Sstevel@tonic-gate 			return (0);
421*7c478bd9Sstevel@tonic-gate 		}
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	value = strtol(name, &eptr, 0);
424*7c478bd9Sstevel@tonic-gate 	if (name != eptr && value >= 0 && value <= UINT8_MAX) {
425*7c478bd9Sstevel@tonic-gate 		*bits = (uint8_t)value;
426*7c478bd9Sstevel@tonic-gate 		return (0);
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	return (-1);
430*7c478bd9Sstevel@tonic-gate }
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate const char *
cpc_getcciname(int cpuver)433*7c478bd9Sstevel@tonic-gate cpc_getcciname(int cpuver)
434*7c478bd9Sstevel@tonic-gate {
435*7c478bd9Sstevel@tonic-gate 	if (validargs(cpuver, 0))
436*7c478bd9Sstevel@tonic-gate 		switch (MAPCPUVER(cpuver)) {
437*7c478bd9Sstevel@tonic-gate 		case V_P5:
438*7c478bd9Sstevel@tonic-gate 			return ("Pentium");
439*7c478bd9Sstevel@tonic-gate 		case V_P5 | V_P5mmx:
440*7c478bd9Sstevel@tonic-gate 			return ("Pentium with MMX");
441*7c478bd9Sstevel@tonic-gate 		case V_P6:
442*7c478bd9Sstevel@tonic-gate 			return ("Pentium Pro, Pentium II");
443*7c478bd9Sstevel@tonic-gate 		case V_P6 | V_P6mmx:
444*7c478bd9Sstevel@tonic-gate 			return ("Pentium Pro with MMX, Pentium II");
445*7c478bd9Sstevel@tonic-gate 		default:
446*7c478bd9Sstevel@tonic-gate 			break;
447*7c478bd9Sstevel@tonic-gate 		}
448*7c478bd9Sstevel@tonic-gate 	return (NULL);
449*7c478bd9Sstevel@tonic-gate }
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate const char *
cpc_getcpuref(int cpuver)452*7c478bd9Sstevel@tonic-gate cpc_getcpuref(int cpuver)
453*7c478bd9Sstevel@tonic-gate {
454*7c478bd9Sstevel@tonic-gate 	if (validargs(cpuver, 0))
455*7c478bd9Sstevel@tonic-gate 		switch (MAPCPUVER(cpuver)) {
456*7c478bd9Sstevel@tonic-gate 		case V_P5:
457*7c478bd9Sstevel@tonic-gate 		case V_P5 | V_P5mmx:
458*7c478bd9Sstevel@tonic-gate 			return (gettext(
459*7c478bd9Sstevel@tonic-gate 			    "See Appendix A.2 of the \"Intel Architecture "
460*7c478bd9Sstevel@tonic-gate 			    "Software Developer's Manual,\" 243192, 1997"));
461*7c478bd9Sstevel@tonic-gate 		case V_P6:
462*7c478bd9Sstevel@tonic-gate 		case V_P6 | V_P6mmx:
463*7c478bd9Sstevel@tonic-gate 			return (gettext(
464*7c478bd9Sstevel@tonic-gate 			    "See Appendix A.1 of the \"Intel Architecture "
465*7c478bd9Sstevel@tonic-gate 			    "Software Developer's Manual,\" 243192, 1997"));
466*7c478bd9Sstevel@tonic-gate 		default:
467*7c478bd9Sstevel@tonic-gate 			break;
468*7c478bd9Sstevel@tonic-gate 		}
469*7c478bd9Sstevel@tonic-gate 	return (NULL);
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate /*
473*7c478bd9Sstevel@tonic-gate  * This is a functional interface to allow CPUs with fewer %pic registers
474*7c478bd9Sstevel@tonic-gate  * to share the same data structure as those with more %pic registers
475*7c478bd9Sstevel@tonic-gate  * within the same instruction set family.
476*7c478bd9Sstevel@tonic-gate  */
477*7c478bd9Sstevel@tonic-gate uint_t
cpc_getnpic(int cpuver)478*7c478bd9Sstevel@tonic-gate cpc_getnpic(int cpuver)
479*7c478bd9Sstevel@tonic-gate {
480*7c478bd9Sstevel@tonic-gate 	switch (cpuver) {
481*7c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM:
482*7c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
483*7c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
484*7c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
485*7c478bd9Sstevel@tonic-gate #define	EVENT	((cpc_event_t *)0)
486*7c478bd9Sstevel@tonic-gate 		return (sizeof (EVENT->ce_pic) / sizeof	(EVENT->ce_pic[0]));
487*7c478bd9Sstevel@tonic-gate #undef	EVENT
488*7c478bd9Sstevel@tonic-gate 	default:
489*7c478bd9Sstevel@tonic-gate 		return (0);
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate }
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate #define	BITS(v, u, l)	\
494*7c478bd9Sstevel@tonic-gate 	(((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1))
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate #include "getcpuid.h"
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate /*
499*7c478bd9Sstevel@tonic-gate  * Return the version of the current processor.
500*7c478bd9Sstevel@tonic-gate  *
501*7c478bd9Sstevel@tonic-gate  * Version -1 is defined as 'not performance counter capable'
502*7c478bd9Sstevel@tonic-gate  */
503*7c478bd9Sstevel@tonic-gate int
cpc_getcpuver(void)504*7c478bd9Sstevel@tonic-gate cpc_getcpuver(void)
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	static int ver = -1;
507*7c478bd9Sstevel@tonic-gate 	uint32_t maxeax;
508*7c478bd9Sstevel@tonic-gate 	uint32_t vbuf[4];
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	if (ver != -1)
511*7c478bd9Sstevel@tonic-gate 		return (ver);
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	maxeax = cpc_getcpuid(0, &vbuf[0], &vbuf[2], &vbuf[1]);
514*7c478bd9Sstevel@tonic-gate 	{
515*7c478bd9Sstevel@tonic-gate 		char *vendor = (char *)vbuf;
516*7c478bd9Sstevel@tonic-gate 		vendor[12] = '\0';
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 		if (strcmp(vendor, "GenuineIntel") != 0)
519*7c478bd9Sstevel@tonic-gate 			return (ver);
520*7c478bd9Sstevel@tonic-gate 	}
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if (maxeax >= 1) {
523*7c478bd9Sstevel@tonic-gate 		int family, model;
524*7c478bd9Sstevel@tonic-gate 		uint32_t eax, ebx, ecx, edx;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 		eax = cpc_getcpuid(1, &ebx, &ecx, &edx);
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 		if ((family = BITS(eax, 11, 8)) == 0xf)
529*7c478bd9Sstevel@tonic-gate 			family = BITS(eax, 27, 20);
530*7c478bd9Sstevel@tonic-gate 		if ((model = BITS(eax, 7, 4)) == 0xf)
531*7c478bd9Sstevel@tonic-gate 			model = BITS(eax, 19, 16);
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 		/*
534*7c478bd9Sstevel@tonic-gate 		 * map family and model into the performance
535*7c478bd9Sstevel@tonic-gate 		 * counter architectures we currently understand.
536*7c478bd9Sstevel@tonic-gate 		 *
537*7c478bd9Sstevel@tonic-gate 		 * See application note AP485 (from developer.intel.com)
538*7c478bd9Sstevel@tonic-gate 		 * for further explanation.
539*7c478bd9Sstevel@tonic-gate 		 */
540*7c478bd9Sstevel@tonic-gate 		switch (family) {
541*7c478bd9Sstevel@tonic-gate 		case 5:		/* Pentium and Pentium with MMX */
542*7c478bd9Sstevel@tonic-gate 			ver = model < 4 ?
543*7c478bd9Sstevel@tonic-gate 				CPC_PENTIUM : CPC_PENTIUM_MMX;
544*7c478bd9Sstevel@tonic-gate 			break;
545*7c478bd9Sstevel@tonic-gate 		case 6:		/* Pentium Pro and Pentium II and III */
546*7c478bd9Sstevel@tonic-gate 			ver = BITS(edx, 23, 23) ?	   /* mmx check */
547*7c478bd9Sstevel@tonic-gate 				CPC_PENTIUM_PRO_MMX : CPC_PENTIUM_PRO;
548*7c478bd9Sstevel@tonic-gate 			break;
549*7c478bd9Sstevel@tonic-gate 		default:
550*7c478bd9Sstevel@tonic-gate 		case 0xf:	/* Pentium IV */
551*7c478bd9Sstevel@tonic-gate 			break;
552*7c478bd9Sstevel@tonic-gate 		}
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	return (ver);
556*7c478bd9Sstevel@tonic-gate }
557