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 2007 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 /* Move on to next node */ 230 log_printf("Getting lane width failed for path %s\n", 231 pci_card.notes); 232 err = picl_get_propval_by_name 233 (nodeh, PICL_PROP_PEER, &nodeh, 234 sizeof (picl_nodehdl_t)); 235 continue; 236 } 237 238 239 err = picl_get_propval_by_name 240 (nodeh, PICL_PROP_NAME, name, sizeof (name)); 241 if (err != PICL_SUCCESS) 242 (void) strcpy(name, ""); 243 244 /* 245 * Get the name of this card. If binding_name is found, 246 * name will be <nodename>-<binding_name> 247 */ 248 249 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, 250 binding_name, sizeof (binding_name)); 251 if (err == PICL_PROPNOTFOUND) { 252 /* 253 * if compatible prop is found, name will be 254 * <nodename>-<compatible> 255 */ 256 err = opl_get_first_compatible_value(nodeh, 257 &compatible); 258 if (err == PICL_SUCCESS) { 259 (void) strlcat(name, "-", MAXSTRLEN); 260 (void) strlcat(name, compatible, MAXSTRLEN); 261 free(compatible); 262 } 263 } else if (err != PICL_SUCCESS) { 264 /* No binding-name or compatible */ 265 (void) strcpy(binding_name, "N/A"); 266 } else if (strcmp(name, binding_name) != 0) { 267 (void) strlcat(name, "-", MAXSTRLEN); 268 (void) strlcat(name, binding_name, MAXSTRLEN); 269 } 270 271 272 prop_size = sizeof (name) + 1; 273 if (prop_size > MAXSTRLEN) 274 prop_size = MAXSTRLEN; 275 (void) strlcpy(pci_card.name, name, prop_size); 276 277 /* Get the status of the card */ 278 err = picl_get_propval_by_name 279 (nodeh, PICL_PROP_STATUS, status, sizeof (status)); 280 281 282 /* Get the model of this card */ 283 284 err = picl_get_propval_by_name 285 (nodeh, OBP_PROP_MODEL, model, sizeof (model)); 286 prop_size = sizeof (model) + 1; 287 if (prop_size > MAXSTRLEN) 288 prop_size = MAXSTRLEN; 289 if (err != PICL_SUCCESS) 290 (void) strcpy(model, "N/A"); 291 (void) strlcpy(pci_card.model, model, prop_size); 292 293 if (bus_type == PCI) 294 (void) strlcpy(pci_card.bus_type, 295 "PCI", sizeof (pci_card.bus_type)); 296 else if (bus_type == PCIX) 297 (void) strlcpy(pci_card.bus_type, 298 "PCIx", sizeof (pci_card.bus_type)); 299 else if (bus_type == PCIE) 300 (void) strlcpy(pci_card.bus_type, 301 "PCIe", sizeof (pci_card.bus_type)); 302 else 303 (void) strlcpy(pci_card.bus_type, 304 "UNKN", sizeof (pci_card.bus_type)); 305 306 /* Get revision id */ 307 err = picl_get_propval_by_name 308 (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id)); 309 310 /* Get device id */ 311 err = picl_get_propval_by_name 312 (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id)); 313 314 /* Get vendor id */ 315 err = picl_get_propval_by_name 316 (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id)); 317 318 /* 319 * prtdiag -v prints all devices 320 */ 321 322 /* Print board number */ 323 log_printf("%02d ", pci_card.board); 324 /* Print IO Type */ 325 log_printf("%-5.5s ", pci_card.bus_type); 326 327 log_printf("%-3d ", pci_card.schizo_portid); 328 log_printf("%4x, %4x, %4x ", rev_id, dev_id, ven_id); 329 330 log_printf("%3d, %2d, %2d", 331 pci_card.slot, pci_card.dev_no, pci_card.func_no); 332 333 /* Print status */ 334 log_printf(" %-5.5s ", status); 335 336 /* Print Lane widths, Max/Sup Freq, Speed */ 337 if (bus_type == PCIE) { 338 PRINT_FMT(actual, maximum); 339 } else if (bus_type == PCIX) { 340 PRINT_FREQ_FMT(freq_at, freq_max); 341 } else if (bus_type == PCI) { 342 err = picldiag_get_clock_freq(nodeh, &freq_at); 343 PRINT_FREQ_FMT(freq_at, freq_max); 344 } else 345 log_printf(" -- , -- "); 346 347 /* Print Card Name */ 348 log_printf("%-30.30s", pci_card.name); 349 350 /* Print Card Model */ 351 log_printf(" %-20.20s", pci_card.model); 352 353 log_printf("\n"); 354 355 log_printf("%4s%-100.100s", " ", pci_card.notes); 356 log_printf("\n"); 357 log_printf("\n"); 358 359 360 err = picl_get_propval_by_name 361 (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t)); 362 363 } 364 365 return (PICL_WALK_CONTINUE); 366 } 367 368 /* 369 * opl_display_pci 370 * Display all the PCI IO cards on this board. 371 */ 372 static int 373 opl_display_pci(int syserrlog, picl_nodehdl_t plafh) 374 { 375 picl_errno_t err; 376 char *fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s"; 377 char *fmt2 = "%-16s"; 378 static int banner = FALSE; /* Have we printed the column headings? */ 379 380 if (banner == FALSE) { 381 log_printf("\n", 0); 382 log_printf("=========================", 0); 383 log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0); 384 log_printf("=========================", 0); 385 log_printf("\n", 0); 386 log_printf("\n", 0); 387 log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq", 388 "", "", 0); 389 log_printf("\n", 0); 390 391 log_printf(fmt, "LSB", "Type", "LPID", " RvID,DvID,VnID", 392 " BDF", "State", "Act, Max", "Name", "Model", 0); 393 394 log_printf("\n"); 395 396 log_printf(fmt, 397 "---", "-----", "----", " ------------------", 398 " ---------", "-----", "-----------", 399 "------------------------------", 400 "--------------------", 0); 401 log_printf("\n"); 402 log_printf(fmt2, " Logical Path"); 403 log_printf("\n"); 404 log_printf(fmt2, " ------------"); 405 log_printf("\n"); 406 banner = TRUE; 407 } 408 409 err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback); 410 return (err); 411 } 412 413 414 /* 415 * return the first compatible value 416 */ 417 static int 418 opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 419 { 420 picl_errno_t err; 421 picl_prophdl_t proph; 422 picl_propinfo_t pinfo; 423 picl_prophdl_t tblh; 424 picl_prophdl_t rowproph; 425 char *pval; 426 427 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 428 &pinfo, &proph); 429 if (err != PICL_SUCCESS) 430 return (err); 431 432 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 433 pval = malloc(pinfo.size); 434 if (pval == NULL) 435 return (PICL_FAILURE); 436 err = picl_get_propval(proph, pval, pinfo.size); 437 if (err != PICL_SUCCESS) { 438 free(pval); 439 return (err); 440 } 441 *outbuf = pval; 442 return (PICL_SUCCESS); 443 } 444 445 if (pinfo.type != PICL_PTYPE_TABLE) 446 return (PICL_FAILURE); 447 448 /* get first string from table */ 449 err = picl_get_propval(proph, &tblh, pinfo.size); 450 if (err != PICL_SUCCESS) 451 return (err); 452 453 err = picl_get_next_by_row(tblh, &rowproph); 454 if (err != PICL_SUCCESS) 455 return (err); 456 457 err = picl_get_propinfo(rowproph, &pinfo); 458 if (err != PICL_SUCCESS) 459 return (err); 460 461 pval = malloc(pinfo.size); 462 if (pval == NULL) 463 return (PICL_FAILURE); 464 465 err = picl_get_propval(rowproph, pval, pinfo.size); 466 if (err != PICL_SUCCESS) { 467 free(pval); 468 return (err); 469 } 470 471 *outbuf = pval; 472 return (PICL_SUCCESS); 473 } 474 475 int 476 do_piclinfo(int syserrlog) 477 { 478 picl_nodehdl_t rooth; /* root PICL node for IO display */ 479 picl_nodehdl_t plafh; /* Platform PICL node for IO display */ 480 481 picl_errno_t err; 482 483 err = picl_initialize(); 484 if (err != PICL_SUCCESS) { 485 (void) log_printf("picl_initialize failed: %s\n", 486 picl_strerror(err)); 487 return (err); 488 } 489 490 491 err = picl_get_root(&rooth); 492 if (err != PICL_SUCCESS) { 493 (void) log_printf("Getting root node failed: %s\n", 494 picl_strerror(err)); 495 return (err); 496 } 497 498 err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh); 499 500 if (err != PICL_SUCCESS) { 501 (void) log_printf("Getting nodes by name failed: %s\n", 502 picl_strerror(err)); 503 return (err); 504 } 505 506 err = opl_display_pci(syserrlog, plafh); 507 508 (void) picl_shutdown(); 509 510 return (err); 511 } 512 513 /* 514 * search children to get the node by the nodename 515 */ 516 static int 517 opl_get_node_by_name(picl_nodehdl_t rooth, char *name, 518 picl_nodehdl_t *nodeh) 519 { 520 picl_nodehdl_t childh; 521 int err; 522 char *nodename; 523 524 nodename = alloca(strlen(name) + 1); 525 if (nodename == NULL) 526 return (PICL_FAILURE); 527 528 err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh, 529 sizeof (picl_nodehdl_t)); 530 531 while (err == PICL_SUCCESS) { 532 err = picl_get_propval_by_name(childh, PICL_PROP_NAME, 533 nodename, (strlen(name) + 1)); 534 if (err != PICL_SUCCESS) { 535 err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 536 &childh, sizeof (picl_nodehdl_t)); 537 continue; 538 } 539 540 if (strcmp(nodename, name) == 0) { 541 *nodeh = childh; 542 return (PICL_SUCCESS); 543 } 544 545 err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 546 &childh, sizeof (picl_nodehdl_t)); 547 } 548 549 return (err); 550 } 551 552 static int 553 open_root_complex(char *root_complex) 554 { 555 char *path; 556 static char device_str[] = {"/devices"}; 557 static char devctl_str[] = {":reg"}; 558 int fd; 559 560 path = malloc( 561 strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str)); 562 if (path == NULL) 563 return (PICL_FAILURE); 564 (void) strcpy(path, device_str); 565 (void) strcat(path, root_complex); 566 (void) strcat(path, devctl_str); 567 568 if ((fd = open(path, O_RDWR)) == -1) { 569 return (-1); 570 } 571 return (fd); 572 } 573 574 static uint32_t 575 read_long(int fd, int bus, int dev, int func, int offset, int *ret) 576 { 577 int rval; 578 pcitool_reg_t prg; 579 580 prg.user_version = PCITOOL_VERSION; 581 prg.barnum = 0; 582 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + 583 PCITOOL_ACC_ATTR_ENDN_LTL; 584 prg.bus_no = bus; 585 prg.dev_no = dev; 586 prg.func_no = func; 587 prg.offset = offset; 588 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); 589 if (rval != 0) { 590 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno)); 591 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); 592 } 593 *ret = rval; 594 return ((uint32_t)prg.data); 595 } 596 597 static uint16_t 598 read_word(int fd, int bus, int dev, int func, int offset, int *ret) 599 { 600 int rval; 601 pcitool_reg_t prg; 602 603 prg.user_version = PCITOOL_VERSION; 604 prg.barnum = 0; 605 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + 606 PCITOOL_ACC_ATTR_ENDN_LTL; 607 prg.bus_no = bus; 608 prg.dev_no = dev; 609 prg.func_no = func; 610 prg.offset = offset; 611 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); 612 if (rval != 0) { 613 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno)); 614 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); 615 } 616 *ret = rval; 617 return ((uint16_t)prg.data); 618 } 619 620 static uint8_t 621 read_byte(int fd, int bus, int dev, int func, int offset, int *ret) 622 { 623 int rval; 624 pcitool_reg_t prg; 625 626 prg.user_version = PCITOOL_VERSION; 627 prg.barnum = 0; 628 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + 629 PCITOOL_ACC_ATTR_ENDN_LTL; 630 prg.bus_no = bus; 631 prg.dev_no = dev; 632 prg.func_no = func; 633 prg.offset = offset; 634 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); 635 if (rval != 0) { 636 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno)); 637 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); 638 } 639 *ret = rval; 640 return ((uint8_t)prg.data); 641 } 642 643 644 static picl_errno_t 645 get_lane_width 646 (char *device_path, int bus, int dev, int func, int *actual, 647 int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type) 648 { 649 uint_t cap_ptr, cap_reg, link_status, link_cap, capid; 650 int fd, ret; 651 652 if (device_path == NULL) 653 return (PICL_FAILURE); 654 655 fd = open_root_complex(device_path); 656 if (fd == -1) 657 return (PICL_FAILURE); 658 659 /* 660 * Link Capabilities and Link Status registers are in the 661 * PCI-E capabilities register. They are at offset 662 * 0xc and 0x12 respectively. They are documented in section 663 * 7.8 of the PCI Express Base Specification. The address of 664 * that structure is not fixed, it's kind of a linked list. 665 * The Capabilities Pointer reg (8 bits) is always at 0x34. 666 * It contains a pointer to the first capabilities structure. 667 * For each capability structure, the first 8 bits is the capability 668 * ID. The next 8 bits is the pointer to the next structure. 669 * If the Next Cap register is zero, it's the end of the list. 670 * The capability ID for the PCI-E strucutre is 0x10. The idea 671 * is to follow the links until you find a Cap ID of 0x10, then 672 * read the registers at 0xc and 0x12 from there. 673 * If there's no Cap ID 0x10, then it's not a PCI-E device. 674 */ 675 676 cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret); 677 if (ret != 0) { 678 /* ioctl failure */ 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 return (PICL_FAILURE); 685 } 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 return (PICL_FAILURE); 694 } 695 link_status = read_word(fd, bus, dev, func, 696 cap_ptr + PCIE_LINKSTS, &ret); 697 if (ret != 0) { 698 return (PICL_FAILURE); 699 } 700 *actual = ((link_status >> PCI_LINK_SHIFT) & 701 PCI_LINK_MASK); 702 *maximum = ((link_cap >> PCI_LINK_SHIFT) & 703 PCI_LINK_MASK); 704 *type = PCIE; 705 } 706 if (capid == PCI_CAP_ID_PCIX) { 707 uint32_t pcix_status; 708 uint8_t hdr_type; 709 int max_speed = PCI_FREQ_66; 710 711 hdr_type = read_byte 712 (fd, bus, dev, func, PCI_CONF_HEADER, &ret); 713 if (ret != 0) { 714 /* ioctl failure */ 715 return (PICL_FAILURE); 716 } 717 if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 718 /* This is a PCI-X bridge */ 719 uint16_t sec_status, mode; 720 sec_status = read_word(fd, bus, dev, func, 721 cap_ptr + PCI_PCIX_SEC_STATUS, &ret); 722 if (ret != 0) { 723 /* ioctl failure */ 724 return (PICL_FAILURE); 725 } 726 if (sec_status & PCI_SEC_133) 727 max_speed = PCI_FREQ_133; 728 if (sec_status & PCI_SEC_266) 729 max_speed = PCI_FREQ_266; 730 if (sec_status & PCI_SEC_533) 731 max_speed = PCI_FREQ_533; 732 *speed_max = max_speed; 733 *type = PCIX; 734 mode = (sec_status >> PCI_CLASS_BRIDGE) & 735 PCI_BRIDGE_MC; 736 if (mode) { 737 int speed; 738 if (mode == PCI_MODE_66) 739 speed = PCI_FREQ_66; 740 else if (mode == PCI_MODE_100) 741 speed = PCI_FREQ_100; 742 else if (mode == PCI_MODE_133) 743 speed = PCI_FREQ_133; 744 *speed_at = speed; 745 } 746 747 } else { /* Leaf device */ 748 pcix_status = read_long(fd, bus, dev, func, 749 cap_ptr + PCI_PCIX_STATUS, &ret); 750 if (ret != 0) { 751 /* ioctl failure */ 752 return (PICL_FAILURE); 753 } 754 if (pcix_status & 755 (PCI_LEAF_ULONG << PCI_SHIFT_133)) 756 max_speed = PCI_FREQ_133; 757 if (pcix_status & 758 (PCI_LEAF_ULONG << PCI_SHIFT_266)) 759 max_speed = PCI_FREQ_266; 760 if (pcix_status & 761 (PCI_LEAF_ULONG << PCI_SHIFT_533)) 762 max_speed = PCI_FREQ_533; 763 *speed_max = max_speed; 764 *type = PCI; 765 } 766 } 767 cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT); 768 cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret); 769 if (ret != 0) { 770 /* ioctl failure */ 771 return (PICL_FAILURE); 772 } 773 capid = cap_reg & PCI_CAP_MASK; 774 } 775 776 return (PICL_SUCCESS); 777 } 778 779 /* 780 * get the clock frequency 781 */ 782 static int 783 picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq) 784 { 785 int err; 786 uint64_t clk_freq; 787 788 clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err); 789 if (err != PICL_SUCCESS) 790 return (err); 791 792 *freq = ROUND_TO_MHZ(clk_freq); 793 794 return (PICL_SUCCESS); 795 } 796 797 static uint64_t 798 picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 799 { 800 int err; 801 picl_prophdl_t proph; 802 picl_propinfo_t pinfo; 803 uint8_t uint8v; 804 uint16_t uint16v; 805 uint32_t uint32v; 806 uint64_t uint64v; 807 808 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 809 if (err != PICL_SUCCESS) { 810 *ret = err; 811 return (0); 812 } 813 814 /* 815 * If it is not an int or uint prop, return failure 816 */ 817 if ((pinfo.type != PICL_PTYPE_INT) && 818 (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) { 819 *ret = PICL_FAILURE; 820 return (0); 821 } 822 823 824 /* uint prop */ 825 826 switch (pinfo.size) { 827 case sizeof (uint8_t): 828 err = picl_get_propval(proph, &uint8v, sizeof (uint8v)); 829 *ret = err; 830 return (uint8v); 831 case sizeof (uint16_t): 832 err = picl_get_propval(proph, &uint16v, sizeof (uint16v)); 833 *ret = err; 834 return (uint16v); 835 case sizeof (uint32_t): 836 err = picl_get_propval(proph, &uint32v, sizeof (uint32v)); 837 *ret = err; 838 return (uint32v); 839 case sizeof (uint64_t): 840 err = picl_get_propval(proph, &uint64v, sizeof (uint64v)); 841 *ret = err; 842 return (uint64v); 843 default: /* not supported size */ 844 *ret = PICL_FAILURE; 845 return (0); 846 } 847 } 848 849 /* 850 * recursively visit all nodes 851 */ 852 static picl_errno_t 853 do_walk(picl_nodehdl_t rooth, const char *classname, 854 void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args)) 855 { 856 picl_errno_t err; 857 picl_nodehdl_t chdh; 858 char classval[PICL_CLASSNAMELEN_MAX]; 859 860 err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, 861 sizeof (chdh)); 862 while (err == PICL_SUCCESS) { 863 err = picl_get_propval_by_name(chdh, PICL_PROP_NAME, 864 classval, sizeof (classval)); 865 if (err != PICL_SUCCESS) 866 return (err); 867 868 err = callback_fn(chdh, c_args); 869 870 if ((err = do_walk(chdh, classname, c_args, callback_fn)) != 871 PICL_WALK_CONTINUE) 872 return (err); 873 874 err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 875 sizeof (chdh)); 876 } 877 if (err == PICL_PROPNOTFOUND) /* end of a branch */ 878 return (PICL_WALK_CONTINUE); 879 return (err); 880 } 881 882 int 883 get_proc_mode(void) 884 { 885 picl_nodehdl_t nodeh; 886 picl_prophdl_t proph; 887 picl_errno_t err; 888 889 err = picl_initialize(); 890 if (err != PICL_SUCCESS) { 891 (void) log_printf("picl_initialize failed: %s\n", 892 picl_strerror(err)); 893 return (err); 894 } 895 896 err = picl_get_node_by_path("/platform", &nodeh); 897 if (err != PICL_SUCCESS) { 898 (void) log_printf("Getting plat node failed: %s\n", 899 picl_strerror(err)); 900 return (err); 901 } 902 903 err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode", &proph); 904 if (err != PICL_SUCCESS) { 905 /* Do not display error message */ 906 return (err); 907 } 908 909 (void) picl_shutdown(); 910 911 return (err); 912 } 913