static int dlpar_add_lmb(struct of_drconf_cell *lmb) { int rc; if (lmb->flags & DRCONF_MEM_ASSIGNED) return -EINVAL; rc = dlpar_acquire_drc(lmb->drc_index); if (rc) return rc; rc = dlpar_add_device_tree_lmb(lmb); if (rc) { pr_err("Couldn't update device tree for drc index %x\n", lmb->drc_index); dlpar_release_drc(lmb->drc_index); return rc; } rc = dlpar_add_lmb_memory(lmb); if (rc) { dlpar_remove_device_tree_lmb(lmb); dlpar_release_drc(lmb->drc_index); } return rc; }
static ssize_t dlpar_cpu_probe(const char *buf, size_t count) { struct device_node *dn; unsigned long drc_index; char *cpu_name; int rc; cpu_hotplug_driver_lock(); rc = strict_strtoul(buf, 0, &drc_index); if (rc) { rc = -EINVAL; goto out; } dn = dlpar_configure_connector(drc_index); if (!dn) { rc = -EINVAL; goto out; } /* configure-connector reports cpus as living in the base * directory of the device tree. CPUs actually live in the * cpus directory so we need to fixup the full_name. */ cpu_name = kzalloc(strlen(dn->full_name) + strlen("/cpus") + 1, GFP_KERNEL); if (!cpu_name) { dlpar_free_cc_nodes(dn); rc = -ENOMEM; goto out; } sprintf(cpu_name, "/cpus%s", dn->full_name); kfree(dn->full_name); dn->full_name = cpu_name; rc = dlpar_acquire_drc(drc_index); if (rc) { dlpar_free_cc_nodes(dn); rc = -EINVAL; goto out; } rc = dlpar_attach_node(dn); if (rc) { dlpar_release_drc(drc_index); dlpar_free_cc_nodes(dn); } rc = dlpar_online_cpu(dn); out: cpu_hotplug_driver_unlock(); return rc ? rc : count; }
static ssize_t dlpar_cpu_probe(const char *buf, size_t count) { struct device_node *dn, *parent; unsigned long drc_index; int rc; cpu_hotplug_driver_lock(); rc = strict_strtoul(buf, 0, &drc_index); if (rc) { rc = -EINVAL; goto out; } parent = of_find_node_by_path("/cpus"); if (!parent) { rc = -ENODEV; goto out; } dn = dlpar_configure_connector(drc_index, parent); if (!dn) { rc = -EINVAL; goto out; } of_node_put(parent); rc = dlpar_acquire_drc(drc_index); if (rc) { dlpar_free_cc_nodes(dn); rc = -EINVAL; goto out; } rc = dlpar_attach_node(dn); if (rc) { dlpar_release_drc(drc_index); dlpar_free_cc_nodes(dn); goto out; } rc = dlpar_online_cpu(dn); out: cpu_hotplug_driver_unlock(); return rc ? rc : count; }
static ssize_t dlpar_cpu_release(const char *buf, size_t count) { struct device_node *dn; const u32 *drc_index; int rc; dn = of_find_node_by_path(buf); if (!dn) return -EINVAL; drc_index = of_get_property(dn, "ibm,my-drc-index", NULL); if (!drc_index) { of_node_put(dn); return -EINVAL; } cpu_hotplug_driver_lock(); rc = dlpar_offline_cpu(dn); if (rc) { of_node_put(dn); rc = -EINVAL; goto out; } rc = dlpar_release_drc(*drc_index); if (rc) { of_node_put(dn); goto out; } rc = dlpar_detach_node(dn); if (rc) { dlpar_acquire_drc(*drc_index); goto out; } of_node_put(dn); out: cpu_hotplug_driver_unlock(); return rc ? rc : count; }
static ssize_t dlpar_cpu_probe(const char *buf, size_t count) { struct device_node *dn, *parent; u32 drc_index; int rc; rc = kstrtou32(buf, 0, &drc_index); if (rc) return -EINVAL; parent = of_find_node_by_path("/cpus"); if (!parent) return -ENODEV; dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent); if (!dn) return -EINVAL; of_node_put(parent); rc = dlpar_acquire_drc(drc_index); if (rc) { dlpar_free_cc_nodes(dn); return -EINVAL; } rc = dlpar_attach_node(dn); if (rc) { dlpar_release_drc(drc_index); dlpar_free_cc_nodes(dn); return rc; } rc = dlpar_online_cpu(dn); if (rc) return rc; return count; }
static int dlpar_memory_add_by_index(u32 drc_index, struct property *prop) { struct of_drconf_cell *lmbs; u32 num_lmbs, *p; int i, lmb_found; int rc; pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index); p = prop->value; num_lmbs = *p++; lmbs = (struct of_drconf_cell *)p; lmb_found = 0; for (i = 0; i < num_lmbs; i++) { if (lmbs[i].drc_index == drc_index) { lmb_found = 1; rc = dlpar_acquire_drc(lmbs[i].drc_index); if (!rc) { rc = dlpar_add_lmb(&lmbs[i]); if (rc) dlpar_release_drc(lmbs[i].drc_index); } break; } } if (!lmb_found) rc = -EINVAL; if (rc) pr_info("Failed to hot-add memory, drc index %x\n", drc_index); else pr_info("Memory at %llx (drc index %x) was hot-added\n", lmbs[i].base_addr, drc_index); return rc; }
static ssize_t dlpar_cpu_release(const char *buf, size_t count) { struct device_node *dn; u32 drc_index; int rc; dn = of_find_node_by_path(buf); if (!dn) return -EINVAL; rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index); if (rc) { of_node_put(dn); return -EINVAL; } rc = dlpar_offline_cpu(dn); if (rc) { of_node_put(dn); return -EINVAL; } rc = dlpar_release_drc(drc_index); if (rc) { of_node_put(dn); return rc; } rc = dlpar_detach_node(dn); if (rc) { dlpar_acquire_drc(drc_index); return rc; } of_node_put(dn); return count; }
static int dlpar_add_lmb(struct of_drconf_cell *lmb) { unsigned long block_sz; int nid, rc; if (lmb->flags & DRCONF_MEM_ASSIGNED) return -EINVAL; rc = dlpar_acquire_drc(lmb->drc_index); if (rc) return rc; rc = dlpar_add_device_tree_lmb(lmb); if (rc) { pr_err("Couldn't update device tree for drc index %x\n", lmb->drc_index); dlpar_release_drc(lmb->drc_index); return rc; } block_sz = memory_block_size_bytes(); /* Find the node id for this address */ nid = memory_add_physaddr_to_nid(lmb->base_addr); /* Add the memory */ rc = add_memory(nid, lmb->base_addr, block_sz); if (rc) { dlpar_remove_device_tree_lmb(lmb); dlpar_release_drc(lmb->drc_index); } else { lmb->flags |= DRCONF_MEM_ASSIGNED; } return rc; }
static int dlpar_memory_add_by_ic(u32 lmbs_to_add, u32 drc_index, struct property *prop) { struct of_drconf_cell *lmbs; u32 num_lmbs, *p; int i, rc, start_lmb_found; int lmbs_available = 0, start_index = 0, end_index; pr_info("Attempting to hot-add %u LMB(s) at index %x\n", lmbs_to_add, drc_index); if (lmbs_to_add == 0) return -EINVAL; p = prop->value; num_lmbs = *p++; lmbs = (struct of_drconf_cell *)p; start_lmb_found = 0; /* Navigate to drc_index */ while (start_index < num_lmbs) { if (lmbs[start_index].drc_index == drc_index) { start_lmb_found = 1; break; } start_index++; } if (!start_lmb_found) return -EINVAL; end_index = start_index + lmbs_to_add; /* Validate that the LMBs in this range are not reserved */ for (i = start_index; i < end_index; i++) { if (lmbs[i].flags & DRCONF_MEM_RESERVED) break; lmbs_available++; } if (lmbs_available < lmbs_to_add) return -EINVAL; for (i = start_index; i < end_index; i++) { if (lmbs[i].flags & DRCONF_MEM_ASSIGNED) continue; rc = dlpar_acquire_drc(lmbs[i].drc_index); if (rc) break; rc = dlpar_add_lmb(&lmbs[i]); if (rc) { dlpar_release_drc(lmbs[i].drc_index); break; } lmbs[i].reserved = 1; } if (rc) { pr_err("Memory indexed-count-add failed, removing any added LMBs\n"); for (i = start_index; i < end_index; i++) { if (!lmbs[i].reserved) continue; rc = dlpar_remove_lmb(&lmbs[i]); if (rc) pr_err("Failed to remove LMB, drc index %x\n", be32_to_cpu(lmbs[i].drc_index)); else dlpar_release_drc(lmbs[i].drc_index); } rc = -EINVAL; } else { for (i = start_index; i < end_index; i++) { if (!lmbs[i].reserved) continue; pr_info("Memory at %llx (drc index %x) was hot-added\n", lmbs[i].base_addr, lmbs[i].drc_index); lmbs[i].reserved = 0; } } return rc; }
static int dlpar_memory_add_by_count(u32 lmbs_to_add, struct property *prop) { struct of_drconf_cell *lmbs; u32 num_lmbs, *p; int lmbs_available = 0; int lmbs_added = 0; int i, rc; pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add); if (lmbs_to_add == 0) return -EINVAL; p = prop->value; num_lmbs = *p++; lmbs = (struct of_drconf_cell *)p; /* Validate that there are enough LMBs to satisfy the request */ for (i = 0; i < num_lmbs; i++) { if (!(lmbs[i].flags & DRCONF_MEM_ASSIGNED)) lmbs_available++; } if (lmbs_available < lmbs_to_add) return -EINVAL; for (i = 0; i < num_lmbs && lmbs_to_add != lmbs_added; i++) { rc = dlpar_acquire_drc(lmbs[i].drc_index); if (rc) continue; rc = dlpar_add_lmb(&lmbs[i]); if (rc) { dlpar_release_drc(lmbs[i].drc_index); continue; } lmbs_added++; /* Mark this lmb so we can remove it later if all of the * requested LMBs cannot be added. */ lmbs[i].reserved = 1; } if (lmbs_added != lmbs_to_add) { pr_err("Memory hot-add failed, removing any added LMBs\n"); for (i = 0; i < num_lmbs; i++) { if (!lmbs[i].reserved) continue; rc = dlpar_remove_lmb(&lmbs[i]); if (rc) pr_err("Failed to remove LMB, drc index %x\n", be32_to_cpu(lmbs[i].drc_index)); else dlpar_release_drc(lmbs[i].drc_index); } rc = -EINVAL; } else { for (i = 0; i < num_lmbs; i++) { if (!lmbs[i].reserved) continue; pr_info("Memory at %llx (drc index %x) was hot-added\n", lmbs[i].base_addr, lmbs[i].drc_index); lmbs[i].reserved = 0; } } return rc; }