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