/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2000, 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Daktari Platform specific functions. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #define EXIT_MSG(msg, err) \ { printf("\n%s failed with %d\n", msg, err); exit(err); } /* we only need the 5 LSB of the portid to calculate the board number */ #define DAK_SAFARI_ID_MASK 0x1F /* 5 bits */ #define DAK_NODE_MASK 0x1F /* 5 bits */ #define DAK_PORTID_NODE_SHIFT 5 #define DAK_MIN_CPU_SAFARI_ID 0 /* 0x00 */ #define DAK_MAX_CPU_SAFARI_ID 23 /* 0x17 */ #define DAK_MIN_IO_SAFARI_ID 24 /* 0x18 */ #define DAK_MAX_IO_SAFARI_ID 31 /* 0x1F */ #define NUM_MBANKS_PER_MC 4 #define DAK_CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000) /* * DAK_PORTID_IS_CPU_TYPE * * If the portid associated with a CPU board is passed in, TRUE is returned, * otherwise FALSE. */ #define DAK_PORTID_IS_CPU_TYPE(portid) \ (((((portid) & DAK_SAFARI_ID_MASK) >= DAK_MIN_CPU_SAFARI_ID) && \ (((portid) & DAK_SAFARI_ID_MASK) <= DAK_MAX_CPU_SAFARI_ID)) ? \ TRUE: FALSE) /* * DAK_CPU_BD_PORTID_TO_BD_NUM * * If the portid associated with a CPU board is passed in, the board number * associated with this portid is returned, otherwise -1. */ #define DAK_CPU_BD_PORTID_TO_BD_NUM(portid) \ ((DAK_PORTID_IS_CPU_TYPE(portid)) ? \ (((portid) & DAK_SAFARI_ID_MASK) / 4) : (-1)) /* * DAK_PORTID_IS_IO_TYPE * * If the portid associated with an IO board is passed in, TRUE is returned, * otherwise FALSE. */ #define DAK_PORTID_IS_IO_TYPE(portid) \ (((((portid) & DAK_SAFARI_ID_MASK) >= DAK_MIN_IO_SAFARI_ID) && \ (((portid) & DAK_SAFARI_ID_MASK) <= DAK_MAX_IO_SAFARI_ID)) ? \ TRUE: FALSE) /* * DAK_IO_BD_PORTID_TO_BD_NUM * * If the portid associated with an IO board is passed in, the board number * associated with this portid is returned, otherwise -1. */ #define DAK_IO_BD_PORTID_TO_BD_NUM(portid) \ (DAK_PORTID_IS_IO_TYPE(portid) ? \ (((((portid) & DAK_SAFARI_ID_MASK) - 24) / 2) + 6) : (-1)) /* * DAK_PORTID_TO_BOARD_NUM * * If a valid portid is passed in, this macro returns the board number * associated with it, otherwise it returns -1. */ #define DAK_PORTID_TO_BOARD_NUM(portid) \ ((DAK_PORTID_IS_CPU_TYPE(portid)) ? \ (DAK_CPU_BD_PORTID_TO_BD_NUM(portid)) : \ ((DAK_PORTID_IS_IO_TYPE(portid)) ? \ DAK_IO_BD_PORTID_TO_BD_NUM(portid) : (-1))) /* Local Functions */ char *get_node_name(Prom_node *pnode); char *get_node_type(Prom_node *pnode); void add_node(Sys_tree *root, Prom_node *pnode); Prop *find_prop(Prom_node *pnode, char *name); int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag); void *get_prop_val(Prop *prop); char *get_node_type(Prom_node *pnode); int get_us3_mem_regs(Board_node *bnode); void fill_pci_card_list(Prom_node *pci_instance, Prom_node *pci_card_node, struct io_card *pci_card, struct io_card **pci_card_list, char **pci_slot_name_arr); static Prom_node *next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev, Prom_node *curr_bridge, Prom_node * parent_bridge, Prom_node *pci); static Prom_node *dev_next_node_by_compat(Prom_node *root, char *compat); static Prom_node *dev_find_node_by_compat(Prom_node *root, char *compat); static Board_node *daktari_insert_board(Sys_tree *root, int board); static Board_node *daktari_find_board(Sys_tree *root, int board); static int32_t find_child_device(picl_nodehdl_t, char *, picl_nodehdl_t *); static int32_t fill_device_from_id(picl_nodehdl_t, char *, picl_nodehdl_t *); static int32_t fill_device_array_from_id(picl_nodehdl_t, char *, int32_t *, picl_nodehdl_t **); /* Overlaying routines */ /* * This function searches through the properties of the node passed in * and returns a pointer to the value of the name property. */ char * get_node_name(Prom_node *pnode) { Prop *prop; if (pnode == NULL) return (NULL); prop = pnode->props; while (prop != NULL) { if (strcmp("name", (char *)prop->name.val_ptr) == 0) return (prop->value.val_ptr); prop = prop->next; } return (NULL); } /* * This function searches through the properties of the node passed in * and returns a pointer to the value of the name property. */ char * get_node_type(Prom_node *pnode) { Prop *prop; if (pnode == NULL) { return (NULL); } prop = pnode->props; while (prop != NULL) { if (strcmp("device_type", (char *)prop->name.val_ptr) == 0) return (prop->value.val_ptr); prop = prop->next; } return (NULL); } /* * add_node * * This function adds a board node to the board structure where that * that node's physical component lives. */ void add_node(Sys_tree *root, Prom_node *pnode) { int board = -1; int portid = -1; void *value = NULL; Board_node *bnode = NULL; Prom_node *p = NULL; /* Get the board number of this board from the portid prop */ value = get_prop_val(find_prop(pnode, "portid")); if (value != NULL) { portid = *(int *)value; } board = DAK_PORTID_TO_BOARD_NUM(portid); /* board = DAK_GETSLOT(portid); */ /* find the board node with the same board number */ if ((bnode = daktari_find_board(root, board)) == NULL) { bnode = daktari_insert_board(root, board); } /* now attach this prom node to the board list */ /* Insert this node at the end of the list */ pnode->sibling = NULL; if (bnode->nodes == NULL) bnode->nodes = pnode; else { p = bnode->nodes; while (p->sibling != NULL) p = p->sibling; p->sibling = pnode; } } /* * Search a Prom node and retrieve the property with the correct * name. */ Prop * find_prop(Prom_node *pnode, char *name) { Prop *prop; if (pnode == NULL) return (NULL); if (pnode->props == NULL) return (NULL); prop = pnode->props; if (prop == NULL) return (NULL); if (prop->name.val_ptr == NULL) return (NULL); while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) { prop = prop->next; } return (prop); } int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) { return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); } /* * return the property value for the Prop * passed in. */ void * get_prop_val(Prop *prop) { if (prop == NULL) return (NULL); return ((void *)(prop->value.val_ptr)); } /* Local Routines */ /* * Start from the current node and return the next node besides * the current one which has the requested model property. */ static Prom_node * dev_next_node_by_compat(Prom_node *root, char *compat) { Prom_node *node; if (root == NULL) return (NULL); /* look at your children first */ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL) return (node); /* now look at your siblings */ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL) return (node); return (NULL); /* not found */ } /* * Do a depth-first walk of a device tree and * return the first node with the matching model. */ static Prom_node * dev_find_node_by_compat(Prom_node *root, char *compat) { Prom_node *node; char *compatible; char *name; if (root == NULL) return (NULL); if (compat == NULL) return (NULL); name = get_node_name(root); if (name == NULL) name = ""; compatible = (char *)get_prop_val(find_prop(root, "compatible")); if (compatible == NULL) return (NULL); if ((strcmp(name, "pci") == 0) && (compatible != NULL) && (strcmp(compatible, compat) == 0)) { return (root); /* found a match */ } /* look at your children first */ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL) return (node); /* now look at your siblings */ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL) return (node); return (NULL); /* not found */ } /* * Add a board to the system list in order (sorted by board#). * Initialize all pointer fields to NULL. */ static Board_node * daktari_insert_board(Sys_tree *root, int board) { Board_node *bnode; Board_node *temp = root->bd_list; if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) { perror("malloc"); exit(1); } bnode->nodes = NULL; bnode->next = NULL; bnode->board_num = board; bnode->board_type = UNKNOWN_BOARD; if (temp == NULL) root->bd_list = bnode; else if (temp->board_num > board) { bnode->next = temp; root->bd_list = bnode; } else { while ((temp->next != NULL) && (board > temp->next->board_num)) temp = temp->next; bnode->next = temp->next; temp->next = bnode; } root->board_cnt++; return (bnode); } /* * Find the requested board struct in the system device tree. * * This function overrides the functionality of the generic find_board() * function in libprtdiag, but since we need to pass another parameter, * we cannot simply overlay the symbol table. */ static Board_node * daktari_find_board(Sys_tree *root, int board) { Board_node *bnode = root->bd_list; while ((bnode != NULL) && (board != bnode->board_num)) { bnode = bnode->next; } return (bnode); } int32_t find_child_device(picl_nodehdl_t parent, char *child_name, picl_nodehdl_t *child) { int32_t err; char name[PICL_PROPNAMELEN_MAX]; err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child), sizeof (picl_nodehdl_t)); switch (err) { case PICL_SUCCESS: break; case PICL_PROPNOTFOUND: err = PICL_INVALIDHANDLE; return (err); default: #ifdef WORKFILE_DEBUG log_printf(dgettext(TEXT_DOMAIN, "Failed picl_get_propval_by_name with %s\n"), picl_strerror(err)); #endif return (err); } err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name, PICL_PROPNAMELEN_MAX); #ifdef WORKFILE_DEBUG if (err != PICL_SUCCESS) { log_printf(dgettext(TEXT_DOMAIN, "failed the get name for root\n"), 0); log_printf(dgettext(TEXT_DOMAIN, "%s\n"), picl_strerror(err), 0); } #endif if (strcmp(name, child_name) == 0) return (err); while (err != PICL_PROPNOTFOUND) { err = picl_get_propval_by_name(*child, PICL_PROP_PEER, &(*child), sizeof (picl_nodehdl_t)); switch (err) { case PICL_SUCCESS: err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name, PICL_PROPNAMELEN_MAX); if (strcmp(name, child_name) == 0) return (err); break; case PICL_PROPNOTFOUND: break; default: #ifdef WORKFILE_DEBUG log_printf(dgettext(TEXT_DOMAIN, "Failed picl_get_propval_by_name with %s\n"), picl_strerror(err), 0); #endif return (err); } } err = PICL_INVALIDHANDLE; return (err); } int32_t fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id, picl_nodehdl_t *device) { int32_t err; picl_prophdl_t tbl_hdl; picl_prophdl_t reference_property; err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl, sizeof (picl_prophdl_t)); if (err != PICL_SUCCESS) { #ifdef WORKFILE_DEBUG if (err != PICL_INVALIDHANDLE) { log_printf(dgettext(TEXT_DOMAIN, "fill_device_from_id failure in " "picl_get_propval_by_name err is %s\n"), picl_strerror(err), 0); } #endif return (err); } err = picl_get_next_by_row(tbl_hdl, &reference_property); if (err != PICL_SUCCESS) { #ifdef WORKFILE_DEBUG log_printf(dgettext(TEXT_DOMAIN, "fill_device_from_id failure in picl_get_next_by_row" " err is %s\n"), picl_strerror(err), 0); #endif return (err); } /* get node associated with reference property */ err = picl_get_propval(reference_property, &(*device), sizeof (picl_nodehdl_t)); #ifdef WORKFILE_DEBUG if (err != 0) { log_printf(dgettext(TEXT_DOMAIN, "fill_device_from_id failure in picl_get_propval" " err is %s\n"), picl_strerror(err), 0); } #endif return (err); } int32_t fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id, int32_t *number_of_devices, picl_nodehdl_t *device_array[]) { int32_t err; int i; picl_prophdl_t tbl_hdl; picl_prophdl_t entry; int devs = 0; err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl, sizeof (picl_prophdl_t)); if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) { #ifdef WORKFILE_DEBUG log_printf(dgettext(TEXT_DOMAIN, "fill_device_array_from_id failure in " "picl_get_propval_by_name err is %s\n"), picl_strerror(err), 0); #endif return (err); } entry = tbl_hdl; while (picl_get_next_by_row(entry, &entry) == 0) ++devs; *device_array = calloc((devs), sizeof (picl_nodehdl_t)); if (*device_array == NULL) { #ifdef WORKFILE_DEBUG log_printf(dgettext(TEXT_DOMAIN, "fill_device_array_from_id failure getting memory" " for array\n"), 0); #endif return (PICL_FAILURE); } entry = tbl_hdl; for (i = 0; i < (devs); i++) { err = picl_get_next_by_row(entry, &entry); if (err != 0) { #ifdef WORKFILE_DEBUG log_printf(dgettext(TEXT_DOMAIN, "fill_device_array_from_id failure in " "picl_get_next_by_row err is %s\n"), picl_strerror(err), 0); #endif return (err); } /* get node associated with reference property */ err = picl_get_propval(entry, &((*device_array)[i]), sizeof (picl_nodehdl_t)); if (err != 0) { #ifdef WORKFILE_DEBUG log_printf(dgettext(TEXT_DOMAIN, "fill_device_array_from_id failure in " "picl_get_propval err is %s\n"), picl_strerror(err), 0); #endif return (err); } } *number_of_devices = devs; return (err); } /* * This function provides formatting of the memory config * information that get_us3_mem_regs() and display_us3_banks() code has * gathered. It overrides the generic print_us3_memory_line() code * which prints an error message. */ void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id) { int mcid; mcid = portid; log_printf(dgettext(TEXT_DOMAIN, "\n %-1c %2d %2d %4lldMB %11-s %4lldMB " " %2d-way %d"), 'A' + DAK_GETSLOT(portid), mcid, (bank_id % 4), bank_size, bank_status, dimm_size, intlv, seg_id, 0); } /* * Fills in the i/o card list to be displayed later in display_pci(); */ void fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node, struct io_card *pci_card, struct io_card **pci_card_list, char **slot_name_arr) { Prom_node *pci_bridge_node; Prom_node *pci_parent_bridge; int *int_val; int pci_bridge = FALSE; int pci_bridge_dev_no = -1; int portid; int pci_bus; char buf[MAXSTRLEN]; char *slot_name = NULL; /* info in "slot-names" prop */ char *child_name; char *name; char *type; void *value; while (pci_card_node != NULL) { int is_pci = FALSE; type = NULL; name = NULL; /* If it doesn't have a name, skip it */ name = (char *)get_prop_val( find_prop(pci_card_node, "name")); if (name == NULL) { pci_card_node = pci_card_node->sibling; continue; } /* * Get the portid of the schizo that this card * lives under. */ portid = -1; value = get_prop_val(find_prop(pci_instance, "portid")); if (value != NULL) { portid = *(int *)value; } pci_card->schizo_portid = portid; /* * Find out whether this is PCI bus A or B * using the 'reg' property. */ int_val = (int *)get_prop_val(find_prop(pci_instance, "reg")); if (int_val != NULL) { int_val++; /* skip over first integer */ pci_bus = ((*int_val) & 0x7f0000); if (pci_bus == 0x600000) pci_card->pci_bus = 'A'; else if (pci_bus == 0x700000) pci_card->pci_bus = 'B'; else pci_card->pci_bus = '-'; } else { pci_card->pci_bus = '-'; } if ((pci_card->schizo_portid == 8) && (pci_card->pci_bus == 'A')) { pci_card_node = pci_card_node->sibling; continue; } /* * get dev# and func# for this card from the * 'reg' property. */ int_val = (int *)get_prop_val( find_prop(pci_card_node, "reg")); if (int_val != NULL) { pci_card->dev_no = (((*int_val) & 0xF800) >> 11); pci_card->func_no = (((*int_val) & 0x700) >> 8); } else { pci_card->dev_no = -1; pci_card->func_no = -1; } type = (char *)get_prop_val( find_prop(pci_card_node, "device_type")); /* * If this is a pci-bridge, then store its dev# * as its children nodes need this to get their slot#. * We set the pci_bridge flag so that we know we are * looking at a pci-bridge node. This flag gets reset * every time we enter this while loop. */ /* * Check for a PCI-PCI Bridge for PCI and cPCI * IO Boards using the name and type properties. */ if ((type != NULL) && (strncmp(name, "pci", 3) == 0) && (strcmp(type, "pci") == 0)) { pci_bridge_node = pci_card_node; is_pci = TRUE; if (!pci_bridge) { pci_bridge_dev_no = pci_card->dev_no; pci_parent_bridge = pci_bridge_node; pci_bridge = TRUE; } } if ((pci_card->pci_bus == 'B') && (pci_card->dev_no == 1) && (!pci_bridge)) { pci_card_node = pci_card_node->sibling; continue; } /* * Get slot-names property from slot_names_arr. * If we are the child of a pci_bridge we use the * dev# of the pci_bridge as an index to get * the slot number. We know that we are a child of * a pci-bridge if our parent is the same as the last * pci_bridge node found above. */ if (pci_card->dev_no != -1) { /* * We compare this cards parent node with the * pci_bridge_node to see if it's a child. */ if (pci_card_node->parent != pci_instance && pci_bridge) { /* use dev_no of pci_bridge */ if (pci_card->pci_bus == 'B') { slot_name = slot_name_arr[pci_bridge_dev_no -2]; } else { slot_name = slot_name_arr[pci_bridge_dev_no -1]; } } else { if (pci_card->pci_bus == 'B') { slot_name = slot_name_arr[pci_card->dev_no-2]; } else { slot_name = slot_name_arr[pci_card->dev_no-1]; } } if (slot_name != NULL && strlen(slot_name) != 0) { /* Slot num is last char in string */ (void) snprintf(pci_card->slot_str, MAXSTRLEN, "%c", slot_name[strlen(slot_name) - 1]); } else { (void) snprintf(pci_card->slot_str, MAXSTRLEN, "-"); } } else { (void) snprintf(pci_card->slot_str, MAXSTRLEN, "%c", '-'); } /* * Check for failed status. */ if (node_failed(pci_card_node)) strcpy(pci_card->status, "fail"); else strcpy(pci_card->status, "ok"); /* Get the model of this pci_card */ value = get_prop_val(find_prop(pci_card_node, "model")); if (value == NULL) pci_card->model[0] = '\0'; else { (void) snprintf(pci_card->model, MAXSTRLEN, "%s", (char *)value); } /* * The card may have a "clock-frequency" but we * are not interested in that. Instead we get the * "clock-frequency" of the PCI Bus that the card * resides on. PCI-A can operate at 33Mhz or 66Mhz * depending on what card is plugged into the Bus. * PCI-B always operates at 33Mhz. */ int_val = get_prop_val(find_prop(pci_instance, "clock-frequency")); if (int_val != NULL) { pci_card->freq = DAK_CLK_FREQ_TO_MHZ(*int_val); } else { pci_card->freq = -1; } /* * Figure out how we want to display the name */ value = get_prop_val(find_prop(pci_card_node, "compatible")); if (value != NULL) { /* use 'name'-'compatible' */ (void) snprintf(buf, MAXSTRLEN, "%s-%s", name, (char *)value); } else { /* just use 'name' */ (void) snprintf(buf, MAXSTRLEN, "%s", name); } name = buf; /* * If this node has children, add the device_type * of the child to the name value of this pci_card-> */ child_name = (char *)get_node_name(pci_card_node->child); if ((pci_card_node->child != NULL) && (child_name != NULL)) { value = get_prop_val(find_prop(pci_card_node->child, "device_type")); if (value != NULL) { /* add device_type of child to name */ (void) snprintf(pci_card->name, MAXSTRLEN, "%s/%s (%s)", name, child_name, (char *)value); } else { /* just add childs name */ (void) snprintf(pci_card->name, MAXSTRLEN, "%s/%s", name, child_name); } } else { (void) snprintf(pci_card->name, MAXSTRLEN, "%s", (char *)name); } /* * If this is a pci-bridge, then add the word * 'pci-bridge' to its model. If we can't find * a model, then we just describe what the device * is based on some properties. */ if (pci_bridge) { if (strlen(pci_card->model) == 0) { if (pci_card_node->parent == pci_bridge_node) (void) snprintf(pci_card->model, MAXSTRLEN, "%s", "device on pci-bridge"); else if (pci_card_node->parent == pci_parent_bridge) (void) snprintf(pci_card->model, MAXSTRLEN, "%s", "pci-bridge/pci-bridge"); else (void) snprintf(pci_card->model, MAXSTRLEN, "%s", "PCI-BRIDGE"); } else (void) snprintf(pci_card->model, MAXSTRLEN, "%s/pci-bridge", pci_card->model); } /* insert this pci_card in the list to be displayed later */ *pci_card_list = insert_io_card(*pci_card_list, pci_card); /* * If we are dealing with a pci-bridge, we need to move * down to the children of this bridge if there are any. * * If we are not, we are either dealing with a regular * card (in which case we move onto the sibling of this * card) or we are dealing with a child of a pci-bridge * (in which case we move onto the child's siblings or * if there are no more siblings for this child, we * move onto the parents siblings). */ pci_card_node = next_pci_card(pci_card_node, &pci_bridge, is_pci, pci_bridge_node, pci_parent_bridge, pci_instance); } /* end-while */ } /* * Helper function for fill_pci_card_list(). Indicates which * card node to go to next. * Parameters: * ----------- * Prom_node * curr_card: pointer to the current card node * * int * is_bridge: indicates whether or not the card (is | is on) * a pci bridge * * int is_pcidev: indicates whether or not the current card * is a pci bridge * * Prom_node * curr_bridge: pointer to the current pci bridge. Eg: * curr_card->parent. * * Prom_node * parent_bridge: pointer to the first pci bridge encountered. * we could have nested pci bridges, this would * be the first one. * * Prom_node * pci: pointer to the pci instance that we are attached to. * This would be parent_bridge->parent, or * curr_node->parent, if curr_node is not on a pci bridge. */ static Prom_node * next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev, Prom_node *curr_bridge, Prom_node *parent_bridge, Prom_node *pci) { Prom_node * curr_node = curr_card; if (*is_bridge) { /* * is_pcidev is used to prevent us from following the * children of something like a scsi device. */ if (curr_node->child != NULL && is_pcidev) { curr_node = curr_node->child; } else { curr_node = curr_node->sibling; if (curr_node == NULL) { curr_node = curr_bridge->sibling; while (curr_node == NULL && curr_bridge != parent_bridge && curr_bridge != NULL) { curr_node = curr_bridge->parent->sibling; curr_bridge = curr_bridge->parent; if (curr_node != NULL && curr_node->parent == pci) { break; } } if (curr_bridge == NULL || curr_node == NULL || curr_node->parent == pci || curr_bridge == parent_bridge || curr_node == parent_bridge) { *is_bridge = FALSE; } } } } else { curr_node = curr_node->sibling; } return (curr_node); }