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