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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Opl platform specific PICL functions. 26 * 27 * called when : 28 * machine_type == MTYPE_OPL 29 */ 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <kstat.h> 35 #include <fcntl.h> 36 #include <string.h> 37 #include <assert.h> 38 #include <libintl.h> 39 #include <note.h> 40 #include <dlfcn.h> 41 #include <errno.h> 42 #include <sys/systeminfo.h> 43 #include <sys/openpromio.h> 44 #include <sys/sysmacros.h> 45 #include <picl.h> 46 #include "picldefs.h" 47 #include <pdevinfo.h> 48 #include <display.h> 49 #include <libprtdiag.h> 50 #include <alloca.h> 51 #include "opl_picl.h" 52 #include <sys/pci.h> 53 #include <sys/pci_tools.h> 54 #include <sys/types.h> 55 56 #if !defined(TEXT_DOMAIN) 57 #define TEXT_DOMAIN "SYS_TEST" 58 #endif 59 60 static picl_errno_t do_walk(picl_nodehdl_t rooth, const char *classname, 61 void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args)); 62 static int opl_get_node_by_name(picl_nodehdl_t rooth, char *name, 63 picl_nodehdl_t *nodeh); 64 static picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no, 65 int dev_no, int *actual, int *maximum, uint32_t *speed_max, 66 uint32_t *speed_at, int *type); 67 static int opl_display_pci(int syserrlog, picl_nodehdl_t plafh); 68 static picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args); 69 static int opl_get_first_compatible_value(picl_nodehdl_t nodeh, 70 char **outbuf); 71 static int picldiag_get_clock_freq(picl_nodehdl_t modh, 72 uint32_t *freq, uint32_t *freq_max); 73 static uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh, 74 char *prop_name, int *ret); 75 static uint32_t read_long(int fd, int bus, int dev, int func, 76 int offset, int *ret); 77 static uint8_t read_byte(int fd, int bus, int dev, int func, int offset, 78 int *ret); 79 static uint16_t read_word(int fd, int bus, int dev, int func, int offset, 80 int *ret); 81 82 /* 83 * Collect I/O nodes information. 84 */ 85 /* ARGSUSED */ 86 static picl_errno_t 87 opl_pci_callback(picl_nodehdl_t pcih, void *args) 88 { 89 picl_errno_t err = PICL_SUCCESS; 90 picl_nodehdl_t nodeh; 91 picl_prophdl_t proph; 92 picl_propinfo_t pinfo; 93 char path[MAXSTRLEN]; 94 char parent_path[MAXSTRLEN]; 95 static char root_path[MAXSTRLEN]; 96 char piclclass[PICL_CLASSNAMELEN_MAX]; 97 char name[MAXSTRLEN]; 98 char model[MAXSTRLEN]; 99 char *compatible; 100 char binding_name[MAXSTRLEN]; 101 struct io_card pci_card; 102 char status[6] = "N/A"; 103 int portid = PROP_INVALID; 104 int *reg_val; 105 int board = PROP_INVALID; 106 static int saved_board = PROP_INVALID; 107 static int saved_portid = PROP_INVALID; 108 int actual = PROP_INVALID, maximum = PROP_INVALID; 109 int bus_type; 110 int rev_id = PROP_INVALID, dev_id = PROP_INVALID; 111 int ven_id = PROP_INVALID; 112 size_t prop_size; 113 114 (void) memset(&pci_card, 0, sizeof (pci_card)); 115 116 err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME, 117 piclclass, sizeof (piclclass)); 118 119 if (err != PICL_SUCCESS) 120 /* Do not proceed to parse this branch */ 121 return (err); 122 123 if (!IS_PCI(piclclass)) 124 /* Do not parse non-pci nodes */ 125 return (PICL_INVALIDARG); 126 127 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path, 128 sizeof (parent_path)); 129 if (err != PICL_SUCCESS) 130 /* Do not proceed to parse this branch */ 131 return (err); 132 err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board, 133 sizeof (board)); 134 135 if (err == PICL_NORESPONSE) 136 /* Do not proceed to parse this branch */ 137 return (err); 138 else if (err != PICL_PROPNOTFOUND) { 139 saved_board = board; 140 /* Save board node's pathname */ 141 prop_size = sizeof (parent_path) + 1; 142 if (prop_size > MAXSTRLEN) 143 prop_size = MAXSTRLEN; 144 (void) strlcpy(root_path, parent_path, prop_size); 145 } 146 147 err = picl_get_propval_by_name 148 (pcih, OBP_PROP_PORTID, &portid, sizeof (portid)); 149 150 if (err != PICL_PROPNOTFOUND) 151 saved_portid = portid; 152 153 /* Walk through the children */ 154 155 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 156 sizeof (picl_nodehdl_t)); 157 158 while (err == PICL_SUCCESS) { 159 uint32_t freq_max = 0, freq_at = 0; 160 161 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 162 piclclass, sizeof (piclclass)); 163 if (err != PICL_SUCCESS) 164 /* Do not proceed to parse this node */ 165 return (err); 166 167 if (IS_EBUS(piclclass)) { 168 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, 169 &nodeh, sizeof (picl_nodehdl_t)); 170 continue; 171 } 172 173 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH, 174 path, sizeof (path)); 175 if (err != PICL_SUCCESS) { 176 /* Do not proceed to parse this node */ 177 return (err); 178 } 179 180 prop_size = sizeof (path) + 1; 181 if (prop_size > MAXSTRLEN) 182 prop_size = MAXSTRLEN; 183 (void) strlcpy(pci_card.notes, path, prop_size); 184 185 pci_card.board = saved_board; 186 pci_card.schizo_portid = saved_portid; 187 188 /* 189 * Get bus#, dev# and func# for this card from 'reg' property. 190 */ 191 192 err = picl_get_propinfo_by_name 193 (nodeh, OBP_PROP_REG, &pinfo, &proph); 194 if (err == PICL_SUCCESS) { 195 /* All of the array of bytes of "reg" have to be read */ 196 reg_val = malloc(pinfo.size); 197 if (reg_val == NULL) 198 return (PICL_FAILURE); 199 200 201 err = picl_get_propval_by_name 202 (nodeh, OBP_PROP_REG, reg_val, pinfo.size); 203 204 if (err != PICL_SUCCESS) { 205 free(reg_val); 206 /* Do not proceed to parse this node */ 207 return (err); 208 } 209 210 if (reg_val[0] != 0) { 211 pci_card.dev_no = 212 (((reg_val[0]) & PCI_DEV_MASK) >> 11); 213 pci_card.func_no = 214 (((reg_val[0]) & PCI_FUNC_MASK) >> 8); 215 pci_card.slot = 216 (((reg_val[0]) & PCI_BUS_MASK) >> 16); 217 } else 218 free(reg_val); 219 } 220 221 err = get_lane_width(root_path, pci_card.slot, pci_card.dev_no, 222 pci_card.func_no, &actual, &maximum, &freq_max, &freq_at, 223 &bus_type); 224 225 if (err != PICL_SUCCESS) { 226 /* 227 * get_lane_width will fail when run as non-root. 228 * Set bus_type to PCI_UNKN so that bus frequency, 229 * bus type and lane width will print as "--" or UNKN. 230 */ 231 bus_type = PCI_UNKN; 232 } 233 234 235 err = picl_get_propval_by_name 236 (nodeh, PICL_PROP_NAME, name, sizeof (name)); 237 if (err != PICL_SUCCESS) 238 (void) strcpy(name, ""); 239 240 /* 241 * Get the name of this card. If binding_name is found, 242 * name will be <nodename>-<binding_name> 243 */ 244 245 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, 246 binding_name, sizeof (binding_name)); 247 if (err == PICL_PROPNOTFOUND) { 248 /* 249 * if compatible prop is found, name will be 250 * <nodename>-<compatible> 251 */ 252 err = opl_get_first_compatible_value(nodeh, 253 &compatible); 254 if (err == PICL_SUCCESS) { 255 (void) strlcat(name, "-", MAXSTRLEN); 256 (void) strlcat(name, compatible, MAXSTRLEN); 257 free(compatible); 258 } 259 } else if (err != PICL_SUCCESS) { 260 /* No binding-name or compatible */ 261 (void) strcpy(binding_name, "N/A"); 262 } else if (strcmp(name, binding_name) != 0) { 263 (void) strlcat(name, "-", MAXSTRLEN); 264 (void) strlcat(name, binding_name, MAXSTRLEN); 265 } 266 267 268 prop_size = sizeof (name) + 1; 269 if (prop_size > MAXSTRLEN) 270 prop_size = MAXSTRLEN; 271 (void) strlcpy(pci_card.name, name, prop_size); 272 273 /* Get the status of the card */ 274 err = picl_get_propval_by_name 275 (nodeh, PICL_PROP_STATUS, status, sizeof (status)); 276 277 278 /* Get the model of this card */ 279 280 err = picl_get_propval_by_name 281 (nodeh, OBP_PROP_MODEL, model, sizeof (model)); 282 prop_size = sizeof (model) + 1; 283 if (prop_size > MAXSTRLEN) 284 prop_size = MAXSTRLEN; 285 if (err != PICL_SUCCESS) 286 (void) strcpy(model, "N/A"); 287 (void) strlcpy(pci_card.model, model, prop_size); 288 289 if (bus_type == PCI) 290 (void) strlcpy(pci_card.bus_type, 291 "PCI", sizeof (pci_card.bus_type)); 292 else if (bus_type == PCIX) 293 (void) strlcpy(pci_card.bus_type, 294 "PCIx", sizeof (pci_card.bus_type)); 295 else if (bus_type == PCIE) 296 (void) strlcpy(pci_card.bus_type, 297 "PCIe", sizeof (pci_card.bus_type)); 298 else 299 (void) strlcpy(pci_card.bus_type, 300 "UNKN", sizeof (pci_card.bus_type)); 301 302 /* Get revision id */ 303 err = picl_get_propval_by_name 304 (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id)); 305 306 /* Get device id */ 307 err = picl_get_propval_by_name 308 (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id)); 309 310 /* Get vendor id */ 311 err = picl_get_propval_by_name 312 (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id)); 313 314 /* 315 * prtdiag -v prints all devices 316 */ 317 318 /* Print board number */ 319 log_printf("%02d ", pci_card.board); 320 /* Print IO Type */ 321 log_printf("%-5.5s ", pci_card.bus_type); 322 323 log_printf("%-3d ", pci_card.schizo_portid); 324 log_printf("%4x, %4x, %4x ", rev_id, dev_id, ven_id); 325 326 log_printf("%3d, %2d, %2d", 327 pci_card.slot, pci_card.dev_no, pci_card.func_no); 328 329 /* Print status */ 330 log_printf(" %-5.5s ", status); 331 332 /* Print Lane widths, Max/Sup Freq, Speed */ 333 if (bus_type == PCIE) { 334 PRINT_FMT(actual, maximum); 335 } else if (bus_type == PCIX) { 336 PRINT_FREQ_FMT(freq_at, freq_max); 337 } else if (bus_type == PCI) { 338 err = picldiag_get_clock_freq(nodeh, &freq_at, 339 &freq_max); 340 PRINT_FREQ_FMT(freq_at, freq_max); 341 } else 342 log_printf(" -- , -- "); 343 344 /* Print Card Name */ 345 log_printf("%-30.30s", pci_card.name); 346 347 /* Print Card Model */ 348 log_printf(" %-20.20s", pci_card.model); 349 350 log_printf("\n"); 351 352 log_printf("%4s%-100.100s", " ", pci_card.notes); 353 log_printf("\n"); 354 log_printf("\n"); 355 356 357 err = picl_get_propval_by_name 358 (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t)); 359 360 } 361 362 return (PICL_WALK_CONTINUE); 363 } 364 365 /* 366 * opl_display_pci 367 * Display all the PCI IO cards on this board. 368 */ 369 static int 370 opl_display_pci(int syserrlog, picl_nodehdl_t plafh) 371 { 372 picl_errno_t err; 373 char *fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s"; 374 char *fmt2 = "%-16s"; 375 static int banner = FALSE; /* Have we printed the column headings? */ 376 377 if (banner == FALSE) { 378 log_printf("\n", 0); 379 log_printf("=========================", 0); 380 log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0); 381 log_printf("=========================", 0); 382 log_printf("\n", 0); 383 log_printf("\n", 0); 384 log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq", 385 "", "", 0); 386 log_printf("\n", 0); 387 388 log_printf(fmt, "LSB", "Type", "LPID", " RvID,DvID,VnID", 389 " BDF", "State", "Act, Max", "Name", "Model", 0); 390 391 log_printf("\n"); 392 393 log_printf(fmt, 394 "---", "-----", "----", " ------------------", 395 " ---------", "-----", "-----------", 396 "------------------------------", 397 "--------------------", 0); 398 log_printf("\n"); 399 log_printf(fmt2, " Logical Path"); 400 log_printf("\n"); 401 log_printf(fmt2, " ------------"); 402 log_printf("\n"); 403 banner = TRUE; 404 } 405 406 err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback); 407 return (err); 408 } 409 410 411 /* 412 * return the first compatible value 413 */ 414 static int 415 opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 416 { 417 picl_errno_t err; 418 picl_prophdl_t proph; 419 picl_propinfo_t pinfo; 420 picl_prophdl_t tblh; 421 picl_prophdl_t rowproph; 422 char *pval; 423 424 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 425 &pinfo, &proph); 426 if (err != PICL_SUCCESS) 427 return (err); 428 429 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 430 pval = malloc(pinfo.size); 431 if (pval == NULL) 432 return (PICL_FAILURE); 433 err = picl_get_propval(proph, pval, pinfo.size); 434 if (err != PICL_SUCCESS) { 435 free(pval); 436 return (err); 437 } 438 *outbuf = pval; 439 return (PICL_SUCCESS); 440 } 441 442 if (pinfo.type != PICL_PTYPE_TABLE) 443 return (PICL_FAILURE); 444 445 /* get first string from table */ 446 err = picl_get_propval(proph, &tblh, pinfo.size); 447 if (err != PICL_SUCCESS) 448 return (err); 449 450 err = picl_get_next_by_row(tblh, &rowproph); 451 if (err != PICL_SUCCESS) 452 return (err); 453 454 err = picl_get_propinfo(rowproph, &pinfo); 455 if (err != PICL_SUCCESS) 456 return (err); 457 458 pval = malloc(pinfo.size); 459 if (pval == NULL) 460 return (PICL_FAILURE); 461 462 err = picl_get_propval(rowproph, pval, pinfo.size); 463 if (err != PICL_SUCCESS) { 464 free(pval); 465 return (err); 466 } 467 468 *outbuf = pval; 469 return (PICL_SUCCESS); 470 } 471 472 int 473 do_piclinfo(int syserrlog) 474 { 475 picl_nodehdl_t rooth; /* root PICL node for IO display */ 476 picl_nodehdl_t plafh; /* Platform PICL node for IO display */ 477 478 picl_errno_t err; 479 480 err = picl_initialize(); 481 if (err != PICL_SUCCESS) { 482 (void) log_printf("picl_initialize failed: %s\n", 483 picl_strerror(err)); 484 return (err); 485 } 486 487 488 err = picl_get_root(&rooth); 489 if (err != PICL_SUCCESS) { 490 (void) log_printf("Getting root node failed: %s\n", 491 picl_strerror(err)); 492 return (err); 493 } 494 495 err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh); 496 497 if (err != PICL_SUCCESS) { 498 (void) log_printf("Getting nodes by name failed: %s\n", 499 picl_strerror(err)); 500 return (err); 501 } 502 503 err = opl_display_pci(syserrlog, plafh); 504 505 (void) picl_shutdown(); 506 507 return (err); 508 } 509 510 /* 511 * search children to get the node by the nodename 512 */ 513 static int 514 opl_get_node_by_name(picl_nodehdl_t rooth, char *name, 515 picl_nodehdl_t *nodeh) 516 { 517 picl_nodehdl_t childh; 518 int err; 519 char *nodename; 520 521 nodename = alloca(strlen(name) + 1); 522 if (nodename == NULL) 523 return (PICL_FAILURE); 524 525 err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh, 526 sizeof (picl_nodehdl_t)); 527 528 while (err == PICL_SUCCESS) { 529 err = picl_get_propval_by_name(childh, PICL_PROP_NAME, 530 nodename, (strlen(name) + 1)); 531 if (err != PICL_SUCCESS) { 532 err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 533 &childh, sizeof (picl_nodehdl_t)); 534 continue; 535 } 536 537 if (strcmp(nodename, name) == 0) { 538 *nodeh = childh; 539 return (PICL_SUCCESS); 540 } 541 542 err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 543 &childh, sizeof (picl_nodehdl_t)); 544 } 545 546 return (err); 547 } 548 549 static int 550 open_root_complex(char *root_complex) 551 { 552 char *path; 553 static char device_str[] = {"/devices"}; 554 static char devctl_str[] = {":reg"}; 555 int fd; 556 557 path = malloc( 558 strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str)); 559 if (path == NULL) 560 return (PICL_FAILURE); 561 (void) strcpy(path, device_str); 562 (void) strcat(path, root_complex); 563 (void) strcat(path, devctl_str); 564 565 if ((fd = open(path, O_RDWR)) == -1) { 566 return (-1); 567 } 568 return (fd); 569 } 570 571 static uint32_t 572 read_long(int fd, int bus, int dev, int func, int offset, int *ret) 573 { 574 int rval; 575 pcitool_reg_t prg; 576 577 prg.user_version = PCITOOL_VERSION; 578 prg.barnum = 0; 579 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + 580 PCITOOL_ACC_ATTR_ENDN_LTL; 581 prg.bus_no = bus; 582 prg.dev_no = dev; 583 prg.func_no = func; 584 prg.offset = offset; 585 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); 586 if (rval != 0) { 587 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno)); 588 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); 589 } 590 *ret = rval; 591 return ((uint32_t)prg.data); 592 } 593 594 static uint16_t 595 read_word(int fd, int bus, int dev, int func, int offset, int *ret) 596 { 597 int rval; 598 pcitool_reg_t prg; 599 600 prg.user_version = PCITOOL_VERSION; 601 prg.barnum = 0; 602 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + 603 PCITOOL_ACC_ATTR_ENDN_LTL; 604 prg.bus_no = bus; 605 prg.dev_no = dev; 606 prg.func_no = func; 607 prg.offset = offset; 608 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); 609 if (rval != 0) { 610 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno)); 611 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); 612 } 613 *ret = rval; 614 return ((uint16_t)prg.data); 615 } 616 617 static uint8_t 618 read_byte(int fd, int bus, int dev, int func, int offset, int *ret) 619 { 620 int rval; 621 pcitool_reg_t prg; 622 623 prg.user_version = PCITOOL_VERSION; 624 prg.barnum = 0; 625 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + 626 PCITOOL_ACC_ATTR_ENDN_LTL; 627 prg.bus_no = bus; 628 prg.dev_no = dev; 629 prg.func_no = func; 630 prg.offset = offset; 631 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); 632 if (rval != 0) { 633 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno)); 634 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); 635 } 636 *ret = rval; 637 return ((uint8_t)prg.data); 638 } 639 640 641 static picl_errno_t 642 get_lane_width 643 (char *device_path, int bus, int dev, int func, int *actual, 644 int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type) 645 { 646 uint_t cap_ptr, cap_reg, link_status, link_cap, capid; 647 int fd, ret; 648 649 if (device_path == NULL) 650 return (PICL_FAILURE); 651 652 fd = open_root_complex(device_path); 653 if (fd == -1) 654 return (PICL_FAILURE); 655 656 /* 657 * Link Capabilities and Link Status registers are in the 658 * PCI-E capabilities register. They are at offset 659 * 0xc and 0x12 respectively. They are documented in section 660 * 7.8 of the PCI Express Base Specification. The address of 661 * that structure is not fixed, it's kind of a linked list. 662 * The Capabilities Pointer reg (8 bits) is always at 0x34. 663 * It contains a pointer to the first capabilities structure. 664 * For each capability structure, the first 8 bits is the capability 665 * ID. The next 8 bits is the pointer to the next structure. 666 * If the Next Cap register is zero, it's the end of the list. 667 * The capability ID for the PCI-E strucutre is 0x10. The idea 668 * is to follow the links until you find a Cap ID of 0x10, then 669 * read the registers at 0xc and 0x12 from there. 670 * If there's no Cap ID 0x10, then it's not a PCI-E device. 671 */ 672 673 cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret); 674 if (ret != 0) { 675 /* ioctl failure */ 676 close(fd); 677 return (PICL_FAILURE); 678 } 679 cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret); 680 if (ret != 0) { 681 /* ioctl failure */ 682 close(fd); 683 return (PICL_FAILURE); 684 } 685 *type = PCI; 686 capid = cap_reg & PCI_CAP_MASK; 687 while (cap_ptr != 0) { 688 689 if (capid == PCI_CAP_ID_PCI_E) { 690 link_cap = read_long(fd, bus, dev, func, cap_ptr + 691 PCIE_LINKCAP, &ret); 692 if (ret != 0) { 693 close(fd); 694 return (PICL_FAILURE); 695 } 696 link_status = read_word(fd, bus, dev, func, 697 cap_ptr + PCIE_LINKSTS, &ret); 698 if (ret != 0) { 699 close(fd); 700 return (PICL_FAILURE); 701 } 702 *actual = ((link_status >> PCI_LINK_SHIFT) & 703 PCI_LINK_MASK); 704 *maximum = ((link_cap >> PCI_LINK_SHIFT) & 705 PCI_LINK_MASK); 706 *type = PCIE; 707 } else if (capid == PCI_CAP_ID_PCIX) { 708 uint32_t pcix_status; 709 uint8_t hdr_type; 710 int max_speed = PCI_FREQ_66; 711 712 hdr_type = read_byte 713 (fd, bus, dev, func, PCI_CONF_HEADER, &ret); 714 if (ret != 0) { 715 /* ioctl failure */ 716 close(fd); 717 return (PICL_FAILURE); 718 } 719 *type = PCIX; 720 if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 721 /* This is a PCI-X bridge */ 722 uint16_t sec_status, mode; 723 sec_status = read_word(fd, bus, dev, func, 724 cap_ptr + PCI_PCIX_SEC_STATUS, &ret); 725 if (ret != 0) { 726 /* ioctl failure */ 727 close(fd); 728 return (PICL_FAILURE); 729 } 730 if (sec_status & PCI_SEC_133) 731 max_speed = PCI_FREQ_133; 732 if (sec_status & PCI_SEC_266) 733 max_speed = PCI_FREQ_266; 734 if (sec_status & PCI_SEC_533) 735 max_speed = PCI_FREQ_533; 736 *speed_max = max_speed; 737 mode = (sec_status >> PCI_CLASS_BRIDGE) & 738 PCI_BRIDGE_MC; 739 if (mode) { 740 int speed; 741 if (mode == PCI_MODE_66) 742 speed = PCI_FREQ_66; 743 else if (mode == PCI_MODE_100) 744 speed = PCI_FREQ_100; 745 else if (mode == PCI_MODE_133) 746 speed = PCI_FREQ_133; 747 *speed_at = speed; 748 } 749 750 } else { /* Leaf device */ 751 pcix_status = read_long(fd, bus, dev, func, 752 cap_ptr + PCI_PCIX_STATUS, &ret); 753 if (ret != 0) { 754 /* ioctl failure */ 755 close(fd); 756 return (PICL_FAILURE); 757 } 758 if (pcix_status & 759 (PCI_LEAF_ULONG << PCI_SHIFT_133)) 760 max_speed = PCI_FREQ_133; 761 if (pcix_status & 762 (PCI_LEAF_ULONG << PCI_SHIFT_266)) 763 max_speed = PCI_FREQ_266; 764 if (pcix_status & 765 (PCI_LEAF_ULONG << PCI_SHIFT_533)) 766 max_speed = PCI_FREQ_533; 767 *speed_max = max_speed; 768 } 769 } 770 cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT); 771 cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret); 772 if (ret != 0) { 773 /* ioctl failure */ 774 close(fd); 775 return (PICL_FAILURE); 776 } 777 capid = cap_reg & PCI_CAP_MASK; 778 } 779 780 if (close(fd) == -1) { 781 return (PICL_FAILURE); 782 } 783 784 return (PICL_SUCCESS); 785 } 786 787 static int 788 is_66mhz_capable(picl_nodehdl_t nodeh) 789 { 790 picl_errno_t err; 791 picl_prophdl_t proph; 792 picl_propinfo_t pinfo; 793 794 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_66MHZ_CAPABLE, 795 &pinfo, &proph); 796 if (err == PICL_SUCCESS) 797 return (1); 798 return (0); 799 } 800 801 /* 802 * get the clock frequency 803 */ 804 static int 805 picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq, uint32_t *freq_max) 806 { 807 int err; 808 uint64_t clk_freq; 809 810 *freq_max = PCI_FREQ_33; 811 if (is_66mhz_capable(modh)) 812 *freq_max = PCI_FREQ_66; 813 clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err); 814 if (err != PICL_SUCCESS) 815 return (err); 816 817 *freq = ROUND_TO_MHZ(clk_freq); 818 819 return (PICL_SUCCESS); 820 } 821 822 static uint64_t 823 picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 824 { 825 int err; 826 picl_prophdl_t proph; 827 picl_propinfo_t pinfo; 828 uint8_t uint8v; 829 uint16_t uint16v; 830 uint32_t uint32v; 831 uint64_t uint64v; 832 833 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 834 if (err != PICL_SUCCESS) { 835 *ret = err; 836 return (0); 837 } 838 839 /* 840 * If it is not an int or uint prop, return failure 841 */ 842 if ((pinfo.type != PICL_PTYPE_INT) && 843 (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) { 844 *ret = PICL_FAILURE; 845 return (0); 846 } 847 848 849 /* uint prop */ 850 851 switch (pinfo.size) { 852 case sizeof (uint8_t): 853 err = picl_get_propval(proph, &uint8v, sizeof (uint8v)); 854 *ret = err; 855 return (uint8v); 856 case sizeof (uint16_t): 857 err = picl_get_propval(proph, &uint16v, sizeof (uint16v)); 858 *ret = err; 859 return (uint16v); 860 case sizeof (uint32_t): 861 err = picl_get_propval(proph, &uint32v, sizeof (uint32v)); 862 *ret = err; 863 return (uint32v); 864 case sizeof (uint64_t): 865 err = picl_get_propval(proph, &uint64v, sizeof (uint64v)); 866 *ret = err; 867 return (uint64v); 868 default: /* not supported size */ 869 *ret = PICL_FAILURE; 870 return (0); 871 } 872 } 873 874 /* 875 * recursively visit all nodes 876 */ 877 static picl_errno_t 878 do_walk(picl_nodehdl_t rooth, const char *classname, 879 void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args)) 880 { 881 picl_errno_t err; 882 picl_nodehdl_t chdh; 883 char classval[PICL_CLASSNAMELEN_MAX]; 884 885 err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, 886 sizeof (chdh)); 887 while (err == PICL_SUCCESS) { 888 err = picl_get_propval_by_name(chdh, PICL_PROP_NAME, 889 classval, sizeof (classval)); 890 if (err != PICL_SUCCESS) 891 return (err); 892 893 err = callback_fn(chdh, c_args); 894 895 if ((err = do_walk(chdh, classname, c_args, callback_fn)) != 896 PICL_WALK_CONTINUE) 897 return (err); 898 899 err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 900 sizeof (chdh)); 901 } 902 if (err == PICL_PROPNOTFOUND) /* end of a branch */ 903 return (PICL_WALK_CONTINUE); 904 return (err); 905 } 906 907 int 908 get_proc_mode(void) 909 { 910 picl_nodehdl_t nodeh; 911 picl_prophdl_t proph; 912 picl_errno_t err; 913 914 err = picl_initialize(); 915 if (err != PICL_SUCCESS) { 916 (void) log_printf("picl_initialize failed: %s\n", 917 picl_strerror(err)); 918 return (err); 919 } 920 921 err = picl_get_node_by_path("/platform", &nodeh); 922 if (err != PICL_SUCCESS) { 923 (void) log_printf("Getting plat node failed: %s\n", 924 picl_strerror(err)); 925 return (err); 926 } 927 928 err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode", &proph); 929 if (err != PICL_SUCCESS) { 930 /* Do not display error message */ 931 return (err); 932 } 933 934 (void) picl_shutdown(); 935 936 return (err); 937 } 938