diff mbox series

[RFC,v4,3/4] hotplug/drcinfo: Fix hot-add CPU issues

Message ID 6f2c522c-8c57-9416-3860-10a5270da059@linux.vnet.ibm.com (mailing list archive)
State RFC
Headers show
Series powerpc/drcinfo: Fix bugs 'ibm,drc-info' property | expand

Commit Message

Michael Bringmann May 22, 2018, 4:37 p.m. UTC
This patch applies a common parse function for the ibm,drc-info
property that can be modified by a callback function to the
hot-add CPU code.  Candidate code is replaced by a call to the
parser including a pointer to a local context-specific functions,
and local data.

In addition, a bug in the release of the previous patch set may
break things in some of the CPU DLPAR operations.  For instance,
when attempting to hot-add a new CPU or set of CPUs, the original
patch failed to always properly calculate the available resources,
and aborted the operation.

Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmwar
e feature" -- end of patch series applied to powerpc next)
---
Changes in V4:
  -- Update code to account for latest kernel checkins.
  -- Rebased to 4.17-rc5 kernel
  -- Compress some more code
---
 arch/powerpc/platforms/pseries/hotplug-cpu.c    |  118 +++++++++++++++++------
 arch/powerpc/platforms/pseries/pseries_energy.c |  107 +++++++++++----------
 2 files changed, 141 insertions(+), 84 deletions(-)

Comments

Nathan Fontenot May 22, 2018, 9:31 p.m. UTC | #1
On 05/22/2018 11:37 AM, Michael Bringmann wrote:
> This patch applies a common parse function for the ibm,drc-info
> property that can be modified by a callback function to the
> hot-add CPU code.  Candidate code is replaced by a call to the
> parser including a pointer to a local context-specific functions,
> and local data.
> 
> In addition, a bug in the release of the previous patch set may
> break things in some of the CPU DLPAR operations.  For instance,
> when attempting to hot-add a new CPU or set of CPUs, the original
> patch failed to always properly calculate the available resources,
> and aborted the operation.
> 
> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
> Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmwar
> e feature" -- end of patch series applied to powerpc next)
> ---
> Changes in V4:
>   -- Update code to account for latest kernel checkins.
>   -- Rebased to 4.17-rc5 kernel
>   -- Compress some more code
> ---
>  arch/powerpc/platforms/pseries/hotplug-cpu.c    |  118 +++++++++++++++++------
>  arch/powerpc/platforms/pseries/pseries_energy.c |  107 +++++++++++----------
>  2 files changed, 141 insertions(+), 84 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> index 6ef77ca..ceacad9 100644
> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> @@ -411,27 +411,63 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
>  	return found;
>  }
> 
> -static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
> +static bool check_cpu_drc_index(struct device_node *parent,
> +				int (*cb)(struct of_drc_info *drc,
> +					void *data, void *not_used,
> +					int *ret_code),
> +				void *cdata)
>  {
>  	bool found = false;
> -	int rc, index;
> 
> -	index = 0;
> -	while (!found) {
> -		u32 drc;
> +	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
> +		if (drc_info_parser(parent, cb, "CPU", cdata))
> +			found = true;
> +	} else {
> +		int index = 0;
> 
> -		rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
> -						index++, &drc);
> -		if (rc)
> -			break;
> +		while (!found) {
> +			u32 drc;
> 
> -		if (drc == drc_index)
> -			found = true;
> +			if (of_property_read_u32_index(parent,
> +						"ibm,drc-indexes",
> +						index++, &drc))
> +				break;
> +			if (cb(NULL, cdata, &drc, NULL))
> +				found = true;
> +		}
>  	}
> 
>  	return found;
>  }
> 
> +struct valid_drc_index_struct {
> +	u32 targ_drc_index;
> +};

Can you help me understand the need to encapsulate the drc_index as a struct.

