/** * init_node * * @param node * @returns 0 on success, !0 otherwise */ static int init_node(struct dr_node *node) { DIR *d; struct dirent *de; char child_path[DR_PATH_MAX]; uint32_t my_drc_index; int rc; if (node->is_owned) find_ofdt_dname(node, node->ofdt_path); d = opendir(node->ofdt_path); if (!d) return -1; rc = 0; while ((de = readdir(d)) != NULL) { if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; sprintf(child_path, "%s/%s", node->ofdt_path, de->d_name); if (get_my_drc_index(child_path, &my_drc_index)) continue; if (node->dev_type == PCI_HP_DEV) { if (node->drc_index == my_drc_index) { /* Add hotplug children */ add_child_node(node, child_path); } } else { if (!node->is_owned) { if (node->drc_index == my_drc_index) { /* Update node path */ snprintf(node->ofdt_path, DR_PATH_MAX, "%s", child_path); node->is_owned = 1; /* Populate w/ children */ rc = init_node(node); if (rc) break; } } else { /* Add all DR-capable children */ add_child_node(node, child_path); } } } closedir(d); return rc; }
static int cpu_index_to_path(struct dr_node *cpu) { DIR *d; struct dirent *de; int found = 0; int rc; char path[DR_PATH_MAX]; d = opendir(CPU_OFDT_BASE); if (d == NULL) { say(ERROR, "Could not open %s: %s\n", CPU_OFDT_BASE, strerror(errno)); return -1; } while ((de = readdir(d)) != NULL) { uint32_t my_drc_index; if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; if (strncmp(de->d_name, "PowerPC", 7)) continue; sprintf(path, "%s/%s", CPU_OFDT_BASE, de->d_name); rc = get_my_drc_index(path, &my_drc_index); if (rc) { /* This is an error, but continue searching since * this may not be the drc index we are looking for */ say(DEBUG, "Could not retrieve drc_index for %s\n", path); continue; } if (my_drc_index == cpu->drc_index) { found = 1; break; } } closedir(d); if (found) snprintf(cpu->ofdt_path, DR_PATH_MAX, "%s", path); return rc; }
/** * update_phb_ic_info * @brief Add interrupt controller information to PHB nodes * * We need to have the interrupt-controller ofdt paths for all PHB * nodes to do DLPAR. This routine adds that information for PHB nodes * that we found. * * @param node_list list of PHB nodes * @returns 0 on success, !0 otherwise */ static int update_phb_ic_info(struct dr_node *node_list) { char *ic_dir = "interrupt-controller"; struct dr_node *node; struct dirent *de; DIR *d; int rc = 0; d = opendir(OFDT_BASE); if (d == NULL) { say(ERROR, "failed to open %s\n%s\n", OFDT_BASE, strerror(errno)); return -1; } while ((de = readdir(d)) != NULL) { uint my_drc_index; char ofdt_path[DR_PATH_MAX]; if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; if (strncmp(de->d_name, ic_dir, strlen(ic_dir))) continue; sprintf(ofdt_path, "%s/%s", OFDT_BASE, de->d_name); rc = get_my_drc_index(ofdt_path, &my_drc_index); if (rc) /* This is expected to fail sometimes, as there can be * more ICs than PHBs on a system. In this case, some * ICs won't have my-drc-index. */ continue; for (node = node_list; node; node = node->next) { if ((node->dev_type == PHB_DEV) && (node->drc_index == my_drc_index)) { snprintf(node->phb_ic_ofdt_path, DR_PATH_MAX, "%s", ofdt_path); break; } } } closedir(d); return 0; }
/** * 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; }
/** * examine_children * * @param node * @param child_path * @returns 0 on success, !0 otherwise */ static int examine_child(struct dr_node *node, char *child_path) { uint32_t my_drc_index; int used = 0; int rc = 0; if (get_my_drc_index(child_path, &my_drc_index)) goto done; if (node->dev_type == PCI_HP_DEV) { if (node->drc_index == my_drc_index) { /* Add hotplug children */ add_child_node(node, child_path); used = 1; } } else { if (! node->is_owned) { if (node->drc_index == my_drc_index) { /* Update node path */ snprintf(node->ofdt_path, DR_PATH_MAX, "%s", child_path); node->is_owned = 1; used = 1; /* Populate w/ children */ rc = init_node(node); } } else { /* Add all DR-capable children */ add_child_node(node, child_path); used = 1; } } done: if (! used) free(child_path); return rc; }
/** * 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; }
/** * get_mem_node_lmbs * @brief Retrieve lmbs from the OF device tree represented as memory@XXX nodes * * @param lmb_list pointer to lmb list head to populate * @returns 0 on success, !0 on failure */ int get_mem_node_lmbs(struct lmb_list_head *lmb_list) { struct dr_node *lmb; struct dirent *de; DIR *d; int rc = 0; d = opendir(OFDT_BASE); if (d == NULL) { report_unknown_error(__FILE__, __LINE__); say(DEBUG, "Could not open %s\n", OFDT_BASE); return -1; } while ((de = readdir(d)) != NULL) { char path[1024]; uint32_t my_drc_index; char *tmp; if (de->d_type != DT_DIR) continue; if (strncmp(de->d_name, "memory@", 7)) continue; memset(path, 0, 1024); sprintf(path, "%s/%s", OFDT_BASE, de->d_name); if (get_my_drc_index(path, &my_drc_index)) continue; for (lmb = lmb_list->lmbs; lmb; lmb = lmb->next) { if (lmb->drc_index == my_drc_index) break; } if (lmb == NULL) { say(DEBUG, "Could not find LMB with drc-index of %x\n", my_drc_index); rc = -1; break; } snprintf(lmb->ofdt_path, DR_PATH_MAX, "%s", path); lmb->is_owned = 1; /* Find the lmb size for this lmb */ /* XXX Do nothing with size and break if it can't be found * but don't change rc to indicate failure? * Why not continue? If we break, set rc=-1? */ if (get_lmb_size(lmb)) break; /* Find the physical address for this lmb */ tmp = strrchr(lmb->ofdt_path, '@'); if (tmp == NULL) { say(DEBUG, "Could not determine physical address for " "%s\n", lmb->ofdt_path); /* XXX No rc change? */ break; } lmb->lmb_address = strtoull(tmp + 1, NULL, 16); /* find the associated sysfs memory blocks */ rc = get_mem_scns(lmb); if (rc) break; } closedir(d); return rc; }