diff options
| -rw-r--r-- | arch/powerpc/include/asm/rtas.h | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/dlpar.c | 88 | 
2 files changed, 88 insertions, 1 deletions
| diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 065ffd1b2f8a..04406162fc5a 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -397,6 +397,7 @@ inline uint16_t pseries_errorlog_length(struct pseries_errorlog *sect)  #define PSERIES_HP_ELOG_RESOURCE_SLOT	3  #define PSERIES_HP_ELOG_RESOURCE_PHB	4  #define PSERIES_HP_ELOG_RESOURCE_PMEM   6 +#define PSERIES_HP_ELOG_RESOURCE_DT	7  #define PSERIES_HP_ELOG_ACTION_ADD	1  #define PSERIES_HP_ELOG_ACTION_REMOVE	2 diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 0777cccd6ac8..6573eb0e1c91 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -327,6 +327,87 @@ int dlpar_unisolate_drc(u32 drc_index)  	return 0;  } +static int changeset_detach_node_recursive(struct of_changeset *ocs, +					struct device_node *node) +{ +	struct device_node *child; +	int rc; + +	for_each_child_of_node(node, child) { +		rc = changeset_detach_node_recursive(ocs, child); +		if (rc) { +			of_node_put(child); +			return rc; +		} +	} + +	return of_changeset_detach_node(ocs, node); +} + +static int dlpar_hp_dt_remove(u32 drc_index) +{ +	struct device_node *np; +	struct of_changeset ocs; +	u32 index; +	int rc = 0; + +	/* +	 * Prune all nodes with a matching index. +	 */ +	of_changeset_init(&ocs); + +	for_each_node_with_property(np, "ibm,my-drc-index") { +		rc = of_property_read_u32(np, "ibm,my-drc-index", &index); +		if (rc) { +			pr_err("%s: %pOF: of_property_read_u32 %s: %d\n", +				__func__, np, "ibm,my-drc-index", rc); +			of_node_put(np); +			goto out; +		} + +		if (index == drc_index) { +			rc = changeset_detach_node_recursive(&ocs, np); +			if (rc) { +				of_node_put(np); +				goto out; +			} +		} +	} + +	rc = of_changeset_apply(&ocs); + +out: +	of_changeset_destroy(&ocs); +	return rc; +} + +static int dlpar_hp_dt(struct pseries_hp_errorlog *phpe) +{ +	u32 drc_index; +	int rc; + +	if (phpe->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX) +		return -EINVAL; + +	drc_index = be32_to_cpu(phpe->_drc_u.drc_index); + +	lock_device_hotplug(); + +	switch (phpe->action) { +	case PSERIES_HP_ELOG_ACTION_REMOVE: +		rc = dlpar_hp_dt_remove(drc_index); +		break; +	default: +		pr_err("Invalid action (%d) specified\n", phpe->action); +		rc = -EINVAL; +		break; +	} + +	unlock_device_hotplug(); + +	return rc; +} +  int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)  {  	int rc; @@ -341,6 +422,9 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)  	case PSERIES_HP_ELOG_RESOURCE_PMEM:  		rc = dlpar_hp_pmem(hp_elog);  		break; +	case PSERIES_HP_ELOG_RESOURCE_DT: +		rc = dlpar_hp_dt(hp_elog); +		break;  	default:  		pr_warn_ratelimited("Invalid resource (%d) specified\n", @@ -393,6 +477,8 @@ static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog)  		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;  	} else if (sysfs_streq(arg, "cpu")) {  		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU; +	} else if (sysfs_streq(arg, "dt")) { +		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_DT;  	} else {  		pr_err("Invalid resource specified.\n");  		return -EINVAL; @@ -534,7 +620,7 @@ dlpar_store_out:  static ssize_t dlpar_show(const struct class *class, const struct class_attribute *attr,  			  char *buf)  { -	return sprintf(buf, "%s\n", "memory,cpu"); +	return sprintf(buf, "%s\n", "memory,cpu,dt");  }  static CLASS_ATTR_RW(dlpar); | 