> +
> +static int valid_drc_index_cb(struct of_drc_info *drc, void *idata,
> +				void *drc_index, int *ret_code)
> +{
> +	struct valid_drc_index_struct *cdata = idata;
> +
> +	if (drc) {
> +		if (!((drc->drc_index_start <= cdata->targ_drc_index) &&
> +			(cdata->targ_drc_index <= drc->last_drc_index)))
> +			return 0;
> +	} else {
> +		if (*((u32 *)drc_index) != cdata->targ_drc_index)
> +			return 0;
> +	}
> +	(*ret_code) = 1;
> +	return 1;
> +}
> +
> +static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
> +{
> +	struct valid_drc_index_struct cdata = { drc_index };
> +
> +	return check_cpu_drc_index(parent, valid_drc_index_cb, &cdata);
> +}
> +
>  static ssize_t dlpar_cpu_add(u32 drc_index)
>  {
>  	struct device_node *dn, *parent;
> @@ -721,11 +757,43 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
>  	return rc;
>  }
> 
> +struct cpus_to_add_struct {
> +	struct device_node *parent;
> +	u32 *cpu_drcs;
> +	u32 cpus_to_add;
> +	u32 cpus_found;
> +};
> +
> +static int cpus_to_add_cb(struct of_drc_info *drc, void *idata,
> +			void *drc_index, int *ret_code)
> +{
> +	struct cpus_to_add_struct *cdata = idata;
> +
> +	if (drc) {
> +		int k;
> +
> +		for (k = 0; (k < drc->num_sequential_elems) &&
> +			(cdata->cpus_found < cdata->cpus_to_add); k++) {
> +			u32 idrc = drc->drc_index_start +
> +				(k * drc->sequential_inc);
> +
> +			if (dlpar_cpu_exists(cdata->parent, idrc))
> +				continue;
> +			cdata->cpu_drcs[cdata->cpus_found++] = idrc;
> +		}
> +	} else {
> +		if (!dlpar_cpu_exists(cdata->parent, *((u32 *)drc_index)))
> +			cdata->cpu_drcs[cdata->cpus_found++] =
> +				*((u32 *)drc_index);
> +	}
> +	return 0;
> +}
> +
>  static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
>  {
>  	struct device_node *parent;
> -	int cpus_found = 0;
> -	int index, rc;
> +	struct cpus_to_add_struct cdata = {
> +		NULL, cpu_drcs, cpus_to_add, 0 };
> 
>  	parent = of_find_node_by_path("/cpus");
>  	if (!parent) {
> @@ -734,28 +802,14 @@ static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
>  		return -1;
>  	}
> 
> -	/* Search the ibm,drc-indexes array for possible CPU drcs to
> -	 * add. Note that the format of the ibm,drc-indexes array is
> -	 * the number of entries in the array followed by the array
> -	 * of drc values so we start looking at index = 1.
> +	/* Search the appropriate property for possible CPU drcs to
> +	 * add.
>  	 */
> -	index = 1;
> -	while (cpus_found < cpus_to_add) {
> -		u32 drc;
> -
> -		rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
> -						index++, &drc);
> -		if (rc)
> -			break;
> -
> -		if (dlpar_cpu_exists(parent, drc))
> -			continue;
> -
> -		cpu_drcs[cpus_found++] = drc;
> -	}
> +	cdata.parent = parent;
> +	check_cpu_drc_index(parent, cpus_to_add_cb, &cdata);
> 
>  	of_node_put(parent);
> -	return cpus_found;
> +	return cdata.cpus_found;
>  }
> 
>  static int dlpar_cpu_add_by_count(u32 cpus_to_add)
> diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c
> index 5261975..d8d7750 100644
> --- a/arch/powerpc/platforms/pseries/pseries_energy.c
> +++ b/arch/powerpc/platforms/pseries/pseries_energy.c
> @@ -36,6 +36,26 @@
> 
>  /* Helper Routines to convert between drc_index to cpu numbers */
> 
> +struct cpu_to_drc_index_struct {
> +	u32	thread_index;
> +	u32	ret;
> +};
> +
> +static int cpu_to_drc_index_cb(struct of_drc_info *drc, void *idata,
> +				void *not_used, int *ret_code)
> +{
> +	struct cpu_to_drc_index_struct *cdata = idata;
> +	int ret = 0;
> +
> +	if (cdata->thread_index < drc->last_drc_index) {

Is this correct? You're comparing a thread index to a drc index.

> +		cdata->ret = drc->drc_index_start +
> +			(cdata->thread_index * drc->sequential_inc);
> +		ret = 1;
> +	}
> +	(*ret_code) = ret;
> +	return ret;
> +}
> +
>  static u32 cpu_to_drc_index(int cpu)
>  {
>  	struct device_node *dn = NULL;
> @@ -51,30 +71,14 @@ static u32 cpu_to_drc_index(int cpu)
>  	thread_index = cpu_core_index_of_thread(cpu);
> 
>  	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
> -		struct property *info = NULL;
> -		struct of_drc_info drc;
> -		int j;
> -		u32 num_set_entries;
> -		const __be32 *value;
> -
> -		info = of_find_property(dn, "ibm,drc-info", NULL);
> -		if (info == NULL)
> -			goto err_of_node_put;
> +		struct cpu_to_drc_index_struct cdata = {
> +			thread_index, 0 };
> 
> -		value = info->value;
> -		num_set_entries = of_read_number(value++, 1);
> -
> -		for (j = 0; j < num_set_entries; j++) {
> -
> -			of_read_drc_info_cell(&info, &value, &drc);
> -			if (strncmp(drc.drc_type, "CPU", 3))
> -				goto err;
> -
> -			if (thread_index < drc.last_drc_index)
> -				break;
> -		}
> -
> -		ret = drc.drc_index_start + (thread_index * drc.sequential_inc);
> +		rc = drc_info_parser(dn, &cpu_to_drc_index_cb,
> +					"CPU", &cdata);
> +		if (rc < 0)
> +			goto err_of_node_put;
> +		ret = cdata.ret;
>  	} else {
>  		const __be32 *indexes;
> 
> @@ -100,11 +104,33 @@ static u32 cpu_to_drc_index(int cpu)
>  	return ret;
>  }
> 
> +struct drc_index_to_cpu_struct {
> +	u32	drc_index;
> +	u32	thread_index;
> +	u32	cpu;
> +};
> +
> +static int drc_index_to_cpu_cb(struct of_drc_info *drc,
> +				void *idata, void *not_used, int *ret_code)
> +{
> +	struct drc_index_to_cpu_struct *cdata = idata;
> +
> +	if (cdata->drc_index > drc->last_drc_index) {
> +		cdata->cpu += drc->num_sequential_elems;
> +	} else {
> +		cdata->cpu += ((cdata->drc_index - drc->drc_index_start) /
> +				drc->sequential_inc);
> +		cdata->thread_index = cpu_first_thread_of_core(cdata->cpu);

Should this return 1 here to avoid continuing to walk the drc_info entries?

-Nathan

> +	}
> +	(*ret_code) = 0;
> +	return 0;
> +}
> +
>  static int drc_index_to_cpu(u32 drc_index)
>  {
>  	struct device_node *dn = NULL;
>  	const int *indexes;
> -	int thread_index = 0, cpu = 0;
> +	int thread_index = 0;
>  	int rc = 1;
> 
>  	dn = of_find_node_by_path("/cpus");
> @@ -112,36 +138,13 @@ static int drc_index_to_cpu(u32 drc_index)
>  		goto err;
> 
>  	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
> -		struct property *info = NULL;
> -		struct of_drc_info drc;
> -		int j;
> -		u32 num_set_entries;
> -		const __be32 *value;
> -
> -		info = of_find_property(dn, "ibm,drc-info", NULL);
> -		if (info == NULL)
> -			goto err_of_node_put;
> -
> -		value = info->value;
> -		num_set_entries = of_read_number(value++, 1);
> -
> -		for (j = 0; j < num_set_entries; j++) {
> +		struct drc_index_to_cpu_struct cdata = {
> +			drc_index, 0, 0 };
> 
> -			of_read_drc_info_cell(&info, &value, &drc);
> -			if (strncmp(drc.drc_type, "CPU", 3))
> -				goto err;
> +		rc = drc_info_parser(dn, &drc_index_to_cpu_cb,
> +					"CPU", &cdata);
> +		thread_index = cdata.thread_index;
> 
> -			if (drc_index > drc.last_drc_index) {
> -				cpu += drc.num_sequential_elems;
> -				continue;
> -			}
> -			cpu += ((drc_index - drc.drc_index_start) /
> -				drc.sequential_inc);
> -
> -			thread_index = cpu_first_thread_of_core(cpu);
> -			rc = 0;
> -			break;
> -		}
>  	} else {
>  		unsigned long int i;
>
Michael Bringmann May 23, 2018, 1:14 a.m. UTC | #2
See below.

On 05/22/2018 04:31 PM, Nathan Fontenot wrote:
> On 05/22/2018 11:37 AM, Michael Bringmann wrote:
>> This patch applies a common parse function for the ibm,drc-info
>> property that can be modified by a callback function to the
>> hot-add CPU code.  Candidate code is replaced by a call to the
>> parser including a pointer to a local context-specific functions,
>> and local data.
>>
>> In addition, a bug in the release of the previous patch set may
>> break things in some of the CPU DLPAR operations.  For instance,
>> when attempting to hot-add a new CPU or set of CPUs, the original
>> patch failed to always properly calculate the available resources,
>> and aborted the operation.
>>
>> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
>> Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmwar
>> e feature" -- end of patch series applied to powerpc next)
>> ---
>> Changes in V4:
>>   -- Update code to account for latest kernel checkins.
>>   -- Rebased to 4.17-rc5 kernel
>>   -- Compress some more code
>> ---
>>  arch/powerpc/platforms/pseries/hotplug-cpu.c    |  118 +++++++++++++++++------
>>  arch/powerpc/platforms/pseries/pseries_energy.c |  107 +++++++++++----------
>>  2 files changed, 141 insertions(+), 84 deletions(-)
>>
>> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> index 6ef77ca..ceacad9 100644
>> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> @@ -411,27 +411,63 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
>>  	return found;
>>  }
>>
>> -static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
>> +static bool check_cpu_drc_index(struct device_node *parent,
>> +				int (*cb)(struct of_drc_info *drc,
>> +					void *data, void *not_used,
>> +					int *ret_code),
>> +				void *cdata)
>>  {
>>  	bool found = false;
>> -	int rc, index;
>>
>> -	index = 0;
>> -	while (!found) {
>> -		u32 drc;
>> +	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
>> +		if (drc_info_parser(parent, cb, "CPU", cdata))
>> +			found = true;
>> +	} else {
>> +		int index = 0;
>>
>> -		rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
>> -						index++, &drc);
>> -		if (rc)
>> -			break;
>> +		while (!found) {
>> +			u32 drc;
>>
>> -		if (drc == drc_index)
>> -			found = true;
>> +			if (of_property_read_u32_index(parent,
>> +						"ibm,drc-indexes",
>> +						index++, &drc))
>> +				break;
>> +			if (cb(NULL, cdata, &drc, NULL))
>> +				found = true;
>> +		}
>>  	}
>>
>>  	return found;
>>  }
>>
>> +struct valid_drc_index_struct {
>> +	u32 targ_drc_index;
>> +};
> 
> Can you help me understand the need to encapsulate the drc_index as a struct.

