/** * 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; }
/** * add_lmbs * * Attempt to acquire and online the given number of LMBs. * This function calls itself recursively to simplify recovery * actions in case of an error. This is intended only for the case * where the user does not specify a drc-name. * * @param nr_lmbs number of lmbs to add * @param lmb_list list of lmbs on the partition * @returns 0 on success, !0 otherwise */ static int add_lmbs(struct lmb_list_head *lmb_list) { int rc = 0; struct dr_node *lmb_head = lmb_list->lmbs; struct dr_node *lmb; lmb_list->lmbs_modified = 0; while (lmb_list->lmbs_modified < usr_drc_count) { if (drmgr_timed_out()) break; lmb = get_available_lmb(lmb_head); if (lmb == NULL) return -1; /* Iterate only over the remaining LMBs */ lmb_head = lmb->next; rc = acquire_drc(lmb->drc_index); if (rc) { report_unknown_error(__FILE__, __LINE__); lmb->unusable = 1; continue; } rc = add_device_tree_lmb(lmb, lmb_list); if (rc) { report_unknown_error(__FILE__, __LINE__); release_drc(lmb->drc_index, MEM_DEV); lmb->unusable = 1; continue; } rc = set_lmb_state(lmb, ONLINE); if (rc) { report_unknown_error(__FILE__, __LINE__); remove_device_tree_lmb(lmb, lmb_list); release_drc(lmb->drc_index, MEM_DEV); lmb->unusable = 1; continue; } lmb_list->lmbs_modified++; } return rc; }
/** * 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; }
/** * 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; }