aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/pseries/mobility.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries/mobility.c')
-rw-r--r--arch/powerpc/platforms/pseries/mobility.c95
1 files changed, 49 insertions, 46 deletions
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index 3e7f651e50a..bde7ebad394 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/smp.h>
+#include <linux/stat.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/delay.h>
@@ -27,7 +28,7 @@ struct update_props_workarea {
u32 state;
u64 reserved;
u32 nprops;
-};
+} __packed;
#define NODE_ACTION_MASK 0xff000000
#define NODE_COUNT_MASK 0x00ffffff
@@ -36,14 +37,16 @@ struct update_props_workarea {
#define UPDATE_DT_NODE 0x02000000
#define ADD_DT_NODE 0x03000000
-static int mobility_rtas_call(int token, char *buf)
+#define MIGRATION_SCOPE (1)
+
+static int mobility_rtas_call(int token, char *buf, s32 scope)
{
int rc;
spin_lock(&rtas_data_buf_lock);
memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
- rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, 1);
+ rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
spin_unlock(&rtas_data_buf_lock);
@@ -59,6 +62,7 @@ static int delete_dt_node(u32 phandle)
return -ENOENT;
dlpar_detach_node(dn);
+ of_node_put(dn);
return 0;
}
@@ -66,7 +70,6 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
const char *name, u32 vd, char *value)
{
struct property *new_prop = *prop;
- struct property *old_prop;
int more = 0;
/* A negative 'vd' value indicates that only part of the new property
@@ -116,27 +119,23 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
}
if (!more) {
- old_prop = of_find_property(dn, new_prop->name, NULL);
- if (old_prop)
- prom_update_property(dn, new_prop, old_prop);
- else
- prom_add_property(dn, new_prop);
-
- new_prop = NULL;
+ of_update_property(dn, new_prop);
+ *prop = NULL;
}
return 0;
}
-static int update_dt_node(u32 phandle)
+static int update_dt_node(u32 phandle, s32 scope)
{
struct update_props_workarea *upwa;
struct device_node *dn;
struct property *prop = NULL;
- int i, rc;
+ int i, rc, rtas_rc;
char *prop_data;
char *rtas_buf;
int update_properties_token;
+ u32 vd;
update_properties_token = rtas_token("ibm,update-properties");
if (update_properties_token == RTAS_UNKNOWN_SERVICE)
@@ -156,19 +155,32 @@ static int update_dt_node(u32 phandle)
upwa->phandle = phandle;
do {
- rc = mobility_rtas_call(update_properties_token, rtas_buf);
- if (rc < 0)
+ rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf,
+ scope);
+ if (rtas_rc < 0)
break;
prop_data = rtas_buf + sizeof(*upwa);
+ /* On the first call to ibm,update-properties for a node the
+ * the first property value descriptor contains an empty
+ * property name, the property value length encoded as u32,
+ * and the property value is the node path being updated.
+ */
+ if (*prop_data == 0) {
+ prop_data++;
+ vd = *(u32 *)prop_data;
+ prop_data += vd + sizeof(vd);
+ upwa->nprops--;
+ }
+
for (i = 0; i < upwa->nprops; i++) {
char *prop_name;
- u32 vd;
- prop_name = prop_data + 1;
+ prop_name = prop_data;
prop_data += strlen(prop_name) + 1;
- vd = *prop_data++;
+ vd = *(u32 *)prop_data;
+ prop_data += sizeof(vd);
switch (vd) {
case 0x00000000:
@@ -177,7 +189,7 @@ static int update_dt_node(u32 phandle)
case 0x80000000:
prop = of_find_property(dn, prop_name, NULL);
- prom_remove_property(dn, prop);
+ of_remove_property(dn, prop);
prop = NULL;
break;
@@ -192,7 +204,7 @@ static int update_dt_node(u32 phandle)
prop_data += vd;
}
}
- } while (rc == 1);
+ } while (rtas_rc == 1);
of_node_put(dn);
kfree(rtas_buf);
@@ -205,17 +217,14 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
struct device_node *parent_dn;
int rc;
- dn = dlpar_configure_connector(drc_index);
- if (!dn)
+ parent_dn = of_find_node_by_phandle(parent_phandle);
+ if (!parent_dn)
return -ENOENT;
- parent_dn = of_find_node_by_phandle(parent_phandle);
- if (!parent_dn) {
- dlpar_free_cc_nodes(dn);
+ dn = dlpar_configure_connector(drc_index, parent_dn);
+ if (!dn)
return -ENOENT;
- }
- dn->parent = parent_dn;
rc = dlpar_attach_node(dn);
if (rc)
dlpar_free_cc_nodes(dn);
@@ -224,7 +233,7 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
return rc;
}
-static int pseries_devicetree_update(void)
+int pseries_devicetree_update(s32 scope)
{
char *rtas_buf;
u32 *data;
@@ -240,7 +249,7 @@ static int pseries_devicetree_update(void)
return -ENOMEM;
do {
- rc = mobility_rtas_call(update_nodes_token, rtas_buf);
+ rc = mobility_rtas_call(update_nodes_token, rtas_buf, scope);
if (rc && rc != 1)
break;
@@ -261,7 +270,7 @@ static int pseries_devicetree_update(void)
delete_dt_node(phandle);
break;
case UPDATE_DT_NODE:
- update_dt_node(phandle);
+ update_dt_node(phandle, scope);
break;
case ADD_DT_NODE:
drc_index = *data++;
@@ -281,13 +290,6 @@ void post_mobility_fixup(void)
int rc;
int activate_fw_token;
- rc = pseries_devicetree_update();
- if (rc) {
- printk(KERN_ERR "Initial post-mobility device tree update "
- "failed: %d\n", rc);
- return;
- }
-
activate_fw_token = rtas_token("ibm,activate-firmware");
if (activate_fw_token == RTAS_UNKNOWN_SERVICE) {
printk(KERN_ERR "Could not make post-mobility "
@@ -295,16 +297,17 @@ void post_mobility_fixup(void)
return;
}
- rc = rtas_call(activate_fw_token, 0, 1, NULL);
- if (!rc) {
- rc = pseries_devicetree_update();
- if (rc)
- printk(KERN_ERR "Secondary post-mobility device tree "
- "update failed: %d\n", rc);
- } else {
+ do {
+ rc = rtas_call(activate_fw_token, 0, 1, NULL);
+ } while (rtas_busy_delay(rc));
+
+ if (rc)
printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
- return;
- }
+
+ rc = pseries_devicetree_update(MIGRATION_SCOPE);
+ if (rc)
+ printk(KERN_ERR "Post-mobility device tree update "
+ "failed: %d\n", rc);
return;
}