At this point, it is consistency of use across all of the instances
of using 'walk_drc_info'.  I believe that there were more values in
the structure earlier on.

> 
>> +
>> +static int valid_drc_index_cb(struct of_drc_info *drc, void *idata,
>> +				void *drc_index, int *ret_code)
>> +{
>> +	struct valid_drc_index_struct *cdata = idata;
>> +
>> +	if (drc) {
>> +		if (!((drc->drc_index_start <= cdata->targ_drc_index) &&
>> +			(cdata->targ_drc_index <= drc->last_drc_index)))
>> +			return 0;
>> +	} else {
>> +		if (*((u32 *)drc_index) != cdata->targ_drc_index)
>> +			return 0;
>> +	}
>> +	(*ret_code) = 1;
>> +	return 1;
>> +}
>> +
>> +static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
>> +{
>> +	struct valid_drc_index_struct cdata = { drc_index };
>> +
>> +	return check_cpu_drc_index(parent, valid_drc_index_cb, &cdata);
>> +}
>> +
>>  static ssize_t dlpar_cpu_add(u32 drc_index)
>>  {
>>  	struct device_node *dn, *parent;
>> @@ -721,11 +757,43 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
>>  	return rc;
>>  }
>>
>> +struct cpus_to_add_struct {
>> +	struct device_node *parent;
>> +	u32 *cpu_drcs;
>> +	u32 cpus_to_add;
>> +	u32 cpus_found;
>> +};
>> +
>> +static int cpus_to_add_cb(struct of_drc_info *drc, void *idata,
>> +			void *drc_index, int *ret_code)
>> +{
>> +	struct cpus_to_add_struct *cdata = idata;
>> +
>> +	if (drc) {
>> +		int k;
>> +
>> +		for (k = 0; (k < drc->num_sequential_elems) &&
>> +			(cdata->cpus_found < cdata->cpus_to_add); k++) {
>> +			u32 idrc = drc->drc_index_start +
>> +				(k * drc->sequential_inc);
>> +
>> +			if (dlpar_cpu_exists(cdata->parent, idrc))
>> +				continue;
>> +			cdata->cpu_drcs[cdata->cpus_found++] = idrc;
>> +		}
>> +	} else {
>> +		if (!dlpar_cpu_exists(cdata->parent, *((u32 *)drc_index)))
>> +			cdata->cpu_drcs[cdata->cpus_found++] =
>> +				*((u32 *)drc_index);
>> +	}
>> +	return 0;
>> +}
>> +
>>  static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
>>  {
>>  	struct device_node *parent;
>> -	int cpus_found = 0;
>> -	int index, rc;
>> +	struct cpus_to_add_struct cdata = {
>> +		NULL, cpu_drcs, cpus_to_add, 0 };
>>
>>  	parent = of_find_node_by_path("/cpus");
>>  	if (!parent) {
>> @@ -734,28 +802,14 @@ static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
>>  		return -1;
>>  	}
>>
>> -	/* Search the ibm,drc-indexes array for possible CPU drcs to
>> -	 * add. Note that the format of the ibm,drc-indexes array is
>> -	 * the number of entries in the array followed by the array
>> -	 * of drc values so we start looking at index = 1.
>> +	/* Search the appropriate property for possible CPU drcs to
>> +	 * add.
>>  	 */
>> -	index = 1;
>> -	while (cpus_found < cpus_to_add) {
>> -		u32 drc;
>> -
>> -		rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
>> -						index++, &drc);
>> -		if (rc)
>> -			break;
>> -
>> -		if (dlpar_cpu_exists(parent, drc))
>> -			continue;
>> -
>> -		cpu_drcs[cpus_found++] = drc;
>> -	}
>> +	cdata.parent = parent;
>> +	check_cpu_drc_index(parent, cpus_to_add_cb, &cdata);
>>
>>  	of_node_put(parent);
>> -	return cpus_found;
>> +	return cdata.cpus_found;
>>  }
>>
>>  static int dlpar_cpu_add_by_count(u32 cpus_to_add)
>> diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c
>> index 5261975..d8d7750 100644
>> --- a/arch/powerpc/platforms/pseries/pseries_energy.c
>> +++ b/arch/powerpc/platforms/pseries/pseries_energy.c
>> @@ -36,6 +36,26 @@
>>
>>  /* Helper Routines to convert between drc_index to cpu numbers */
>>
>> +struct cpu_to_drc_index_struct {
>> +	u32	thread_index;
>> +	u32	ret;
>> +};
>> +
>> +static int cpu_to_drc_index_cb(struct of_drc_info *drc, void *idata,
>> +				void *not_used, int *ret_code)
>> +{
>> +	struct cpu_to_drc_index_struct *cdata = idata;
>> +	int ret = 0;
>> +
>> +	if (cdata->thread_index < drc->last_drc_index) {
> 
> Is this correct? You're comparing a thread index to a drc index.

I believe so.  I will check when I retest this week, hopefully.

> 
>> +		cdata->ret = drc->drc_index_start +
>> +			(cdata->thread_index * drc->sequential_inc);
>> +		ret = 1;
>> +	}
>> +	(*ret_code) = ret;
>> +	return ret;
>> +}
>> +
>>  static u32 cpu_to_drc_index(int cpu)
>>  {
>>  	struct device_node *dn = NULL;
>> @@ -51,30 +71,14 @@ static u32 cpu_to_drc_index(int cpu)
>>  	thread_index = cpu_core_index_of_thread(cpu);
>>
>>  	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
>> -		struct property *info = NULL;
>> -		struct of_drc_info drc;
>> -		int j;
>> -		u32 num_set_entries;
>> -		const __be32 *value;
>> -
>> -		info = of_find_property(dn, "ibm,drc-info", NULL);
>> -		if (info == NULL)
>> -			goto err_of_node_put;
>> +		struct cpu_to_drc_index_struct cdata = {
>> +			thread_index, 0 };
>>
>> -		value = info->value;
>> -		num_set_entries = of_read_number(value++, 1);
>> -
>> -		for (j = 0; j < num_set_entries; j++) {
>> -
>> -			of_read_drc_info_cell(&info, &value, &drc);
>> -			if (strncmp(drc.drc_type, "CPU", 3))
>> -				goto err;
>> -
>> -			if (thread_index < drc.last_drc_index)
>> -				break;
>> -		}
>> -
>> -		ret = drc.drc_index_start + (thread_index * drc.sequential_inc);
>> +		rc = drc_info_parser(dn, &cpu_to_drc_index_cb,
>> +					"CPU", &cdata);
>> +		if (rc < 0)
>> +			goto err_of_node_put;
>> +		ret = cdata.ret;
>>  	} else {
>>  		const __be32 *indexes;
>>
>> @@ -100,11 +104,33 @@ static u32 cpu_to_drc_index(int cpu)
>>  	return ret;
>>  }
>>
>> +struct drc_index_to_cpu_struct {
>> +	u32	drc_index;
>> +	u32	thread_index;
>> +	u32	cpu;
>> +};
>> +
>> +static int drc_index_to_cpu_cb(struct of_drc_info *drc,
>> +				void *idata, void *not_used, int *ret_code)
>> +{
>> +	struct drc_index_to_cpu_struct *cdata = idata;
>> +
>> +	if (cdata->drc_index > drc->last_drc_index) {
>> +		cdata->cpu += drc->num_sequential_elems;
>> +	} else {
>> +		cdata->cpu += ((cdata->drc_index - drc->drc_index_start) /
>> +				drc->sequential_inc);
>> +		cdata->thread_index = cpu_first_thread_of_core(cdata->cpu);
> 
> Should this return 1 here to avoid continuing to walk the drc_info entries?

Yes.

> 
> -Nathan

Michael

> 
>> +	}
>> +	(*ret_code) = 0;
>> +	return 0;
>> +}
>> +
>>  static int drc_index_to_cpu(u32 drc_index)
>>  {
>>  	struct device_node *dn = NULL;
>>  	const int *indexes;
>> -	int thread_index = 0, cpu = 0;
>> +	int thread_index = 0;
>>  	int rc = 1;
>>
>>  	dn = of_find_node_by_path("/cpus");
>> @@ -112,36 +138,13 @@ static int drc_index_to_cpu(u32 drc_index)
>>  		goto err;
>>
>>  	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
>> -		struct property *info = NULL;
>> -		struct of_drc_info drc;
>> -		int j;
>> -		u32 num_set_entries;
>> -		const __be32 *value;
>> -
>> -		info = of_find_property(dn, "ibm,drc-info", NULL);
>> -		if (info == NULL)
>> -			goto err_of_node_put;
>> -
>> -		value = info->value;
>> -		num_set_entries = of_read_number(value++, 1);
>> -
>> -		for (j = 0; j < num_set_entries; j++) {
>> +		struct drc_index_to_cpu_struct cdata = {
>> +			drc_index, 0, 0 };
>>
>> -			of_read_drc_info_cell(&info, &value, &drc);
>> -			if (strncmp(drc.drc_type, "CPU", 3))
>> -				goto err;
>> +		rc = drc_info_parser(dn, &drc_index_to_cpu_cb,
>> +					"CPU", &cdata);
>> +		thread_index = cdata.thread_index;
>>
>> -			if (drc_index > drc.last_drc_index) {
>> -				cpu += drc.num_sequential_elems;
>> -				continue;
>> -			}
>> -			cpu += ((drc_index - drc.drc_index_start) /
>> -				drc.sequential_inc);
>> -
>> -			thread_index = cpu_first_thread_of_core(cpu);
>> -			rc = 0;
>> -			break;
>> -		}
>>  	} else {
>>  		unsigned long int i;
>>
> 
>
diff mbox series

Patch

diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 6ef77ca..ceacad9 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -411,27 +411,63 @@  static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
 	return found;
 }
 
