diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/mobility.c')
| -rw-r--r-- | arch/powerpc/platforms/pseries/mobility.c | 95 | 
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;  }  | 
