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 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 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 * 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 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 * 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 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 * 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 * 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 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 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 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 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