-static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
+static bool check_cpu_drc_index(struct device_node *parent,
+				int (*cb)(struct of_drc_info *drc,
+					void *data, void *not_used,
+					int *ret_code),
+				void *cdata)
 {
 	bool found = false;
-	int rc, index;
 
-	index = 0;
-	while (!found) {
-		u32 drc;
+	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
+		if (drc_info_parser(parent, cb, "CPU", cdata))
+			found = true;
+	} else {
+		int index = 0;
 
-		rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
-						index++, &drc);
-		if (rc)
-			break;
+		while (!found) {
+			u32 drc;
 
-		if (drc == drc_index)
-			found = true;
+			if (of_property_read_u32_index(parent,
+						"ibm,drc-indexes",
+						index++, &drc))
+				break;
+			if (cb(NULL, cdata, &drc, NULL))
+				found = true;
+		}
 	}
 
 	return found;
 }
 
+struct valid_drc_index_struct {
+	u32 targ_drc_index;
+};
+
+static int valid_drc_index_cb(struct of_drc_info *drc, void *idata,
+				void *drc_index, int *ret_code)
+{
+	struct valid_drc_index_struct *cdata = idata;
+
+	if (drc) {
+		if (!((drc->drc_index_start <= cdata->targ_drc_index) &&
+			(cdata->targ_drc_index <= drc->last_drc_index)))
+			return 0;
+	} else {
+		if (*((u32 *)drc_index) != cdata->targ_drc_index)
+			return 0;
+	}
+	(*ret_code) = 1;
+	return 1;
+}
+
+static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
+{
+	struct valid_drc_index_struct cdata = { drc_index };
+
+	return check_cpu_drc_index(parent, valid_drc_index_cb, &cdata);
+}
+
 static ssize_t dlpar_cpu_add(u32 drc_index)
 {
 	struct device_node *dn, *parent;
@@ -721,11 +757,43 @@  static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
 	return rc;
 }
 
