diff mbox series

[RFC,v5,6/6] migration/memory: Update memory for assoc changes

Message ID 8b17b806-abe7-49cf-0f0f-9b23905cdfd1@linux.vnet.ibm.com (mailing list archive)
State Superseded
Headers show
Series powerpc/hotplug: Fix affinity assoc for LPAR migration | expand

Commit Message

Michael Bringmann May 21, 2018, 5:52 p.m. UTC
migration/memory: This patch adds more recognition for changes to
the associativity of memory blocks described by the device-tree
properties and updates local and general kernel data structures to
reflect those changes.  These differences may include:

* Evaluating 'ibm,dynamic-memory' properties when processing the
  topology of LPARS in Post Migration events.  Previous efforts
  only recognized whether a memory block's assignment had changed
  in the property.  Changes here include checking the aa_index
  values for each drc_index of the old/new LMBs and to 'readd'
  any block for which the setting has changed.

* In an LPAR migration scenario, the "ibm,associativity-lookup-arrays"
  property may change.  In the event that a row of the array differs,
  locate all assigned memory blocks with that 'aa_index' and 're-add'
  them to the system memory block data structures.  In the process of
  the 're-add', the system routines will update the corresponding entry
  for the memory in the LMB structures and any other relevant kernel
  data structures.

* Extend the previous work for the 'ibm,associativity-lookup-array'
  and 'ibm,dynamic-memory' properties to support the property
  'ibm,dynamic-memory-v2' by means of the DRMEM LMB interpretation
  code.

Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---
Changes in RFC:
  -- Simplify code to update memory nodes during mobility checks.
  -- Reuse code from DRMEM changes to scan for LMBs when updating
     aa_index
  -- Combine common code for properties 'ibm,dynamic-memory' and
     'ibm,dynamic-memory-v2' after integrating DRMEM features.
  -- Rearrange patches to co-locate memory property-related changes.
  -- Use new paired list iterator for the drmem info arrays.
  -- Use direct calls to add/remove memory from the update drconf
     function as those operations are only intended for user DLPAR
     ops, and should not occur during Migration reconfig notifier
     changes.
  -- Correct processing bug in processing of ibm,associativity-lookup-arrays
  -- Rebase to 4.17-rc5 kernel
  -- Apply minor code cleanups
---
 arch/powerpc/platforms/pseries/hotplug-memory.c |  153 ++++++++++++++++++-----
 1 file changed, 121 insertions(+), 32 deletions(-)

Comments

