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 * Cherrystone platform-specific functions that aren't platform specific 26 * 27 */ 28 29 #include <psvc_objects.h> 30 #include <libprtdiag.h> 31 #include <sys/mc.h> 32 33 /* prtdiag exit codes */ 34 #define PD_SUCCESS 0 35 #define PD_SYSTEM_FAILURE 1 36 #define PD_INTERNAL_FAILURE 2 37 38 static int exit_code = PD_SUCCESS; 39 40 static Prom_node *dev_next_node_by_compat(Prom_node *root, char *model); 41 static Prom_node *dev_find_node_by_compat(Prom_node *root, char *model); 42 43 void print_us3_memory_line(int portid, 44 int bank_id, 45 uint64_t bank_size, 46 char *bank_status, 47 uint64_t dimm_size, 48 uint32_t intlv, 49 int seg_id); 50 51 void add_node(Sys_tree *root, Prom_node *pnode); 52 int do_prominfo(int syserrlog, 53 char *pgname, 54 int log_flag, 55 int prt_flag); 56 57 void *get_prop_val(Prop *prop); 58 Prop *find_prop(Prom_node *pnode, char *name); 59 char *get_node_name(Prom_node *pnode); 60 char *get_node_type(Prom_node *pnode); 61 62 void fill_pci_card_list(Prom_node *pci_instance, 63 Prom_node *pci_card_node, 64 struct io_card *pci_card, 65 struct io_card **pci_card_list, 66 char **pci_slot_name_arr); 67 68 static Prom_node *next_pci_card(Prom_node *curr_card, int *is_bridge, 69 int is_pcidev, Prom_node *curr_bridge, 70 Prom_node * parent_bridge, Prom_node *pci); 71 72 #define HZ_TO_MHZ(x) (((x) + 500000) / 1000000) 73 74 /* 75 * Start from the current node and return the next node besides 76 * the current one which has the requested model property. 77 */ 78 static Prom_node * 79 dev_next_node_by_compat(Prom_node *root, char *compat) 80 { 81 Prom_node *node; 82 83 if (root == NULL) 84 return (NULL); 85 86 /* look at your children first */ 87 if ((node = dev_find_node_by_compat(root->child, compat)) != NULL) 88 return (node); 89 90 /* now look at your siblings */ 91 if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL) 92 return (node); 93 94 return (NULL); /* not found */ 95 } 96 97 /* 98 * Do a depth-first walk of a device tree and 99 * return the first node with the matching model. 100 */ 101 static Prom_node * 102 dev_find_node_by_compat(Prom_node *root, char *compat) 103 { 104 Prom_node *node; 105 char *compatible; 106 char *name; 107 108 if (root == NULL) 109 return (NULL); 110 111 if (compat == NULL) 112 return (NULL); 113 114 name = get_node_name(root); 115 if (name == NULL) 116 name = ""; 117 118 compatible = (char *)get_prop_val(find_prop(root, "compatible")); 119 120 if (compatible == NULL) 121 return (NULL); 122 123 if ((strcmp(name, "pci") == 0) && (compatible != NULL) && 124 (strcmp(compatible, compat) == 0)) { 125 return (root); /* found a match */ 126 } 127 128 /* look at your children first */ 129 if ((node = dev_find_node_by_compat(root->child, compat)) != NULL) 130 return (node); 131 132 /* now look at your siblings */ 133 if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL) 134 return (node); 135 136 return (NULL); /* not found */ 137 } 138 139 int32_t 140 find_child_device(picl_nodehdl_t parent, char *child_name, 141 picl_nodehdl_t *child) 142 { 143 int32_t err; 144 char name[PICL_PROPNAMELEN_MAX]; 145 146 err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child), 147 sizeof (picl_nodehdl_t)); 148 switch (err) { 149 case PICL_SUCCESS: 150 break; 151 case PICL_PROPNOTFOUND: 152 err = PICL_INVALIDHANDLE; 153 return (err); 154 default: 155 #ifdef WORKFILE_DEBUG 156 log_printf(dgettext(TEXT_DOMAIN, 157 "Failed picl_get_propval_by_name with %s\n"), 158 picl_strerror(err)); 159 #endif 160 return (err); 161 } 162 163 err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name, 164 PICL_PROPNAMELEN_MAX); 165 166 #ifdef WORKFILE_DEBUG 167 if (err != PICL_SUCCESS) { 168 log_printf(dgettext(TEXT_DOMAIN, 169 "failed the get name for root\n")); 170 log_printf(dgettext(TEXT_DOMAIN, "%s\n"), picl_strerror(err)); 171 } 172 #endif 173 174 if (strcmp(name, child_name) == 0) 175 return (err); 176 177 while (err != PICL_PROPNOTFOUND) { 178 #ifdef WORKFILE_DEBUG 179 log_printf(dgettext(TEXT_DOMAIN, "child name is %s\n"), name); 180 #endif 181 err = picl_get_propval_by_name(*child, PICL_PROP_PEER, 182 &(*child), sizeof (picl_nodehdl_t)); 183 switch (err) { 184 case PICL_SUCCESS: 185 err = picl_get_propval_by_name(*child, PICL_PROP_NAME, 186 name, PICL_PROPNAMELEN_MAX); 187 if (strcmp(name, child_name) == 0) 188 return (err); 189 break; 190 case PICL_PROPNOTFOUND: 191 break; 192 default: 193 #ifdef WORKFILE_DEBUG 194 log_printf(dgettext(TEXT_DOMAIN, 195 "Failed picl_get_propval_by_name with %s\n"), 196 picl_strerror(err)); 197 #endif 198 return (err); 199 } 200 } 201 err = PICL_INVALIDHANDLE; 202 return (err); 203 } 204 205 int32_t 206 fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id, 207 picl_nodehdl_t *device) 208 { 209 int32_t err; 210 picl_prophdl_t tbl_hdl; 211 picl_prophdl_t reference_property; 212 213 err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl, 214 sizeof (picl_prophdl_t)); 215 if (err != PICL_SUCCESS) { 216 #ifdef WORKFILE_DEBUG 217 if (err != PICL_INVALIDHANDLE) { 218 log_printf(dgettext(TEXT_DOMAIN, 219 "fill_device_from_id failure in " 220 "picl_get_propval_by_name err is %s\n"), 221 picl_strerror(err)); 222 } 223 #endif 224 return (err); 225 } 226 227 err = picl_get_next_by_row(tbl_hdl, &reference_property); 228 if (err != PICL_SUCCESS) { 229 #ifdef WORKFILE_DEBUG 230 log_printf(dgettext(TEXT_DOMAIN, 231 "fill_device_from_id failure in picl_get_next_by_row" 232 " err is %s\n"), picl_strerror(err)); 233 #endif 234 return (err); 235 } 236 237 /* get node associated with reference property */ 238 err = picl_get_propval(reference_property, &(*device), 239 sizeof (picl_nodehdl_t)); 240 241 #ifdef WORKFILE_DEBUG 242 if (err != 0) { 243 log_printf(dgettext(TEXT_DOMAIN, 244 "fill_device_from_id failure in picl_get_propval" 245 " err is %s\n"), picl_strerror(err)); 246 } 247 #endif 248 249 return (err); 250 } 251 252 int32_t 253 fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id, 254 int32_t *number_of_devices, picl_nodehdl_t *device_array[]) 255 { 256 int32_t err; 257 int i; 258 picl_prophdl_t tbl_hdl; 259 picl_prophdl_t entry; 260 int devs = 0; 261 262 err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl, 263 sizeof (picl_prophdl_t)); 264 if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) { 265 #ifdef WORKFILE_DEBUG 266 log_printf(dgettext(TEXT_DOMAIN, 267 "fill_device_array_from_id failure in " 268 "picl_get_propval_by_name err is %s\n"), 269 picl_strerror(err)); 270 #endif 271 return (err); 272 } 273 274 entry = tbl_hdl; 275 while (picl_get_next_by_row(entry, &entry) == 0) 276 ++devs; 277 278 *device_array = calloc((devs), sizeof (picl_nodehdl_t)); 279 if (*device_array == NULL) { 280 281 #ifdef WORFILE_DEBUG 282 log_printf(dgettext(TEXT_DOMAIN, 283 "fill_device_array_from_id failure getting memory" 284 " for array\n")); 285 #endif 286 return (PICL_FAILURE); 287 } 288 289 entry = tbl_hdl; 290 for (i = 0; i < devs; i++) { 291 err = picl_get_next_by_row(entry, &entry); 292 if (err != 0) { 293 #ifdef WORKFILE_DEBUG 294 log_printf(dgettext(TEXT_DOMAIN, 295 "fill_device_array_from_id failure in " 296 "picl_get_next_by_row err is %s\n"), 297 picl_strerror(err)); 298 #endif 299 return (err); 300 } 301 302 /* get node associated with reference property */ 303 err = picl_get_propval(entry, &((*device_array)[i]), 304 sizeof (picl_nodehdl_t)); 305 if (err != 0) { 306 #ifdef WORKFILE_DEBUG 307 log_printf(dgettext(TEXT_DOMAIN, 308 "fill_device_array_from_id failure in " 309 "picl_get_propval err is %s\n"), picl_strerror(err)); 310 #endif 311 312 return (err); 313 } 314 } 315 *number_of_devices = devs; 316 return (err); 317 } 318 319 /* 320 * add_node 321 * 322 * This function adds a board node to the board structure where that 323 * that node's physical component lives. 324 */ 325 void 326 add_node(Sys_tree *root, Prom_node *pnode) 327 { 328 int board = -1; 329 int portid = -1; 330 331 void *value = NULL; 332 Board_node *bnode = NULL; 333 Prom_node *p = NULL; 334 335 /* Get the board number of this board from the portid prop */ 336 value = get_prop_val(find_prop(pnode, "portid")); 337 if (value != NULL) { 338 portid = *(int *)value; 339 } 340 341 board = CHERRYSTONE_GETSLOT(portid); 342 343 if ((bnode = find_board(root, board)) == NULL) { 344 bnode = insert_board(root, board); 345 } 346 347 /* now attach this prom node to the board list */ 348 /* Insert this node at the end of the list */ 349 pnode->sibling = NULL; 350 if (bnode->nodes == NULL) 351 bnode->nodes = pnode; 352 else { 353 p = bnode->nodes; 354 while (p->sibling != NULL) 355 p = p->sibling; 356 p->sibling = pnode; 357 } 358 } 359 360 /* 361 * This function provides formatting of the memory config 362 * information that get_us3_mem_regs() and display_us3_banks() code has 363 * gathered. It overrides the generic print_us3_memory_line() code 364 * which prints an error message. 365 */ 366 void 367 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 368 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id) 369 { 370 log_printf(dgettext(TEXT_DOMAIN, 371 "\n %-1c %2d %2d %4lldMB %11-s %4lldMB " 372 " %2d-way %d"), 373 CHERRYSTONE_GETSLOT_LABEL(portid), portid, 374 (bank_id % 4), bank_size, bank_status, dimm_size, 375 intlv, seg_id, 0); 376 } 377 378 /* 379 * We call do_devinfo() in order to use the libdevinfo device tree instead of 380 * OBP's device tree. Ignore its return value and use our exit_code instead. 381 * Its return value comes from calling error_check() which is not implemented 382 * because the device tree does not keep track of the status property for the 383 * 480/490. The exit_code we return is set while do_devinfo() calls our local 384 * functions to gather/print data. That way we can report both internal and 385 * device failures. 386 */ 387 int 388 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 389 { 390 (void) do_devinfo(syserrlog, pgname, log_flag, prt_flag); 391 return (exit_code); 392 } 393 394 /* 395 * return the property value for the Prop 396 * passed in. (When using libdevinfo) 397 */ 398 void * 399 get_prop_val(Prop *prop) 400 { 401 if (prop == NULL) 402 return (NULL); 403 404 return ((void *)(prop->value.val_ptr)); 405 } 406 407 /* 408 * Search a Prom node and retrieve the property with the correct 409 * name. (When using libdevinfo) 410 */ 411 Prop * 412 find_prop(Prom_node *pnode, char *name) 413 { 414 Prop *prop; 415 416 if (pnode == NULL) 417 return (NULL); 418 419 if (pnode->props == NULL) 420 return (NULL); 421 422 prop = pnode->props; 423 if (prop == NULL) 424 return (NULL); 425 426 if (prop->name.val_ptr == NULL) 427 return (NULL); 428 429 while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) { 430 prop = prop->next; 431 } 432 return (prop); 433 } 434 435 /* 436 * This function searches through the properties of the node passed in 437 * and returns a pointer to the value of the name property. 438 * (When using libdevinfo) 439 */ 440 char * 441 get_node_name(Prom_node *pnode) 442 { 443 Prop *prop; 444 445 if (pnode == NULL) { 446 return (NULL); 447 } 448 449 prop = pnode->props; 450 while (prop != NULL) { 451 if (strcmp("name", (char *)prop->name.val_ptr) == 0) 452 return (prop->value.val_ptr); 453 prop = prop->next; 454 } 455 return (NULL); 456 } 457 458 /* 459 * This function searches through the properties of the node passed in 460 * and returns a pointer to the value of the device_type property. 461 * (When using libdevinfo) 462 */ 463 char * 464 get_node_type(Prom_node *pnode) 465 { 466 Prop *prop; 467 468 if (pnode == NULL) { 469 return (NULL); 470 } 471 472 prop = pnode->props; 473 while (prop != NULL) { 474 if (strcmp("device_type", (char *)prop->name.val_ptr) == 0) 475 return (prop->value.val_ptr); 476 prop = prop->next; 477 } 478 return (NULL); 479 } 480 481 482 /* 483 * Fills in the i/o card list to be displayed later in display_pci(); 484 */ 485 void 486 fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node, 487 struct io_card *pci_card, 488 struct io_card **pci_card_list, char **slot_name_arr) 489 { 490 Prom_node *pci_bridge_node; 491 Prom_node *pci_parent_bridge; 492 int *int_val; 493 int pci_bridge = FALSE; 494 int pci_bridge_dev_no = -1; 495 int portid; 496 int pci_bus; 497 char buf[MAXSTRLEN]; 498 char *slot_name = NULL; /* info in "slot-names" prop */ 499 char *child_name; 500 char *name; 501 char *type; 502 void *value; 503 504 while (pci_card_node != NULL) { 505 int is_pci = FALSE; 506 type = NULL; 507 name = NULL; 508 /* If it doesn't have a name, skip it */ 509 name = (char *)get_prop_val( 510 find_prop(pci_card_node, "name")); 511 if (name == NULL) { 512 pci_card_node = pci_card_node->sibling; 513 continue; 514 } 515 516 /* 517 * Get the portid of the schizo that this card 518 * lives under. 519 */ 520 portid = -1; 521 value = get_prop_val(find_prop(pci_instance, "portid")); 522 if (value != NULL) { 523 portid = *(int *)value; 524 } 525 pci_card->schizo_portid = portid; 526 if (pci_card->schizo_portid != 8) { 527 /* 528 * Schizo0 (portid 8) has no slots on Cherrystone. 529 * So if that's who we're looking at, we're done. 530 */ 531 return; 532 } 533 534 /* 535 * Find out whether this is PCI bus A or B 536 * using the 'reg' property. 537 */ 538 int_val = (int *)get_prop_val(find_prop(pci_instance, "reg")); 539 540 if (int_val != NULL) { 541 int_val++; /* skip over first integer */ 542 pci_bus = ((*int_val) & 0x7f0000); 543 if (pci_bus == 0x600000) 544 pci_card->pci_bus = 'A'; 545 else if (pci_bus == 0x700000) 546 pci_card->pci_bus = 'B'; 547 else { 548 assert(0); /* should never happen */ 549 pci_card->pci_bus = '-'; 550 } 551 } else { 552 assert(0); /* should never happen */ 553 pci_card->pci_bus = '-'; 554 } 555 556 /* 557 * get dev# and func# for this card from the 558 * 'reg' property. 559 */ 560 int_val = (int *)get_prop_val( 561 find_prop(pci_card_node, "reg")); 562 if (int_val != NULL) { 563 pci_card->dev_no = (((*int_val) & 0xF800) >> 11); 564 pci_card->func_no = (((*int_val) & 0x700) >> 8); 565 } else { 566 pci_card->dev_no = -1; 567 pci_card->func_no = -1; 568 } 569 570 switch (pci_card->pci_bus) { 571 case 'A': 572 if ((pci_card->dev_no < 1 || pci_card->dev_no > 2) && 573 (!pci_bridge)) { 574 pci_card_node = pci_card_node->sibling; 575 continue; 576 } 577 break; 578 case 'B': 579 if ((pci_card->dev_no < 2 || pci_card->dev_no > 5) && 580 (!pci_bridge)) { 581 pci_card_node = pci_card_node->sibling; 582 continue; 583 } 584 break; 585 default: 586 pci_card_node = pci_card_node->sibling; 587 continue; 588 } 589 590 type = (char *)get_prop_val( 591 find_prop(pci_card_node, "device_type")); 592 /* 593 * If this is a pci-bridge, then store its dev# 594 * as its children nodes need this to get their slot#. 595 * We set the pci_bridge flag so that we know we are 596 * looking at a pci-bridge node. This flag gets reset 597 * every time we enter this while loop. 598 */ 599 600 /* 601 * Check for a PCI-PCI Bridge for PCI and cPCI 602 * IO Boards using the name and type properties. 603 */ 604 if ((type != NULL) && (strncmp(name, "pci", 3) == 0) && 605 (strcmp(type, "pci") == 0)) { 606 pci_bridge_node = pci_card_node; 607 is_pci = TRUE; 608 if (!pci_bridge) { 609 pci_bridge_dev_no = pci_card->dev_no; 610 pci_parent_bridge = pci_bridge_node; 611 pci_bridge = TRUE; 612 } 613 } 614 615 /* 616 * Get slot-names property from slot_names_arr. 617 * If we are the child of a pci_bridge we use the 618 * dev# of the pci_bridge as an index to get 619 * the slot number. We know that we are a child of 620 * a pci-bridge if our parent is the same as the last 621 * pci_bridge node found above. 622 */ 623 if (pci_card->dev_no != -1) { 624 /* 625 * We compare this cards parent node with the 626 * pci_bridge_node to see if it's a child. 627 */ 628 if (pci_card_node->parent != pci_instance && 629 pci_bridge) { 630 /* use dev_no of pci_bridge */ 631 if (pci_card->pci_bus == 'B') { 632 slot_name = 633 slot_name_arr[pci_bridge_dev_no -2]; 634 } else { 635 slot_name = 636 slot_name_arr[pci_bridge_dev_no -1]; 637 } 638 } else { 639 if (pci_card->pci_bus == 'B') { 640 slot_name = 641 slot_name_arr[pci_card->dev_no-2]; 642 } else { 643 slot_name = 644 slot_name_arr[pci_card->dev_no-1]; 645 } 646 } 647 648 if (slot_name != NULL && 649 strlen(slot_name) != 0) { 650 /* Slot num is last char in string */ 651 (void) snprintf(pci_card->slot_str, MAXSTRLEN, 652 "%c", slot_name[strlen(slot_name) - 1]); 653 } else { 654 (void) snprintf(pci_card->slot_str, MAXSTRLEN, 655 "-"); 656 } 657 658 } else { 659 (void) snprintf(pci_card->slot_str, MAXSTRLEN, 660 "%c", '-'); 661 } 662 663 /* 664 * Check for failed status. 665 */ 666 if (node_failed(pci_card_node)) 667 (void) strcpy(pci_card->status, "fail"); 668 else 669 (void) strcpy(pci_card->status, "ok"); 670 671 /* Get the model of this pci_card */ 672 value = get_prop_val(find_prop(pci_card_node, "model")); 673 if (value == NULL) 674 pci_card->model[0] = '\0'; 675 else { 676 (void) snprintf(pci_card->model, MAXSTRLEN, "%s", 677 (char *)value); 678 } 679 /* 680 * The card may have a "clock-frequency" but we 681 * are not interested in that. Instead we get the 682 * "clock-frequency" of the PCI Bus that the card 683 * resides on. PCI-A can operate at 33Mhz or 66Mhz 684 * depending on what card is plugged into the Bus. 685 * PCI-B always operates at 33Mhz. 686 */ 687 int_val = get_prop_val(find_prop(pci_instance, 688 "clock-frequency")); 689 if (int_val != NULL) { 690 pci_card->freq = HZ_TO_MHZ(*int_val); 691 } else { 692 pci_card->freq = -1; 693 } 694 695 /* 696 * Figure out how we want to display the name 697 */ 698 value = get_prop_val(find_prop(pci_card_node, 699 "compatible")); 700 if (value != NULL) { 701 /* use 'name'-'compatible' */ 702 (void) snprintf(buf, MAXSTRLEN, "%s-%s", name, 703 (char *)value); 704 } else { 705 /* just use 'name' */ 706 (void) snprintf(buf, MAXSTRLEN, "%s", name); 707 } 708 name = buf; 709 710 /* 711 * If this node has children, add the device_type 712 * of the child to the name value of this pci_card-> 713 */ 714 child_name = (char *)get_node_name(pci_card_node->child); 715 if ((pci_card_node->child != NULL) && 716 (child_name != NULL)) { 717 value = get_prop_val(find_prop(pci_card_node->child, 718 "device_type")); 719 if (value != NULL) { 720 /* add device_type of child to name */ 721 (void) snprintf(pci_card->name, MAXSTRLEN, 722 "%s/%s (%s)", name, child_name, 723 (char *)value); 724 } else { 725 /* just add childs name */ 726 (void) snprintf(pci_card->name, MAXSTRLEN, 727 "%s/%s", name, child_name); 728 } 729 } else { 730 (void) snprintf(pci_card->name, MAXSTRLEN, "%s", 731 (char *)name); 732 } 733 734 /* 735 * If this is a pci-bridge, then add the word 736 * 'pci-bridge' to its model. If we can't find 737 * a model, then we just describe what the device 738 * is based on some properties. 739 */ 740 if (pci_bridge) { 741 if (strlen(pci_card->model) == 0) { 742 if (pci_card_node->parent == pci_bridge_node) 743 (void) snprintf(pci_card->model, 744 MAXSTRLEN, 745 "%s", "device on pci-bridge"); 746 else if (pci_card_node->parent 747 == pci_parent_bridge) 748 (void) snprintf(pci_card->model, 749 MAXSTRLEN, 750 "%s", "pci-bridge/pci-bridge"); 751 else 752 (void) snprintf(pci_card->model, 753 MAXSTRLEN, 754 "%s", "PCI-BRIDGE"); 755 } 756 else 757 (void) snprintf(pci_card->model, MAXSTRLEN, 758 "%s/pci-bridge", pci_card->model); 759 } 760 /* insert this pci_card in the list to be displayed later */ 761 762 *pci_card_list = insert_io_card(*pci_card_list, pci_card); 763 764 /* 765 * If we are dealing with a pci-bridge, we need to move 766 * down to the children of this bridge if there are any. 767 * 768 * If we are not, we are either dealing with a regular 769 * card (in which case we move onto the sibling of this 770 * card) or we are dealing with a child of a pci-bridge 771 * (in which case we move onto the child's siblings or 772 * if there are no more siblings for this child, we 773 * move onto the parents siblings). 774 */ 775 pci_card_node = next_pci_card(pci_card_node, &pci_bridge, 776 is_pci, pci_bridge_node, 777 pci_parent_bridge, pci_instance); 778 } /* end-while */ 779 } 780 781 /* 782 * Helper function for fill_pci_card_list(). Indicates which 783 * card node to go to next. 784 * Parameters: 785 * ----------- 786 * Prom_node * curr_card: pointer to the current card node 787 * 788 * int * is_bridge: indicates whether or not the card (is | is on) 789 * a pci bridge 790 * 791 * int is_pcidev: indicates whether or not the current card 792 * is a pci bridge 793 * 794 * Prom_node * curr_bridge: pointer to the current pci bridge. Eg: 795 * curr_card->parent. 796 * 797 * Prom_node * parent_bridge: pointer to the first pci bridge encountered. 798 * we could have nested pci bridges, this would 799 * be the first one. 800 * 801 * Prom_node * pci: pointer to the pci instance that we are attached to. 802 * This would be parent_bridge->parent, or 803 * curr_node->parent, if curr_node is not on a pci bridge. 804 */ 805 static Prom_node * 806 next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev, 807 Prom_node *curr_bridge, Prom_node *parent_bridge, 808 Prom_node *pci) 809 { 810 Prom_node * curr_node = curr_card; 811 if (*is_bridge) { 812 /* 813 * is_pcidev is used to prevent us from following the 814 * children of something like a scsi device. 815 */ 816 if (curr_node->child != NULL && is_pcidev) { 817 curr_node = curr_node->child; 818 } else { 819 curr_node = curr_node->sibling; 820 if (curr_node == NULL) { 821 curr_node = curr_bridge->sibling; 822 while (curr_node == NULL && 823 curr_bridge != parent_bridge && 824 curr_bridge != NULL) { 825 curr_node = 826 curr_bridge->parent->sibling; 827 curr_bridge = curr_bridge->parent; 828 if (curr_node != NULL && 829 curr_node->parent == pci) 830 break; 831 } 832 if (curr_bridge == NULL || 833 curr_node == NULL || 834 curr_node->parent == pci || 835 curr_bridge == parent_bridge || 836 curr_node == parent_bridge) { 837 *is_bridge = FALSE; 838 } 839 } 840 } 841 842 } else { 843 curr_node = curr_node->sibling; 844 } 845 return (curr_node); 846 } 847