+struct cpus_to_add_struct {
+	struct device_node *parent;
+	u32 *cpu_drcs;
+	u32 cpus_to_add;
+	u32 cpus_found;
+};
+
+static int cpus_to_add_cb(struct of_drc_info *drc, void *idata,
+			void *drc_index, int *ret_code)
+{
+	struct cpus_to_add_struct *cdata = idata;
+
+	if (drc) {
+		int k;
+
+		for (k = 0; (k < drc->num_sequential_elems) &&
+			(cdata->cpus_found < cdata->cpus_to_add); k++) {
+			u32 idrc = drc->drc_index_start +
+				(k * drc->sequential_inc);
+
+			if (dlpar_cpu_exists(cdata->parent, idrc))
+				continue;
+			cdata->cpu_drcs[cdata->cpus_found++] = idrc;
+		}
+	} else {
+		if (!dlpar_cpu_exists(cdata->parent, *((u32 *)drc_index)))
+			cdata->cpu_drcs[cdata->cpus_found++] =
+				*((u32 *)drc_index);
+	}
+	return 0;
+}
+
 static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
 {
 	struct device_node *parent;
-	int cpus_found = 0;
-	int index, rc;
+	struct cpus_to_add_struct cdata = {
+		NULL, cpu_drcs, cpus_to_add, 0 };
 
 	parent = of_find_node_by_path("/cpus");
 	if (!parent) {
@@ -734,28 +802,14 @@  static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
 		return -1;
 	}
 
-	/* Search the ibm,drc-indexes array for possible CPU drcs to
-	 * add. Note that the format of the ibm,drc-indexes array is
-	 * the number of entries in the array followed by the array
-	 * of drc values so we start looking at index = 1.
+	/* Search the appropriate property for possible CPU drcs to
+	 * add.
 	 */
-	index = 1;
-	while (cpus_found < cpus_to_add) {
-		u32 drc;
-
-		rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
-						index++, &drc);
-		if (rc)
-			break;
-
-		if (dlpar_cpu_exists(parent, drc))
-			continue;
-
-		cpu_drcs[cpus_found++] = drc;
-	}
+	cdata.parent = parent;
+	check_cpu_drc_index(parent, cpus_to_add_cb, &cdata);
 
 	of_node_put(parent);
