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