/** * acquire_cpu * * Acquire a new cpu for this partition from the hypervisor. * If drc_index is zero, look up an available index to use. * * @param drc_index * @returns pointer to cpu_info on success, NULL otherwise */ static int acquire_cpu(struct dr_node *cpu, struct dr_info *dr_info) { struct of_node *of_nodes; int rc; rc = acquire_drc(cpu->drc_index); if (rc) { say(DEBUG, "Could not acquire drc resources for %s\n", cpu->name); return rc; } of_nodes = configure_connector(cpu->drc_index); if (of_nodes == NULL) { say(ERROR, "Call to configure_connector failed for %s\n", cpu->name); release_drc(cpu->drc_index, CPU_DEV); return -1; } rc = add_device_tree_nodes(CPU_OFDT_BASE, of_nodes); free_of_node(of_nodes); if (rc) { say(ERROR, "Failure to add device tree nodes for %s\n", cpu->name); release_drc(cpu->drc_index, CPU_DEV); return rc; } update_cpu_node(cpu, NULL, dr_info); refresh_cache_info(dr_info); return 0; }
/** * acquire_hp_resource * * @param drc * @param of_path * @returns 0 on success, !0 otherwise */ static int acquire_hp_resource(struct dr_connector *drc, char *of_path) { struct of_node *new_nodes; int progress = ACQUIRE_HP_START; int state; int rc; state = dr_entity_sense(drc->index); if (state == PRESENT || state == NEED_POWER || state == PWR_ONLY) { rc = set_power(drc->powerdomain, POWER_ON); if (rc) { say(ERROR, "set power failed for 0x%x\n", drc->powerdomain); return progress; } progress = ACQUIRE_HP_SPL; if (state == PWR_ONLY) state = dr_entity_sense(drc->index); } if (state == PRESENT || state == NEED_POWER) { rc = rtas_set_indicator(ISOLATION_STATE, drc->index, UNISOLATE); if (rc) { say(ERROR, "set ind failed for 0x%x\n", drc->index); return progress; } progress = ACQUIRE_HP_UNISO; if (state == NEED_POWER) state = dr_entity_sense(drc->index); } if (state < 0) { say(ERROR, "invalid state %d\n", state); return progress; } if (state == PRESENT) { new_nodes = configure_connector(drc->index); if (new_nodes == NULL) return progress; progress = ACQUIRE_HP_CFGCONN; rc = add_device_tree_nodes(of_path, new_nodes); if (rc) { say(ERROR, "add nodes failed for 0x%x\n", drc->index); return progress; } } return 0; }
/** * acquire_phb * */ static int acquire_phb(char *drc_name, struct dr_node **phb) { struct dr_connector drc; struct of_node *of_nodes; char path[DR_PATH_MAX]; int rc; rc = get_drc_by_name(drc_name, &drc, path, OFDT_BASE); if (rc) { say(ERROR, "Could not find drc index for %s, unable to add the" "PHB.\n", drc_name); return rc; } rc = acquire_drc(drc.index); if (rc) return rc; of_nodes = configure_connector(drc.index); if (of_nodes == NULL) { release_drc(drc.index, PHB_DEV); return -1; } rc = add_device_tree_nodes(path, of_nodes); free_of_node(of_nodes); if (rc) { say(ERROR, "add_device_tree_nodes failed at %s\n", path); release_drc(drc.index, PHB_DEV); return -1; } /* Now that the node has been added to the device-tree, retrieve it. * This also acts as a sanity check that everything up to this * point has succeeded. */ *phb = get_node_by_name(drc_name, PHB_NODES); if (*phb == NULL) { say(ERROR, "Could not get find \"%s\"\n", drc_name); /* or should we call release_drc? but need device type */ release_drc(drc.index, PHB_DEV); return -1; } return 0; }
/** * add_new_node * * @param phandle * @param drcindex */ static void add_new_node(unsigned int phandle, unsigned int drcindex) { char *path; int rtas_rc; struct of_node *new_nodes;/* nodes returned from configure_connector */ new_nodes = configure_connector(drcindex); path = find_phandle(phandle); if (path == NULL) { say(DEBUG, "Cannot find pnahdle %x\n", phandle); return; } rtas_rc = add_device_tree_nodes(path, new_nodes); if (rtas_rc) say(DEBUG, "add_device_tree_nodes failed at %s\n", path); }
/** * add_work * * Prepares a PCI hot plug slot for adding an adapter, then * configures the adapter and any PCI adapters below into the * kernel's and /proc's Open Firmware device tree. * * If there are any errors from the RTAS routines, * the slot is powered off, isolated, and the LED is turned off. No * configuration is completed. * If the OF tree cannot be updated, the slot is powered * off, isolated, and the LED is turned off. * * @param opts * @param slot * @returns 0 on success, !0 on failure */ static int add_work(struct options *opts, struct dr_node *node) { int pow_state; /* Tells us if power was turned on when */ int iso_state; /* Tells us isolation state after */ int rc; struct of_node *new_nodes;/* nodes returned from configure_connector */ /* if we're continuing, set LED_ON and see if a card is really there. */ if (process_led(node, LED_ON)) return -1; say(DEBUG, "is calling card_present\n"); rc = card_present(opts, node, &pow_state, &iso_state); if (!rc) { say(ERROR, "No PCI card was detected in the specified " "PCI slot.\n"); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } if (!pow_state) { say(DEBUG, "is calling set_power(POWER_ON index 0x%x, " "power_domain 0x%x\n", node->drc_index, node->drc_power); rc = set_power(node->drc_power, POWER_ON); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else if (rc == SPEED_ERROR) say(ERROR, "%s", speed_error); else say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } } if (!iso_state) { say(DEBUG, "calling rtas_set_indicator(UNISOLATE index 0x%x)\n", node->drc_index); rc = rtas_set_indicator(ISOLATION_STATE, node->drc_index, UNISOLATE); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } } /* Now go get all the new nodes for this adapter. If * the return status requires a message, print it out * and exit, otherwise, add the nodes to the OF tree. */ new_nodes = configure_connector(node->drc_index); if (new_nodes == NULL) { rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } say(DEBUG, "Adding %s to %s\n", new_nodes->name, node->ofdt_path); rc = add_device_tree_nodes(node->ofdt_path, new_nodes); if (rc) { say(DEBUG, "add_device_tree_nodes failed at %s\n", node->ofdt_path); say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } return 0; }
/** * release_cpu * * Release a cpu back to the hypervisor, using the cpu's drc-index. * The cpu must have already been offlined. We remove the cpu from the * device tree only when the isolate and set_indicator have succeeded. * The caller must not use the value given for the cpu parameter after * this function has returned. * * @param cpu * @returns 0 on success, !0 otherwise */ int release_cpu(struct dr_node *cpu, struct dr_info *dr_info) { int release_file; int rc; release_file = open(CPU_RELEASE_FILE, O_WRONLY); if (release_file > 0) { /* DLPAR can be done in kernel */ char *path = cpu->ofdt_path + strlen(OFDT_BASE); int write_len = strlen(path); say(DEBUG, "Releasing cpu \"%s\"\n", path); rc = write(release_file, path, write_len); if (rc != write_len) say(ERROR, "Release failed! rc = %d\n", rc); else /* set rc to success */ rc = 0; close(release_file); } else { /* Must do DLPAR from user-space */ rc = offline_cpu(cpu); if (rc) { say(ERROR, "Could not offline cpu %s\n", cpu->drc_name); return rc; } rc = release_drc(cpu->drc_index, CPU_DEV); if (rc) { say(ERROR, "Could not release drc resources for %s\n", cpu->name); return rc; } rc = remove_device_tree_nodes(cpu->ofdt_path); if (rc) { struct of_node *of_nodes; say(ERROR, "Could not remove device tree nodes %s\n", cpu->name); of_nodes = configure_connector(cpu->drc_index); if (of_nodes == NULL) { say(ERROR, "Call to configure_connector failed " "for %s. The device tree\nmay contain " "invalid data for this cpu and a " "re-activation of the partition is " "needed to correct it.\n", cpu->name); } else { rc = add_device_tree_nodes(CPU_OFDT_BASE, of_nodes); free_of_node(of_nodes); } acquire_drc(cpu->drc_index); return rc; } release_caches(cpu, dr_info); } return rc; }
/** * add_device_tree_lmb * @brief Update the device tree for the lmb being added.. * * @param lmb lmb to acquire * @param lmb_list list of all lmbs * @returns 0 on success, !0 otherwise */ static int add_device_tree_lmb(struct dr_node *lmb, struct lmb_list_head *lmb_list) { int rc; lmb->lmb_of_node = configure_connector(lmb->drc_index); if (lmb->lmb_of_node == NULL) { release_drc(lmb->drc_index, MEM_DEV); return -1; } if (lmb_list->drconf_buf) { errno = 0; rc = update_drconf_node(lmb, lmb_list, ADD); if (errno == ENODEV) { /* Due to bug in pre 2.6.27 kernels, updating the * property in the device tree fails when the phandle * is processed as a signed int instead of unsigned * In this case we provide this little hack to allow * memory add to work on these kernels. */ say(DEBUG, "Assuming older kernel, trying to add " "node\n"); sprintf(lmb->ofdt_path, "%s/%s", OFDT_BASE, lmb->lmb_of_node->name); rc = add_device_tree_nodes(OFDT_BASE, lmb->lmb_of_node); } else { sprintf(lmb->ofdt_path, "%s/%s", OFDT_BASE, "/ibm,dynamic-reconfiguration-memory"); } } else { /* Add the new nodes to the device tree */ sprintf(lmb->ofdt_path, "%s/%s", OFDT_BASE, lmb->lmb_of_node->name); rc = add_device_tree_nodes(OFDT_BASE, lmb->lmb_of_node); } if (rc) return rc; if (! lmb_list->drconf_buf) { /* Find the physical address for this lmb. This is only * needed for non-drconf memory. The address for drconf * lmbs is correctly initialized when building the lmb list */ char *tmp = strrchr(lmb->ofdt_path, '@'); if (tmp == NULL) { say(DEBUG, "Could not determine physical address for " "%s\n", lmb->ofdt_path); remove_device_tree_nodes(lmb->ofdt_path); return -1; } lmb->lmb_address = strtoull(tmp + 1, NULL, 16); rc = get_lmb_size(lmb); if (rc) { remove_device_tree_nodes(lmb->ofdt_path); return rc; } } rc = get_mem_scns(lmb); if (rc) remove_device_tree_lmb(lmb, lmb_list); return rc; }