Thomas Falcon May 22, 2018, 9:11 p.m. UTC | #1
On 05/21/2018 12:52 PM, Michael Bringmann wrote:
> migration/memory: This patch adds more recognition for changes to
> the associativity of memory blocks described by the device-tree
> properties and updates local and general kernel data structures to
> reflect those changes.  These differences may include:
>
> * Evaluating 'ibm,dynamic-memory' properties when processing the
>   topology of LPARS in Post Migration events.  Previous efforts
>   only recognized whether a memory block's assignment had changed
>   in the property.  Changes here include checking the aa_index
>   values for each drc_index of the old/new LMBs and to 'readd'
>   any block for which the setting has changed.
>
> * In an LPAR migration scenario, the "ibm,associativity-lookup-arrays"
>   property may change.  In the event that a row of the array differs,
>   locate all assigned memory blocks with that 'aa_index' and 're-add'
>   them to the system memory block data structures.  In the process of
>   the 're-add', the system routines will update the corresponding entry
>   for the memory in the LMB structures and any other relevant kernel
>   data structures.
>
> * Extend the previous work for the 'ibm,associativity-lookup-array'
>   and 'ibm,dynamic-memory' properties to support the property
>   'ibm,dynamic-memory-v2' by means of the DRMEM LMB interpretation
>   code.
>
> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
> ---
> Changes in RFC:
>   -- Simplify code to update memory nodes during mobility checks.
>   -- Reuse code from DRMEM changes to scan for LMBs when updating
>      aa_index
>   -- Combine common code for properties 'ibm,dynamic-memory' and
>      'ibm,dynamic-memory-v2' after integrating DRMEM features.
>   -- Rearrange patches to co-locate memory property-related changes.
>   -- Use new paired list iterator for the drmem info arrays.
>   -- Use direct calls to add/remove memory from the update drconf
>      function as those operations are only intended for user DLPAR
>      ops, and should not occur during Migration reconfig notifier
>      changes.
>   -- Correct processing bug in processing of ibm,associativity-lookup-arrays
>   -- Rebase to 4.17-rc5 kernel
>   -- Apply minor code cleanups
> ---
>  arch/powerpc/platforms/pseries/hotplug-memory.c |  153 ++++++++++++++++++-----
>  1 file changed, 121 insertions(+), 32 deletions(-)
>
> diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
> index c1578f5..ac329aa 100644
> --- a/arch/powerpc/platforms/pseries/hotplug-memory.c
> +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
> @@ -994,13 +994,11 @@ static int pseries_add_mem_node(struct device_node *np)
>  	return (ret < 0) ? -EINVAL : 0;
>  }
>
> -static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
> +static int pseries_update_drconf_memory(struct drmem_lmb_info *new_dinfo)
>  {
> -	struct of_drconf_cell_v1 *new_drmem, *old_drmem;
> +	struct drmem_lmb *old_lmb, *new_lmb;
>  	unsigned long memblock_size;
> -	u32 entries;
> -	__be32 *p;
> -	int i, rc = -EINVAL;
> +	int rc = 0;
>
>  	if (rtas_hp_event)
>  		return 0;
> @@ -1009,42 +1007,124 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
>  	if (!memblock_size)
>  		return -EINVAL;
>
> -	p = (__be32 *) pr->old_prop->value;
> -	if (!p)
> -		return -EINVAL;
> +	/* Arrays should have the same size and DRC indexes */
> +	for_each_pair_drmem_lmb(drmem_info, old_lmb, new_dinfo, new_lmb) {
>
> -	/* The first int of the property is the number of lmb's described
> -	 * by the property. This is followed by an array of of_drconf_cell
> -	 * entries. Get the number of entries and skip to the array of
> -	 * of_drconf_cell's.
> -	 */
> -	entries = be32_to_cpu(*p++);
> -	old_drmem = (struct of_drconf_cell_v1 *)p;
> -
> -	p = (__be32 *)pr->prop->value;
> -	p++;
> -	new_drmem = (struct of_drconf_cell_v1 *)p;
> +		if (new_lmb->drc_index != old_lmb->drc_index)
> +			continue;
>
> -	for (i = 0; i < entries; i++) {
> -		if ((be32_to_cpu(old_drmem[i].flags) & DRCONF_MEM_ASSIGNED) &&
> -		    (!(be32_to_cpu(new_drmem[i].flags) & DRCONF_MEM_ASSIGNED))) {
> +		if ((old_lmb->flags & DRCONF_MEM_ASSIGNED) &&
> +		    (!(new_lmb->flags & DRCONF_MEM_ASSIGNED))) {
>  			rc = pseries_remove_memblock(
> -				be64_to_cpu(old_drmem[i].base_addr),
> -						     memblock_size);
> +				old_lmb->base_addr, memblock_size);
>  			break;
> -		} else if ((!(be32_to_cpu(old_drmem[i].flags) &
> -			    DRCONF_MEM_ASSIGNED)) &&
> -			    (be32_to_cpu(new_drmem[i].flags) &
> -			    DRCONF_MEM_ASSIGNED)) {
> -			rc = memblock_add(be64_to_cpu(old_drmem[i].base_addr),
> -					  memblock_size);
> +		} else if ((!(old_lmb->flags & DRCONF_MEM_ASSIGNED)) &&
> +			   (new_lmb->flags & DRCONF_MEM_ASSIGNED)) {
> +			rc = memblock_add(old_lmb->base_addr,
> +					memblock_size);
>  			rc = (rc < 0) ? -EINVAL : 0;
>  			break;
> +		} else if ((old_lmb->aa_index != new_lmb->aa_index) &&
> +			   (new_lmb->flags & DRCONF_MEM_ASSIGNED)) {
> +			dlpar_queue_action(PSERIES_HP_ELOG_RESOURCE_MEM,
> +					   PSERIES_HP_ELOG_ACTION_READD,
> +					   new_lmb->drc_index);
>  		}
>  	}
>  	return rc;
>  }
>
> +static void pseries_update_ala_memory_aai(int aa_index)
> +{
> +	struct drmem_lmb *lmb;
> +
> +	/* Readd all LMBs which were previously using the
> +	 * specified aa_index value.
> +	 */
> +	for_each_drmem_lmb(lmb) {
> +		if ((lmb->aa_index == aa_index) &&
> +			(lmb->flags & DRCONF_MEM_ASSIGNED)) {
> +			dlpar_queue_action(PSERIES_HP_ELOG_RESOURCE_MEM,
> +					   PSERIES_HP_ELOG_ACTION_READD,
> +					   lmb->drc_index);
> +		}
> +	}
> +}
> +
> +struct assoc_arrays {
> +	u32 n_arrays;
> +	u32 array_sz;
> +	const __be32 *arrays;
> +};
> +
> +static int pseries_update_ala_memory(struct of_reconfig_data *pr)
> +{
> +	struct assoc_arrays new_ala, old_ala;
> +	__be32 *p;
> +	int i, lim;
> +
> +	if (rtas_hp_event)
> +		return 0;
> +
> +	/*
> +	 * The layout of the ibm,associativity-lookup-arrays
> +	 * property is a number N indicating the number of
> +	 * associativity arrays, followed by a number M
> +	 * indicating the size of each associativity array,
> +	 * followed by a list of N associativity arrays.
> +	 */
> +
> +	p = (__be32 *) pr->old_prop->value;
> +	if (!p)
> +		return -EINVAL;
> +	old_ala.n_arrays = of_read_number(p++, 1);
> +	old_ala.array_sz = of_read_number(p++, 1);
> +	old_ala.arrays = p;
> +
> +	p = (__be32 *) pr->prop->value;
> +	if (!p)
> +		return -EINVAL;
> +	new_ala.n_arrays = of_read_number(p++, 1);
> +	new_ala.array_sz = of_read_number(p++, 1);
> +	new_ala.arrays = p;
> +

I don't know how often associativity lookup arrays needs to be parsed, but maybe it would be helpful to create a helper function to parse those here.

> +	lim = (new_ala.n_arrays > old_ala.n_arrays) ? old_ala.n_arrays :
> +			new_ala.n_arrays;
> +
> +	if (old_ala.array_sz == new_ala.array_sz) {
> +
> +		/* Reset any entries where the old and new rows
> +		 * the array have changed.
> +		 */
> +		for (i = 0; i < lim; i++) {
> +			int index = (i * new_ala.array_sz);
> +
> +			if (!memcmp(&old_ala.arrays[index],
> +				&new_ala.arrays[index],
> +				new_ala.array_sz))
> +				continue;
> +
> +			pseries_update_ala_memory_aai(i);
> +		}
> +
> +		/* Reset any entries representing the extra rows.
> +		 * There shouldn't be any, but just in case ...
> +		 */
> +		for (i = lim; i < new_ala.n_arrays; i++)
> +			pseries_update_ala_memory_aai(i);
> +
> +	} else {
> +		/* Update all entries representing these rows;
> +		 * as all rows have different sizes, none can
> +		 * have equivalent values.
> +		 */
> +		for (i = 0; i < lim; i++)
> +			pseries_update_ala_memory_aai(i);
> +	}
> +
> +	return 0;
> +}
> +
>  static int pseries_memory_notifier(struct notifier_block *nb,
>  				   unsigned long action, void *data)
>  {
> @@ -1059,8 +1139,17 @@ static int pseries_memory_notifier(struct notifier_block *nb,
>  		err = pseries_remove_mem_node(rd->dn);
>  		break;
>  	case OF_RECONFIG_UPDATE_PROPERTY:
> -		if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
> -			err = pseries_update_drconf_memory(rd);
> +		if (!strcmp(rd->prop->name, "ibm,dynamic-memory") ||
> +		    !strcmp(rd->prop->name, "ibm,dynamic-memory-v2")) {
> +			struct drmem_lmb_info *dinfo =
> +				drmem_lmbs_init(rd->prop);
> +			if (!dinfo)
> +				return -EINVAL;
> +			err = pseries_update_drconf_memory(dinfo);
> +			drmem_lmbs_free(dinfo);

Is this block above related to the other associativity changes?  It seems to be an update for dynamic-memory-v2, so should probably be in a separate patch.

Thanks,
Tom

> +		} else if (!strcmp(rd->prop->name,
> +				"ibm,associativity-lookup-arrays"))
> +			err = pseries_update_ala_memory(rd);
>  		break;
>  	}
>  	return notifier_from_errno(err);
Michael Bringmann May 22, 2018, 11:54 p.m. UTC | #2
This patch was intended to apply the necessary changes for the
'ibm,dynamic-memory[-v2]' properties.  Before the advent of the
LMB representation, that code took up a lot more space.  At this
point, it has shrunk to only one line of unique change.  I was
hoping to include it here rather than create another patch.

But that can be done.

Michael

On 05/22/2018 04:11 PM, Thomas Falcon wrote:
> On 05/21/2018 12:52 PM, Michael Bringmann wrote:
>> migration/memory: This patch adds more recognition for changes to
>> the associativity of memory blocks described by the device-tree
>> properties and updates local and general kernel data structures to
>> reflect those changes.  These differences may include:
>>
>> * Evaluating 'ibm,dynamic-memory' properties when processing the
>>   topology of LPARS in Post Migration events.  Previous efforts
>>   only recognized whether a memory block's assignment had changed
>>   in the property.  Changes here include checking the aa_index
>>   values for each drc_index of the old/new LMBs and to 'readd'
>>   any block for which the setting has changed.
>>
>> * In an LPAR migration scenario, the "ibm,associativity-lookup-arrays"
>>   property may change.  In the event that a row of the array differs,
>>   locate all assigned memory blocks with that 'aa_index' and 're-add'
>>   them to the system memory block data structures.  In the process of
>>   the 're-add', the system routines will update the corresponding entry
>>   for the memory in the LMB structures and any other relevant kernel
>>   data structures.
>>
>> * Extend the previous work for the 'ibm,associativity-lookup-array'
>>   and 'ibm,dynamic-memory' properties to support the property
>>   'ibm,dynamic-memory-v2' by means of the DRMEM LMB interpretation
>>   code.
>>
>> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
>> ---
>> Changes in RFC:
>>   -- Simplify code to update memory nodes during mobility checks.
>>   -- Reuse code from DRMEM changes to scan for LMBs when updating
>>      aa_index
>>   -- Combine common code for properties 'ibm,dynamic-memory' and
>>      'ibm,dynamic-memory-v2' after integrating DRMEM features.
>>   -- Rearrange patches to co-locate memory property-related changes.
>>   -- Use new paired list iterator for the drmem info arrays.
>>   -- Use direct calls to add/remove memory from the update drconf
>>      function as those operations are only intended for user DLPAR
>>      ops, and should not occur during Migration reconfig notifier
>>      changes.
>>   -- Correct processing bug in processing of ibm,associativity-lookup-arrays
>>   -- Rebase to 4.17-rc5 kernel
>>   -- Apply minor code cleanups
>> ---
>>  arch/powerpc/platforms/pseries/hotplug-memory.c |  153 ++++++++++++++++++-----
>>  1 file changed, 121 insertions(+), 32 deletions(-)
>>
>> diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
>> index c1578f5..ac329aa 100644
>> --- a/arch/powerpc/platforms/pseries/hotplug-memory.c
>> +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
>> @@ -994,13 +994,11 @@ static int pseries_add_mem_node(struct device_node *np)
>>  	return (ret < 0) ? -EINVAL : 0;
>>  }
>>
>> -static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
>> +static int pseries_update_drconf_memory(struct drmem_lmb_info *new_dinfo)
>>  {
>> -	struct of_drconf_cell_v1 *new_drmem, *old_drmem;
>> +	struct drmem_lmb *old_lmb, *new_lmb;
>>  	unsigned long memblock_size;
>> -	u32 entries;
>> -	__be32 *p;
>> -	int i, rc = -EINVAL;
>> +	int rc = 0;
>>
>>  	if (rtas_hp_event)
>>  		return 0;
>> @@ -1009,42 +1007,124 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
>>  	if (!memblock_size)
>>  		return -EINVAL;
>>
>> -	p = (__be32 *) pr->old_prop->value;
>> -	if (!p)
>> -		return -EINVAL;
>> +	/* Arrays should have the same size and DRC indexes */
>> +	for_each_pair_drmem_lmb(drmem_info, old_lmb, new_dinfo, new_lmb) {
>>
>> -	/* The first int of the property is the number of lmb's described
>> -	 * by the property. This is followed by an array of of_drconf_cell
>> -	 * entries. Get the number of entries and skip to the array of
>> -	 * of_drconf_cell's.
>> -	 */
>> -	entries = be32_to_cpu(*p++);
>> -	old_drmem = (struct of_drconf_cell_v1 *)p;
>> -
>> -	p = (__be32 *)pr->prop->value;
>> -	p++;
>> -	new_drmem = (struct of_drconf_cell_v1 *)p;
>> +		if (new_lmb->drc_index != old_lmb->drc_index)
>> +			continue;
>>
>> -	for (i = 0; i < entries; i++) {
>> -		if ((be32_to_cpu(old_drmem[i].flags) & DRCONF_MEM_ASSIGNED) &&
>> -		    (!(be32_to_cpu(new_drmem[i].flags) & DRCONF_MEM_ASSIGNED))) {
>> +		if ((old_lmb->flags & DRCONF_MEM_ASSIGNED) &&
>> +		    (!(new_lmb->flags & DRCONF_MEM_ASSIGNED))) {
>>  			rc = pseries_remove_memblock(
>> -				be64_to_cpu(old_drmem[i].base_addr),
>> -						     memblock_size);
>> +				old_lmb->base_addr, memblock_size);
>>  			break;
>> -		} else if ((!(be32_to_cpu(old_drmem[i].flags) &
>> -			    DRCONF_MEM_ASSIGNED)) &&
>> -			    (be32_to_cpu(new_drmem[i].flags) &
>> -			    DRCONF_MEM_ASSIGNED)) {
>> -			rc = memblock_add(be64_to_cpu(old_drmem[i].base_addr),
>> -					  memblock_size);
>> +		} else if ((!(old_lmb->flags & DRCONF_MEM_ASSIGNED)) &&
>> +			   (new_lmb->flags & DRCONF_MEM_ASSIGNED)) {
>> +			rc = memblock_add(old_lmb->base_addr,
>> +					memblock_size);
>>  			rc = (rc < 0) ? -EINVAL : 0;
>>  			break;
>> +		} else if ((old_lmb->aa_index != new_lmb->aa_index) &&
>> +			   (new_lmb->flags & DRCONF_MEM_ASSIGNED)) {
>> +			dlpar_queue_action(PSERIES_HP_ELOG_RESOURCE_MEM,
>> +					   PSERIES_HP_ELOG_ACTION_READD,
>> +					   new_lmb->drc_index);
>>  		}
>>  	}
>>  	return rc;
>>  }
>>
>> +static void pseries_update_ala_memory_aai(int aa_index)
>> +{
>> +	struct drmem_lmb *lmb;
>> +
>> +	/* Readd all LMBs which were previously using the
>> +	 * specified aa_index value.
>> +	 */
>> +	for_each_drmem_lmb(lmb) {
>> +		if ((lmb->aa_index == aa_index) &&
>> +			(lmb->flags & DRCONF_MEM_ASSIGNED)) {
>> +			dlpar_queue_action(PSERIES_HP_ELOG_RESOURCE_MEM,
>> +					   PSERIES_HP_ELOG_ACTION_READD,
>> +					   lmb->drc_index);
>> +		}
>> +	}
>> +}
>> +
>> +struct assoc_arrays {
>> +	u32 n_arrays;
>> +	u32 array_sz;
>> +	const __be32 *arrays;
>> +};
>> +
>> +static int pseries_update_ala_memory(struct of_reconfig_data *pr)
>> +{
>> +	struct assoc_arrays new_ala, old_ala;
>> +	__be32 *p;
>> +	int i, lim;
>> +
>> +	if (rtas_hp_event)
>> +		return 0;
>> +
>> +	/*
>> +	 * The layout of the ibm,associativity-lookup-arrays
>> +	 * property is a number N indicating the number of
>> +	 * associativity arrays, followed by a number M
>> +	 * indicating the size of each associativity array,
>> +	 * followed by a list of N associativity arrays.
>> +	 */
>> +
>> +	p = (__be32 *) pr->old_prop->value;
>> +	if (!p)
>> +		return -EINVAL;
>> +	old_ala.n_arrays = of_read_number(p++, 1);
>> +	old_ala.array_sz = of_read_number(p++, 1);
>> +	old_ala.arrays = p;
>> +
>> +	p = (__be32 *) pr->prop->value;
>> +	if (!p)
>> +		return -EINVAL;
>> +	new_ala.n_arrays = of_read_number(p++, 1);
>> +	new_ala.array_sz = of_read_number(p++, 1);
>> +	new_ala.arrays = p;
>> +
> 
> I don't know how often associativity lookup arrays needs to be parsed, but maybe it would be helpful to create a helper function to parse those here.
> 
>> +	lim = (new_ala.n_arrays > old_ala.n_arrays) ? old_ala.n_arrays :
>> +			new_ala.n_arrays;
>> +
>> +	if (old_ala.array_sz == new_ala.array_sz) {
>> +
>> +		/* Reset any entries where the old and new rows
>> +		 * the array have changed.
>> +		 */
>> +		for (i = 0; i < lim; i++) {
>> +			int index = (i * new_ala.array_sz);
>> +
>> +			if (!memcmp(&old_ala.arrays[index],
>> +				&new_ala.arrays[index],
>> +				new_ala.array_sz))
>> +				continue;
>> +
>> +			pseries_update_ala_memory_aai(i);
>> +		}
>> +
>> +		/* Reset any entries representing the extra rows.
>> +		 * There shouldn't be any, but just in case ...
>> +		 */
>> +		for (i = lim; i < new_ala.n_arrays; i++)
>> +			pseries_update_ala_memory_aai(i);
>> +
>> +	} else {
>> +		/* Update all entries representing these rows;
>> +		 * as all rows have different sizes, none can
>> +		 * have equivalent values.
>> +		 */
>> +		for (i = 0; i < lim; i++)
>> +			pseries_update_ala_memory_aai(i);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>  static int pseries_memory_notifier(struct notifier_block *nb,
>>  				   unsigned long action, void *data)
>>  {
>> @@ -1059,8 +1139,17 @@ static int pseries_memory_notifier(struct notifier_block *nb,
>>  		err = pseries_remove_mem_node(rd->dn);
>>  		break;
>>  	case OF_RECONFIG_UPDATE_PROPERTY:
>> -		if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
>> -			err = pseries_update_drconf_memory(rd);
>> +		if (!strcmp(rd->prop->name, "ibm,dynamic-memory") ||
>> +		    !strcmp(rd->prop->name, "ibm,dynamic-memory-v2")) {
>> +			struct drmem_lmb_info *dinfo =
>> +				drmem_lmbs_init(rd->prop);
>> +			if (!dinfo)
>> +				return -EINVAL;
>> +			err = pseries_update_drconf_memory(dinfo);
>> +			drmem_lmbs_free(dinfo);
> 
> Is this block above related to the other associativity changes?  It seems to be an update for dynamic-memory-v2, so should probably be in a separate patch.
> 
> Thanks,
> Tom
> 
>> +		} else if (!strcmp(rd->prop->name,
>> +				"ibm,associativity-lookup-arrays"))
>> +			err = pseries_update_ala_memory(rd);
>>  		break;
>>  	}
>>  	return notifier_from_errno(err);
> 
> 
>
diff mbox series

Patch

diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index c1578f5..ac329aa 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -994,13 +994,11 @@  static int pseries_add_mem_node(struct device_node *np)
 	return (ret < 0) ? -EINVAL : 0;
 }
 
-static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
+static int pseries_update_drconf_memory(struct drmem_lmb_info *new_dinfo)
 {
-	struct of_drconf_cell_v1 *new_drmem, *old_drmem;
+	struct drmem_lmb *old_lmb, *new_lmb;
 	unsigned long memblock_size;
-	u32 entries;
-	__be32 *p;
-	int i, rc = -EINVAL;
+	int rc = 0;
 
 	if (rtas_hp_event)
 		return 0;
@@ -1009,42 +1007,124 @@  static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
 	if (!memblock_size)
 		return -EINVAL;
 
-	p = (__be32 *) pr->old_prop->value;
-	if (!p)
-		return -EINVAL;
+	/* Arrays should have the same size and DRC indexes */
+	for_each_pair_drmem_lmb(drmem_info, old_lmb, new_dinfo, new_lmb) {
 
-	/* The first int of the property is the number of lmb's described
-	 * by the property. This is followed by an array of of_drconf_cell
-	 * entries. Get the number of entries and skip to the array of
-	 * of_drconf_cell's.
-	 */
-	entries = be32_to_cpu(*p++);
-	old_drmem = (struct of_drconf_cell_v1 *)p;
-
-	p = (__be32 *)pr->prop->value;
-	p++;
-	new_drmem = (struct of_drconf_cell_v1 *)p;
+		if (new_lmb->drc_index != old_lmb->drc_index)
+			continue;
 
-	for (i = 0; i < entries; i++) {
-		if ((be32_to_cpu(old_drmem[i].flags) & DRCONF_MEM_ASSIGNED) &&
-		    (!(be32_to_cpu(new_drmem[i].flags) & DRCONF_MEM_ASSIGNED))) {
+		if ((old_lmb->flags & DRCONF_MEM_ASSIGNED) &&
+		    (!(new_lmb->flags & DRCONF_MEM_ASSIGNED))) {
 			rc = pseries_remove_memblock(
-				be64_to_cpu(old_drmem[i].base_addr),
-						     memblock_size);
+				old_lmb->base_addr, memblock_size);
 			break;
-		} else if ((!(be32_to_cpu(old_drmem[i].flags) &
-			    DRCONF_MEM_ASSIGNED)) &&
-			    (be32_to_cpu(new_drmem[i].flags) &
-			    DRCONF_MEM_ASSIGNED)) {
-			rc = memblock_add(be64_to_cpu(old_drmem[i].base_addr),
-					  memblock_size);
+		} else if ((!(old_lmb->flags & DRCONF_MEM_ASSIGNED)) &&
+			   (new_lmb->flags & DRCONF_MEM_ASSIGNED)) {
+			rc = memblock_add(old_lmb->base_addr,
+					memblock_size);
 			rc = (rc < 0) ? -EINVAL : 0;
 			break;
+		} else if ((old_lmb->aa_index != new_lmb->aa_index) &&
+			   (new_lmb->flags & DRCONF_MEM_ASSIGNED)) {
+			dlpar_queue_action(PSERIES_HP_ELOG_RESOURCE_MEM,
+					   PSERIES_HP_ELOG_ACTION_READD,
+					   new_lmb->drc_index);
 		}
 	}
 	return rc;
 }
 
+static void pseries_update_ala_memory_aai(int aa_index)
+{
+	struct drmem_lmb *lmb;
+
+	/* Readd all LMBs which were previously using the
+	 * specified aa_index value.
+	 */
+	for_each_drmem_lmb(lmb) {
+		if ((lmb->aa_index == aa_index) &&
+			(lmb->flags & DRCONF_MEM_ASSIGNED)) {
+			dlpar_queue_action(PSERIES_HP_ELOG_RESOURCE_MEM,
+					   PSERIES_HP_ELOG_ACTION_READD,
+					   lmb->drc_index);
+		}
+	}
+}
+
+struct assoc_arrays {
+	u32 n_arrays;
+	u32 array_sz;
+	const __be32 *arrays;
+};
+
+static int pseries_update_ala_memory(struct of_reconfig_data *pr)
+{
+	struct assoc_arrays new_ala, old_ala;
+	__be32 *p;
+	int i, lim;
+
+	if (rtas_hp_event)
+		return 0;
+
+	/*
+	 * The layout of the ibm,associativity-lookup-arrays
+	 * property is a number N indicating the number of
+	 * associativity arrays, followed by a number M
+	 * indicating the size of each associativity array,
+	 * followed by a list of N associativity arrays.
+	 */
+
+	p = (__be32 *) pr->old_prop->value;
+	if (!p)
+		return -EINVAL;
+	old_ala.n_arrays = of_read_number(p++, 1);
+	old_ala.array_sz = of_read_number(p++, 1);
+	old_ala.arrays = p;
+
+	p = (__be32 *) pr->prop->value;
+	if (!p)
+		return -EINVAL;
+	new_ala.n_arrays = of_read_number(p++, 1);
+	new_ala.array_sz = of_read_number(p++, 1);
+	new_ala.arrays = p;
+
+	lim = (new_ala.n_arrays > old_ala.n_arrays) ? old_ala.n_arrays :
+			new_ala.n_arrays;
+
+	if (old_ala.array_sz == new_ala.array_sz) {
+
+		/* Reset any entries where the old and new rows
+		 * the array have changed.
+		 */
+		for (i = 0; i < lim; i++) {
+			int index = (i * new_ala.array_sz);
+
+			if (!memcmp(&old_ala.arrays[index],
+				&new_ala.arrays[index],
+				new_ala.array_sz))
+				continue;
+
+			pseries_update_ala_memory_aai(i);
+		}
+
+		/* Reset any entries representing the extra rows.
+		 * There shouldn't be any, but just in case ...
+		 */
+		for (i = lim; i < new_ala.n_arrays; i++)
+			pseries_update_ala_memory_aai(i);
+
+	} else {
+		/* Update all entries representing these rows;
+		 * as all rows have different sizes, none can
+		 * have equivalent values.
+		 */
+		for (i = 0; i < lim; i++)
+			pseries_update_ala_memory_aai(i);
+	}
+
+	return 0;
+}
+
 static int pseries_memory_notifier(struct notifier_block *nb,
 				   unsigned long action, void *data)
 {
@@ -1059,8 +1139,17 @@  static int pseries_memory_notifier(struct notifier_block *nb,
 		err = pseries_remove_mem_node(rd->dn);
 		break;
 	case OF_RECONFIG_UPDATE_PROPERTY:
-		if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
-			err = pseries_update_drconf_memory(rd);
+		if (!strcmp(rd->prop->name, "ibm,dynamic-memory") ||
+		    !strcmp(rd->prop->name, "ibm,dynamic-memory-v2")) {
+			struct drmem_lmb_info *dinfo =
+				drmem_lmbs_init(rd->prop);
+			if (!dinfo)
+				return -EINVAL;
+			err = pseries_update_drconf_memory(dinfo);
+			drmem_lmbs_free(dinfo);
+		} else if (!strcmp(rd->prop->name,
+				"ibm,associativity-lookup-arrays"))
+			err = pseries_update_ala_memory(rd);
 		break;
 	}
 	return notifier_from_errno(err);