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