/** * add_pci_vio_node * @bried Add a PCI or virtual device node * * @param path ofdt path to this node * @param dev_type type of device * @param node_list pointer to list to add node to * @returns 0 on success, !0 otherwise */ static int add_pci_vio_node(const char *path, int dev_type, struct dr_node **node_list) { struct dr_connector *drc_list; struct dr_connector *drc; struct dr_node *node; int child_dev_type = 0; int rc = -1; drc_list = get_drc_info(path); if (drc_list == NULL) return -1; for (drc = drc_list; drc != NULL; drc = drc->next) { switch (dev_type) { case PCI_HP_DEV: if (! is_hp_type(drc->type)) continue; child_dev_type = dev_type; break; case PCI_DLPAR_DEV: case VIO_DEV: if (! is_logical_type(drc->type)) continue; child_dev_type = dev_type; break; case PHB_DEV: if (is_logical_type(drc->type)) child_dev_type = PCI_DLPAR_DEV; else child_dev_type = PCI_HP_DEV; break; } node = alloc_dr_node(drc, child_dev_type, path); if (node == NULL) { say(ERROR, "Could not allocate pci/vio node\n"); return -1; } if (child_dev_type == PCI_HP_DEV) node->is_owned = 1; rc = init_node(node); if (rc) { free(node); return rc; } node->next = *node_list; *node_list = node; } return rc; }
/** * add_hea_node * @brief Add a node for an HEA adapter * * @param path ofdt_path to this node * @param drc_list list of drc's at OFDT_BASE * @param pointer to the node list to add new nodes to * @return 0 on success, !0 otherwise */ static int add_hea_node(char *path, struct dr_connector *drc_list, struct dr_node **node_list) { struct dr_connector *drc; struct dr_node *hea_node; uint my_drc_index; int rc; if (drc_list == NULL) return -1; if (get_my_drc_index(path, &my_drc_index)) return -1; for (drc = drc_list; drc != NULL; drc = drc->next) { if (drc->index == my_drc_index) break; } if (drc == NULL) { say(ERROR, "Could not find drc index 0x%x to add to hea list\n", my_drc_index); return -1; } hea_node = alloc_dr_node(drc, HEA_DEV, path); if (hea_node == NULL) { say(ERROR, "Could not allocate hea node for drc index 0x%x\n", my_drc_index); return -1; } hea_node->is_owned = 1; rc = init_node(hea_node); if (rc) { free(hea_node); return -1; } hea_node->next = *node_list; *node_list = hea_node; return 0; }
/** * add_phb_node * @brief Add a PHB node to the node list * * @param ofdt_poath, ofdt path to this node * @param drc_list list of drc's at OFDT_BASE * @param node_list list of nodes to add node to * @returns 0 on success, !0 otherwise */ static int add_phb_node(char *ofdt_path, struct dr_connector *drc_list, struct dr_node **node_list) { struct dr_node *phb_node; struct dr_connector *drc; uint my_drc_index; if (get_my_drc_index(ofdt_path, &my_drc_index)) return -1; for (drc = drc_list; drc; drc = drc->next) { if (drc->index == my_drc_index) break; } if (drc == NULL) { say(ERROR, "Could not find drc index 0x%x to add to phb list\n", my_drc_index); return -1; } phb_node = alloc_dr_node(drc, PHB_DEV, ofdt_path); if (phb_node == NULL) { say(ERROR, "Could not allocate PHB node for drc index 0x%x\n", my_drc_index); return -1; } phb_node->is_owned = 1; add_pci_vio_node(ofdt_path, PHB_DEV, &phb_node->children); phb_node->next = *node_list; *node_list = phb_node; return 0; }
/** * add_child_node * * Create information about the Open Firmware node and * add that information to the appropriate per-node list of * Open Firmware nodes. Also create the corresponding information * for any PCI device. * * NOTES: * 1) does not need to be concerned about one or more Open * Firmware nodes having the used-by-rtas property present. * One of the RTAS services used during removing a PCI adapter * must take the appropriate action (most likely eliminate RTAS * usage) in this case. * 2) Open Firmware node RPA physical location code: * * [Un.m-]Pn[-Pm]-In[[/Zn]-An] * * where * Un.m is for the enclosure for multi-enclosue systems * Pn is for the planar * In is for the slot * /Zn is for the connector on the adapter card * An is for the device connected to the adapter * * note * There may be multiple levels of planars [Pm]. * * RECOVERY OPERATION: * 1) This function does not add the Open Firmware node if the user * mode process has exceeded all available malloc space. This * should not happen based on the rather small total amount of * memory allocation required. The node is marked as skip. * 2) This function does not add the device information if there * is a problem initializing device. The node is marked as skip. * * @param parent * @param child_path */ static void add_child_node(struct dr_node *parent, char *child_path) { struct dr_connector *drc_list, *drc; char loc_code[DR_BUF_SZ]; char *slash; struct dr_node *child; uint my_drc_index; int rc; assert(parent != NULL); assert(strlen(child_path) != 0); /* Make sure that the Open Firmware node is not added twice * in case the ibm,my-drc-index property is put in all nodes * for the adapter instead of just the ones at the connector. */ if (parent->children != NULL) { struct dr_node *tmp; for (tmp = parent->children; tmp; tmp = tmp->next) { if (! strcmp(tmp->ofdt_path, child_path)) return; } } /* Create the Open Firmware node's information and insert that * information into the node's list based on the node's RPA * physical location code. Ignore the OF node if the node * does not have an RPA physical location code because that is * a firmware error. */ rc = get_property(child_path, "ibm,loc-code", &loc_code, DR_BUF_SZ); if (rc) return; /* Skip the Open Firmware node if it is a device node. Determine that * the node is for a device by looking for a hyphen after the last * slash (...-In/Z1-An). */ slash = strrchr(loc_code, '/'); if (slash != NULL) { char *hyphen; hyphen = strchr(slash, '-'); if (hyphen != NULL) return; *slash = '\0'; } if (parent->dev_type == PCI_HP_DEV) { /* hotplug */ /* Squadrons don't have "/" in devices' (scsi, * ethernet, tokenring ...) loc-code strings. * * Skip the Open Firmware node if the node's RPA * physical location code does not match the node's * location code. Ignore the connector information, * i.e. information after last slash if no hyphen * follows. */ if ((strcmp(parent->drc_name, loc_code) != 0) && (slash != NULL)) { parent->skip = 1; return; } } /* Restore the slash because the full RPA location code * is saved for each OF node so that the connector * information can be used to sort the OF node list for * each node. */ if (slash != NULL) *slash = '/'; if (get_my_drc_index(child_path, &my_drc_index)) return; /* need the drc-info in the dir above */ slash = strrchr(child_path, '/'); *slash = '\0'; drc_list = get_drc_info(child_path); *slash = '/'; for (drc = drc_list; drc != NULL; drc = drc->next) { if (drc->index == my_drc_index) break; } /* Allocate space for the Open Firmware node information. */ child = alloc_dr_node(drc, parent->dev_type, child_path); if (child == NULL) { parent->skip = 1; return; } if ((! strcmp(parent->drc_type, "SLOT")) && (parent->dev_type == PCI_DLPAR_DEV)) snprintf(child->ofdt_dname, DR_STR_MAX, "%s", parent->ofdt_dname); else get_property(child_path, "name", child->ofdt_dname, sizeof(child->ofdt_dname)); switch (parent->dev_type) { case PCI_HP_DEV: case PCI_DLPAR_DEV: { get_ofdt_uint_property(child_path, "vendor-id", &child->pci_vendor_id); get_ofdt_uint_property(child_path, "device-id", &child->pci_device_id); get_ofdt_uint_property(child_path, "class_code", &child->pci_class_code); break; } case HEA_DEV: { child->dev_type = HEA_PORT_DEV; get_ofdt_uint_property(child_path, "ibm,hea-port-no", &child->hea_port_no); get_ofdt_uint_property(child_path, "ibm,hea-port-tenure", &child->hea_port_tenure); break; } } child->next = parent->children; parent->children = child; }
/** * init_cpu_info * @brief Initialize cpu information * * @returns pointer to cpu_info on success, NULL otherwise */ static int init_cpu_info(struct dr_info *dr_info) { struct dr_connector *drc_list, *drc; struct dr_node *cpu, *cpu_list = NULL; DIR *d; struct dirent *de; int rc = 0; drc_list = get_drc_info(CPU_OFDT_BASE); if (drc_list == NULL) { say(ERROR, "Could not get drc information for %s\n", CPU_OFDT_BASE); return -1; } /* For cpu dlpar, we need a list of all possible cpus on the system */ for (drc = drc_list; drc; drc = drc->next) { cpu = alloc_dr_node(drc, CPU_DEV, NULL); if (cpu == NULL) { say(ERROR, "Could not allocate CPU node structure: " "%s\n", strerror(errno)); free_node(cpu_list); return -1; } cpu->next = cpu_list; cpu_list = cpu; } d = opendir(CPU_OFDT_BASE); if (d == NULL) { say(ERROR, "Could not open %s: %s\n", CPU_OFDT_BASE, strerror(errno)); free_node(cpu_list); return -1; } while ((de = readdir(d)) != NULL) { char path[DR_PATH_MAX]; if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; if (! strncmp(de->d_name, "PowerPC", 7)) { uint32_t my_drc_index; memset(path, 0, 1024); sprintf(path, "%s/%s", CPU_OFDT_BASE, de->d_name); rc = get_my_drc_index(path, &my_drc_index); if (rc) { say(ERROR, "Could not retrieve drc index for " "%s\n", path); break; } for (cpu = cpu_list; cpu; cpu = cpu->next) { if (cpu->drc_index == my_drc_index) break; } if (cpu == NULL) { say(ERROR, "Could not find cpu with drc index " "%x\n", my_drc_index); rc = -1; break; } rc = update_cpu_node(cpu, path, dr_info); if (rc) break; say(DEBUG, "Found cpu %s\n", cpu->name); } } closedir(d); if (rc) free_node(cpu_list); else dr_info->all_cpus = cpu_list; return rc; }