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