-	return cpus_found;
+	return cdata.cpus_found;
 }
 
 static int dlpar_cpu_add_by_count(u32 cpus_to_add)
diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c
index 5261975..d8d7750 100644
--- a/arch/powerpc/platforms/pseries/pseries_energy.c
+++ b/arch/powerpc/platforms/pseries/pseries_energy.c
@@ -36,6 +36,26 @@ 
 
 /* Helper Routines to convert between drc_index to cpu numbers */
 
+struct cpu_to_drc_index_struct {
+	u32	thread_index;
+	u32	ret;
+};
+
+static int cpu_to_drc_index_cb(struct of_drc_info *drc, void *idata,
+				void *not_used, int *ret_code)
+{
+	struct cpu_to_drc_index_struct *cdata = idata;
+	int ret = 0;
+
+	if (cdata->thread_index < drc->last_drc_index) {
+		cdata->ret = drc->drc_index_start +
+			(cdata->thread_index * drc->sequential_inc);
+		ret = 1;
+	}
+	(*ret_code) = ret;
+	return ret;
+}
+
 static u32 cpu_to_drc_index(int cpu)
 {
 	struct device_node *dn = NULL;
@@ -51,30 +71,14 @@  static u32 cpu_to_drc_index(int cpu)
 	thread_index = cpu_core_index_of_thread(cpu);
 
 	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
-		struct property *info = NULL;
-		struct of_drc_info drc;
-		int j;
-		u32 num_set_entries;
-		const __be32 *value;
-
-		info = of_find_property(dn, "ibm,drc-info", NULL);
-		if (info == NULL)
-			goto err_of_node_put;
+		struct cpu_to_drc_index_struct cdata = {
+			thread_index, 0 };
 
-		value = info->value;
-		num_set_entries = of_read_number(value++, 1);
-
-		for (j = 0; j < num_set_entries; j++) {
-
-			of_read_drc_info_cell(&info, &value, &drc);
-			if (strncmp(drc.drc_type, "CPU", 3))
-				goto err;
-
-			if (thread_index < drc.last_drc_index)
-				break;
-		}
-
-		ret = drc.drc_index_start + (thread_index * drc.sequential_inc);
+		rc = drc_info_parser(dn, &cpu_to_drc_index_cb,
+					"CPU", &cdata);
+		if (rc < 0)
+			goto err_of_node_put;
+		ret = cdata.ret;
 	} else {
 		const __be32 *indexes;
 
@@ -100,11 +104,33 @@  static u32 cpu_to_drc_index(int cpu)
 	return ret;
 }
 
