void dlpar_free_cc_nodes(struct device_node *dn) { if (dn->child) dlpar_free_cc_nodes(dn->child); if (dn->sibling) dlpar_free_cc_nodes(dn->sibling); dlpar_free_one_cc_node(dn); }
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 u32 lookup_lmb_associativity_index(struct of_drconf_cell *lmb) { struct device_node *parent, *lmb_node, *dr_node; struct property *ala_prop; const u32 *lmb_assoc; u32 aa_index; parent = of_find_node_by_path("/"); if (!parent) return -ENODEV; lmb_node = dlpar_configure_connector(cpu_to_be32(lmb->drc_index), parent); of_node_put(parent); if (!lmb_node) return -EINVAL; lmb_assoc = of_get_property(lmb_node, "ibm,associativity", NULL); if (!lmb_assoc) { dlpar_free_cc_nodes(lmb_node); return -ENODEV; } dr_node = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); if (!dr_node) { dlpar_free_cc_nodes(lmb_node); return -ENODEV; } ala_prop = of_find_property(dr_node, "ibm,associativity-lookup-arrays", NULL); if (!ala_prop) { of_node_put(dr_node); dlpar_free_cc_nodes(lmb_node); return -ENODEV; } aa_index = find_aa_index(dr_node, ala_prop, lmb_assoc); dlpar_free_cc_nodes(lmb_node); return aa_index; }
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 add_dt_node(u32 parent_phandle, u32 drc_index) { struct device_node *dn; struct device_node *parent_dn; int rc; dn = dlpar_configure_connector(drc_index); if (!dn) return -ENOENT; parent_dn = of_find_node_by_phandle(parent_phandle); if (!parent_dn) { dlpar_free_cc_nodes(dn); return -ENOENT; } dn->parent = parent_dn; rc = dlpar_attach_node(dn); if (rc) dlpar_free_cc_nodes(dn); of_node_put(parent_dn); return rc; }
static int add_dt_node(__be32 parent_phandle, __be32 drc_index) { struct device_node *dn; struct device_node *parent_dn; int rc; parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle)); if (!parent_dn) return -ENOENT; dn = dlpar_configure_connector(drc_index, parent_dn); if (!dn) return -ENOENT; rc = dlpar_attach_node(dn); if (rc) dlpar_free_cc_nodes(dn); of_node_put(parent_dn); return rc; }
struct device_node *dlpar_configure_connector(u32 drc_index) { struct device_node *dn; struct device_node *first_dn = NULL; struct device_node *last_dn = NULL; struct property *property; struct property *last_property = NULL; struct cc_workarea *ccwa; char *data_buf; int cc_token; int rc = -1; cc_token = rtas_token("ibm,configure-connector"); if (cc_token == RTAS_UNKNOWN_SERVICE) return NULL; data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); if (!data_buf) return NULL; ccwa = (struct cc_workarea *)&data_buf[0]; ccwa->drc_index = drc_index; ccwa->zero = 0; do { /* Since we release the rtas_data_buf lock between configure * connector calls we want to re-populate the rtas_data_buffer * with the contents of the previous call. */ spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE); rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); switch (rc) { case COMPLETE: break; case NEXT_SIBLING: dn = dlpar_parse_cc_node(ccwa); if (!dn) goto cc_error; dn->parent = last_dn->parent; last_dn->sibling = dn; last_dn = dn; break; case NEXT_CHILD: dn = dlpar_parse_cc_node(ccwa); if (!dn) goto cc_error; if (!first_dn) first_dn = dn; else { dn->parent = last_dn; if (last_dn) last_dn->child = dn; } last_dn = dn; break; case NEXT_PROPERTY: property = dlpar_parse_cc_property(ccwa); if (!property) goto cc_error; if (!last_dn->properties) last_dn->properties = property; else last_property->next = property; last_property = property; break; case PREV_PARENT: last_dn = last_dn->parent; break; case CALL_AGAIN: break; case MORE_MEMORY: case ERR_CFG_USE: default: printk(KERN_ERR "Unexpected Error (%d) " "returned from configure-connector\n", rc); goto cc_error; } } while (rc); cc_error: kfree(data_buf); if (rc) { if (first_dn) dlpar_free_cc_nodes(first_dn); return NULL; } return first_dn; }
struct device_node *dlpar_configure_connector(u32 drc_index) { struct device_node *dn; struct device_node *first_dn = NULL; struct device_node *last_dn = NULL; struct property *property; struct property *last_property = NULL; struct cc_workarea *ccwa; int cc_token; int rc; cc_token = rtas_token("ibm,configure-connector"); if (cc_token == RTAS_UNKNOWN_SERVICE) return NULL; spin_lock(&rtas_data_buf_lock); ccwa = (struct cc_workarea *)&rtas_data_buf[0]; ccwa->drc_index = drc_index; ccwa->zero = 0; rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); while (rc) { switch (rc) { case NEXT_SIBLING: dn = dlpar_parse_cc_node(ccwa); if (!dn) goto cc_error; dn->parent = last_dn->parent; last_dn->sibling = dn; last_dn = dn; break; case NEXT_CHILD: dn = dlpar_parse_cc_node(ccwa); if (!dn) goto cc_error; if (!first_dn) first_dn = dn; else { dn->parent = last_dn; if (last_dn) last_dn->child = dn; } last_dn = dn; break; case NEXT_PROPERTY: property = dlpar_parse_cc_property(ccwa); if (!property) goto cc_error; if (!last_dn->properties) last_dn->properties = property; else last_property->next = property; last_property = property; break; case PREV_PARENT: last_dn = last_dn->parent; break; case CALL_AGAIN: break; case MORE_MEMORY: case ERR_CFG_USE: default: printk(KERN_ERR "Unexpected Error (%d) " "returned from configure-connector\n", rc); goto cc_error; } rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); } spin_unlock(&rtas_data_buf_lock); return first_dn; cc_error: if (first_dn) dlpar_free_cc_nodes(first_dn); spin_unlock(&rtas_data_buf_lock); return NULL; }
static u32 lookup_lmb_associativity_index(struct of_drconf_cell *lmb) { struct device_node *parent, *lmb_node, *dr_node; const u32 *lmb_assoc; const u32 *assoc_arrays; u32 aa_index; int aa_arrays, aa_array_entries, aa_array_sz; int i; parent = of_find_node_by_path("/"); if (!parent) return -ENODEV; lmb_node = dlpar_configure_connector(cpu_to_be32(lmb->drc_index), parent); of_node_put(parent); if (!lmb_node) return -EINVAL; lmb_assoc = of_get_property(lmb_node, "ibm,associativity", NULL); if (!lmb_assoc) { dlpar_free_cc_nodes(lmb_node); return -ENODEV; } dr_node = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); if (!dr_node) { dlpar_free_cc_nodes(lmb_node); return -ENODEV; } assoc_arrays = of_get_property(dr_node, "ibm,associativity-lookup-arrays", NULL); of_node_put(dr_node); if (!assoc_arrays) { dlpar_free_cc_nodes(lmb_node); return -ENODEV; } /* The ibm,associativity-lookup-arrays property is defined to be * a 32-bit value specifying the number of associativity arrays * followed by a 32-bitvalue specifying the number of entries per * array, followed by the associativity arrays. */ aa_arrays = be32_to_cpu(assoc_arrays[0]); aa_array_entries = be32_to_cpu(assoc_arrays[1]); aa_array_sz = aa_array_entries * sizeof(u32); aa_index = -1; for (i = 0; i < aa_arrays; i++) { int indx = (i * aa_array_entries) + 2; if (memcmp(&assoc_arrays[indx], &lmb_assoc[1], aa_array_sz)) continue; aa_index = i; break; } dlpar_free_cc_nodes(lmb_node); return aa_index; }