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