+struct drc_index_to_cpu_struct {
+	u32	drc_index;
+	u32	thread_index;
+	u32	cpu;
+};
+
+static int drc_index_to_cpu_cb(struct of_drc_info *drc,
+				void *idata, void *not_used, int *ret_code)
+{
+	struct drc_index_to_cpu_struct *cdata = idata;
+
+	if (cdata->drc_index > drc->last_drc_index) {
+		cdata->cpu += drc->num_sequential_elems;
+	} else {
+		cdata->cpu += ((cdata->drc_index - drc->drc_index_start) /
+				drc->sequential_inc);
+		cdata->thread_index = cpu_first_thread_of_core(cdata->cpu);
+	}
+	(*ret_code) = 0;
+	return 0;
+}
+
 static int drc_index_to_cpu(u32 drc_index)
 {
 	struct device_node *dn = NULL;
 	const int *indexes;
-	int thread_index = 0, cpu = 0;
+	int thread_index = 0;
 	int rc = 1;
 
 	dn = of_find_node_by_path("/cpus");
@@ -112,36 +138,13 @@  static int drc_index_to_cpu(u32 drc_index)
 		goto err;
 
 	if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
-		struct property *info = NULL;
-		struct of_drc_info drc;
-		int j;
-		u32 num_set_entries;
-		const __be32 *value;
-
-		info = of_find_property(dn, "ibm,drc-info", NULL);
-		if (info == NULL)
-			goto err_of_node_put;
-
-		value = info->value;
-		num_set_entries = of_read_number(value++, 1);
-
-		for (j = 0; j < num_set_entries; j++) {
+		struct drc_index_to_cpu_struct cdata = {
+			drc_index, 0, 0 };
 
-			of_read_drc_info_cell(&info, &value, &drc);
-			if (strncmp(drc.drc_type, "CPU", 3))
-				goto err;
+		rc = drc_info_parser(dn, &drc_index_to_cpu_cb,
+					"CPU", &cdata);
+		thread_index = cdata.thread_index;
 
-			if (drc_index > drc.last_drc_index) {
-				cpu += drc.num_sequential_elems;
-				continue;
-			}
-			cpu += ((drc_index - drc.drc_index_start) /
-				drc.sequential_inc);
-
-			thread_index = cpu_first_thread_of_core(cpu);
-			rc = 0;
-			break;
-		}
 	} else {
 		unsigned long int i;