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