|
@@ -116,6 +116,155 @@ static struct property *dlpar_clone_drconf_property(struct device_node *dn)
|
|
|
return new_prop;
|
|
|
}
|
|
|
|
|
|
+static void dlpar_update_drconf_property(struct device_node *dn,
|
|
|
+ struct property *prop)
|
|
|
+{
|
|
|
+ struct of_drconf_cell *lmbs;
|
|
|
+ u32 num_lmbs, *p;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /* Convert the property back to BE */
|
|
|
+ p = prop->value;
|
|
|
+ num_lmbs = *p;
|
|
|
+ *p = cpu_to_be32(*p);
|
|
|
+ p++;
|
|
|
+
|
|
|
+ lmbs = (struct of_drconf_cell *)p;
|
|
|
+ for (i = 0; i < num_lmbs; i++) {
|
|
|
+ lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr);
|
|
|
+ lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index);
|
|
|
+ lmbs[i].flags = cpu_to_be32(lmbs[i].flags);
|
|
|
+ }
|
|
|
+
|
|
|
+ rtas_hp_event = true;
|
|
|
+ of_update_property(dn, prop);
|
|
|
+ rtas_hp_event = false;
|
|
|
+}
|
|
|
+
|
|
|
+static int dlpar_update_device_tree_lmb(struct of_drconf_cell *lmb)
|
|
|
+{
|
|
|
+ struct device_node *dn;
|
|
|
+ struct property *prop;
|
|
|
+ struct of_drconf_cell *lmbs;
|
|
|
+ u32 *p, num_lmbs;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
|
|
|
+ if (!dn)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ prop = dlpar_clone_drconf_property(dn);
|
|
|
+ if (!prop) {
|
|
|
+ of_node_put(dn);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ p = prop->value;
|
|
|
+ num_lmbs = *p++;
|
|
|
+ lmbs = (struct of_drconf_cell *)p;
|
|
|
+
|
|
|
+ for (i = 0; i < num_lmbs; i++) {
|
|
|
+ if (lmbs[i].drc_index == lmb->drc_index) {
|
|
|
+ lmbs[i].flags = lmb->flags;
|
|
|
+ lmbs[i].aa_index = lmb->aa_index;
|
|
|
+
|
|
|
+ dlpar_update_drconf_property(dn, prop);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ of_node_put(dn);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+static int dlpar_add_device_tree_lmb(struct of_drconf_cell *lmb)
|
|
|
+{
|
|
|
+ int aa_index;
|
|
|
+
|
|
|
+ lmb->flags |= DRCONF_MEM_ASSIGNED;
|
|
|
+
|
|
|
+ aa_index = lookup_lmb_associativity_index(lmb);
|
|
|
+ if (aa_index < 0) {
|
|
|
+ pr_err("Couldn't find associativity index for drc index %x\n",
|
|
|
+ lmb->drc_index);
|
|
|
+ return aa_index;
|
|
|
+ }
|
|
|
+
|
|
|
+ lmb->aa_index = aa_index;
|
|
|
+ return dlpar_update_device_tree_lmb(lmb);
|
|
|
+}
|
|
|
+
|
|
|
+static int dlpar_remove_device_tree_lmb(struct of_drconf_cell *lmb)
|
|
|
+{
|
|
|
+ lmb->flags &= ~DRCONF_MEM_ASSIGNED;
|
|
|
+ lmb->aa_index = 0xffffffff;
|
|
|
+ return dlpar_update_device_tree_lmb(lmb);
|
|
|
+}
|
|
|
+
|
|
|
static struct memory_block *lmb_to_memblock(struct of_drconf_cell *lmb)
|
|
|
{
|
|
|
unsigned long section_nr;
|
|
@@ -243,8 +392,8 @@ static int dlpar_remove_lmb(struct of_drconf_cell *lmb)
|
|
|
memblock_remove(lmb->base_addr, block_sz);
|
|
|
|
|
|
dlpar_release_drc(lmb->drc_index);
|
|
|
+ dlpar_remove_device_tree_lmb(lmb);
|
|
|
|
|
|
- lmb->flags &= ~DRCONF_MEM_ASSIGNED;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -435,9 +584,19 @@ static int dlpar_add_lmb(struct of_drconf_cell *lmb)
|
|
|
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)
|
|
|
+ if (rc) {
|
|
|
+ dlpar_remove_device_tree_lmb(lmb);
|
|
|
dlpar_release_drc(lmb->drc_index);
|
|
|
+ }
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
@@ -542,31 +701,6 @@ static int dlpar_memory_add_by_index(u32 drc_index, struct property *prop)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static void dlpar_update_drconf_property(struct device_node *dn,
|
|
|
- struct property *prop)
|
|
|
-{
|
|
|
- struct of_drconf_cell *lmbs;
|
|
|
- u32 num_lmbs, *p;
|
|
|
- int i;
|
|
|
-
|
|
|
- /* Convert the property back to BE */
|
|
|
- p = prop->value;
|
|
|
- num_lmbs = *p;
|
|
|
- *p = cpu_to_be32(*p);
|
|
|
- p++;
|
|
|
-
|
|
|
- lmbs = (struct of_drconf_cell *)p;
|
|
|
- for (i = 0; i < num_lmbs; i++) {
|
|
|
- lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr);
|
|
|
- lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index);
|
|
|
- lmbs[i].flags = cpu_to_be32(lmbs[i].flags);
|
|
|
- }
|
|
|
-
|
|
|
- rtas_hp_event = true;
|
|
|
- of_update_property(dn, prop);
|
|
|
- rtas_hp_event = false;
|
|
|
-}
|
|
|
-
|
|
|
int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
|
|
|
{
|
|
|
struct device_node *dn;
|
|
@@ -614,10 +748,7 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (rc)
|
|
|
- dlpar_free_drconf_property(prop);
|
|
|
- else
|
|
|
- dlpar_update_drconf_property(dn, prop);
|
|
|
+ dlpar_free_drconf_property(prop);
|
|
|
|
|
|
dlpar_memory_out:
|
|
|
of_node_put(dn);
|