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