[RFC v2 3/3] postmigration/memory: Associativity & ibm,dynamic-memory-v2

Nathan Fontenot nfont at linux.vnet.ibm.com
Fri Apr 27 04:39:11 AEST 2018


On 04/24/2018 04:35 PM, Michael Bringmann wrote:
> See below.
> 
> On 04/24/2018 12:17 PM, Nathan Fontenot wrote:
>> On 02/26/2018 02:53 PM, Michael Bringmann wrote:
>>> postmigration/memory: Now apply changes to the associativity of memory
>>> blocks described by the 'ibm,dynamic-memory-v2' property regarding
>>> the topology of LPARS in Post Migration events.
>>>
>>> * Extend the previous work done for the 'ibm,associativity-lookup-array'
>>>   to apply to either property 'ibm,dynamic-memory' or
>>>   'ibm,dynamic-memory-v2', whichever is present.
>>> * Add new code to parse the 'ibm,dynamic-memory-v2' property looking
>>>   for differences in block 'assignment', associativity indexes per
>>>   block, and any other difference currently known.
>>> * Rewrite some of the original code to parse the 'ibm,dynamic-memory'
>>>   property to take advantage of LMB parsing code.
>>>
>>> When block differences are recognized, the memory block may be removed,
>>> added, or updated depending upon the state of the new device tree
>>> property and differences from the migrated value of the property.
>>>
>>
>> The only thing we need to check during LPM is affinity updates, memory
>> is not added or removed as part of LPM.
>>
>> I think a slightly different approach to this may be worth considering.
>> One of the goals of the drmem.c code was to remove the need to parse the
>> device tree for memory directly. For this update, I think we could modify
>> the code that builds the drmem_info data so that it can return a drmem_info
>> struct instead of assuming to set the global one.
>>
>> This change would allow you to do a straight compare on the global vs. the
>> new info from the updated device tree property. I think this would be cleaner
>> and may be able to use the same routine for V1 and V2 properties.
> 
> The code dealing with the 'ibm,associativity' array updated cleanly to use
> the same function to scan the LMBs regardless of the version of the properties.
> 
> The code dealing with changes to 'ibm,dynamic-memory-v2' is a mirror of the
> code in 'pseries_update_drconf_memory' that deals with changes to the property
> 'ibm,dynamic-memory', so it should also be updated.  On the other hand, do we
> need to consider the memory requirements of creating/cloning the drmem_info
> structure to provide a copy based on the new 'dynamic-memory' property?
> Or is this not an issue?

If done correctly, using the drmem code to create a drmem_info struct from
the new memory property would allow us to use the same comparison routine
for v1 and v2 versions of the property.

The size of the drmem_info data is not big enough to be concerned about
memory requirements when making a copy. 

-Nathan

> 
>>
>>> Signed-off-by: Michael Bringmann <mwb at linux.vnet.ibm.com>
>>> ---
>>> Changes in RFC v2:
>>>   -- Reuse existing parser code from 'drmem.c' in parsing property
>>>      'imb,dynamic-memory-v2' for migration.
>>>   -- Fix crash during migration that occurs on non-VPHN systems
>>>      when attempting to reset topology timer.
>>>   -- Change section of a support function + variable from __init 
>>>      to normal runtime to make them visible to migration code.
>>> ---
>>>  arch/powerpc/include/asm/drmem.h                |    8 +
>>>  arch/powerpc/mm/drmem.c                         |   23 ++-
>>>  arch/powerpc/mm/numa.c                          |    3 
>>>  arch/powerpc/platforms/pseries/hotplug-memory.c |  175 +++++++++++++++++++----
>>>  drivers/of/fdt.c                                |    4 -
>>>  include/linux/of_fdt.h                          |    2 
>>>  6 files changed, 170 insertions(+), 45 deletions(-)
>>>
>>> diff --git a/arch/powerpc/include/asm/drmem.h b/arch/powerpc/include/asm/drmem.h
>>> index 47a7012..e4773c9 100644
>>> --- a/arch/powerpc/include/asm/drmem.h
>>> +++ b/arch/powerpc/include/asm/drmem.h
>>> @@ -92,6 +92,14 @@ void __init walk_drmem_lmbs(struct device_node *dn,
>>>  			void (*func)(struct drmem_lmb *, const __be32 **));
>>>  int drmem_update_dt(void);
>>>
>>> +void walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *data,
>>> +			void (*func)(struct drmem_lmb *, const __be32 **));
>>> +
>>> +void read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
>>> +			const __be32 **prop);
>>> +void walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *data,
>>> +			void (*func)(struct drmem_lmb *, const __be32 **));
>>> +
>>>  #ifdef CONFIG_PPC_PSERIES
>>>  void __init walk_drmem_lmbs_early(unsigned long node,
>>>  			void (*func)(struct drmem_lmb *, const __be32 **));
>>> diff --git a/arch/powerpc/mm/drmem.c b/arch/powerpc/mm/drmem.c
>>> index 31dbe14..e47a6e0 100644
>>> --- a/arch/powerpc/mm/drmem.c
>>> +++ b/arch/powerpc/mm/drmem.c
>>> @@ -192,7 +192,7 @@ int drmem_update_dt(void)
>>>  	return rc;
>>>  }
>>>
>>> -static void __init read_drconf_v1_cell(struct drmem_lmb *lmb,
>>> +static void read_drconf_v1_cell(struct drmem_lmb *lmb,
>>>  				       const __be32 **prop)
>>>  {
>>>  	const __be32 *p = *prop;
>>> @@ -208,7 +208,7 @@ static void __init read_drconf_v1_cell(struct drmem_lmb *lmb,
>>>  	*prop = p;
>>>  }
>>>
>>> -static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm,
>>> +void walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *data,
>>>  			void (*func)(struct drmem_lmb *, const __be32 **))
>>>  {
>>>  	struct drmem_lmb lmb;
>>> @@ -218,11 +218,12 @@ static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm,
>>>
>>>  	for (i = 0; i < n_lmbs; i++) {
>>>  		read_drconf_v1_cell(&lmb, &prop);
>>> -		func(&lmb, &usm);
>>> +		func(&lmb, &data);
>>>  	}
>>>  }
>>> +EXPORT_SYMBOL(walk_drmem_v1_lmbs);
>>>
>>> -static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
>>> +void read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
>>>  				       const __be32 **prop)
>>>  {
>>>  	const __be32 *p = *prop;
>>> @@ -235,8 +236,9 @@ static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
>>>
>>>  	*prop = p;
>>>  }
>>> +EXPORT_SYMBOL(read_drconf_v2_cell);
>>>
>>> -static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
>>> +void walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *data,
>>>  			void (*func)(struct drmem_lmb *, const __be32 **))
>>>  {
>>>  	struct of_drconf_cell_v2 dr_cell;
>>> @@ -258,10 +260,11 @@ static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
>>>  			lmb.aa_index = dr_cell.aa_index;
>>>  			lmb.flags = dr_cell.flags;
>>>
>>> -			func(&lmb, &usm);
>>> +			func(&lmb, &data);
>>>  		}
>>>  	}
>>>  }
>>> +EXPORT_SYMBOL(walk_drmem_v2_lmbs);
>>>
>>>  #ifdef CONFIG_PPC_PSERIES
>>>  void __init walk_drmem_lmbs_early(unsigned long node,
>>> @@ -280,12 +283,12 @@ void __init walk_drmem_lmbs_early(unsigned long node,
>>>
>>>  	prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &len);
>>>  	if (prop) {
>>> -		__walk_drmem_v1_lmbs(prop, usm, func);
>>> +		walk_drmem_v1_lmbs(prop, usm, func);
>>>  	} else {
>>>  		prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2",
>>>  					   &len);
>>>  		if (prop)
>>> -			__walk_drmem_v2_lmbs(prop, usm, func);
>>> +			walk_drmem_v2_lmbs(prop, usm, func);
>>>  	}
>>>
>>>  	memblock_dump_all();
>>> @@ -340,11 +343,11 @@ void __init walk_drmem_lmbs(struct device_node *dn,
>>>
>>>  	prop = of_get_property(dn, "ibm,dynamic-memory", NULL);
>>>  	if (prop) {
>>> -		__walk_drmem_v1_lmbs(prop, usm, func);
>>> +		walk_drmem_v1_lmbs(prop, usm, func);
>>>  	} else {
>>>  		prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL);
>>>  		if (prop)
>>> -			__walk_drmem_v2_lmbs(prop, usm, func);
>>> +			walk_drmem_v2_lmbs(prop, usm, func);
>>>  	}
>>>  }
>>>
>>> diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
>>> index 0e573f9..2545fea 100644
>>> --- a/arch/powerpc/mm/numa.c
>>> +++ b/arch/powerpc/mm/numa.c
>>> @@ -1395,7 +1395,8 @@ static void topology_timer_fn(struct timer_list *unused)
>>>
>>>  static void reset_topology_timer(void)
>>>  {
>>> -	mod_timer(&topology_timer, jiffies + topology_timer_secs * HZ);
>>> +	if (vphn_enabled)
>>> +		mod_timer(&topology_timer, jiffies + topology_timer_secs * HZ);
>>
>> This really looks like a bug fix that should be in a different patch.
> 
> Okay.
> 
>>
>> -Nathan
> 
> Thanks.
> Michael
> 
>>
>>>  }
>>>
>>>  #ifdef CONFIG_SMP
>>> diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
>>> index b63181d..bf717e2 100644
>>> --- a/arch/powerpc/platforms/pseries/hotplug-memory.c
>>> +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
>>> @@ -1051,49 +1051,155 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
>>>  	return rc;
>>>  }
>>>
>>> -struct assoc_arrays {
>>> -	u32 n_arrays;
>>> -	u32 array_sz;
>>> -	const __be32 *arrays;
>>> -};
>>> +static inline int pseries_memory_v2_find_drc(u32 drc_index,
>>> +			u64 *base_addr, unsigned long memblock_size,
>>> +			struct of_drconf_cell_v2 *dm)
>>> +{
>>> +	if ((dm->drc_index <= drc_index) &&
>>> +		(drc_index <= (dm->drc_index + dm->seq_lmbs - 1))) {
>>> +		int offset = drc_index - dm->drc_index;
>>> +
>>> +		(*base_addr) = dm->base_addr +
>>> +				(offset * memblock_size);
>>> +	} else if (drc_index > (dm->drc_index +
>>> +				dm->seq_lmbs - 1)) {
>>> +		return -1;
>>> +	} else if (dm->drc_index > drc_index) {
>>> +		return -1;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>>
>>> -static int pseries_update_ala_memory_aai(int aa_index,
>>> -					struct property *dmprop)
>>> +static int pseries_update_drconf_memory_v2(struct of_reconfig_data *pr)
>>>  {
>>> -	struct of_drconf_cell *drmem;
>>> -	u32 entries;
>>> -	__be32 *p;
>>> -	int i;
>>> -	int rc = 0;
>>> +	const __be32 *new_drmem, *old_drmem;
>>> +	unsigned long memblock_size;
>>> +	u32 new_lmb_sets, old_lmb_sets;
>>> +	u64 old_base_addr;
>>> +	int i, rc = 0;
>>>
>>> -	p = (__be32 *) dmprop->value;
>>> -	if (!p)
>>> +	if (rtas_hp_event)
>>> +		return 0;
>>> +
>>> +	memblock_size = pseries_memory_block_size();
>>> +	if (!memblock_size)
>>>  		return -EINVAL;
>>>
>>>  	/* 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.
>>> +	 * of of_drconf_cell_v2 entries. Get the number of entries
>>> +	 * and skip to the array of of_drconf_cell_v2's.
>>>  	 */
>>> -	entries = be32_to_cpu(*p++);
>>> -	drmem = (struct of_drconf_cell *)p;
>>> +	old_drmem = (__be32 *) pr->old_prop->value;
>>> +	if (!old_drmem)
>>> +		return -EINVAL;
>>> +	old_lmb_sets = of_read_number(old_drmem++, 1);
>>>
>>> -	for (i = 0; i < entries; i++) {
>>> -		if ((be32_to_cpu(drmem[i].aa_index) != aa_index) &&
>>> -			(be32_to_cpu(drmem[i].flags) & DRCONF_MEM_ASSIGNED)) {
>>> -			rc = dlpar_memory_readd_by_index(
>>> -				be32_to_cpu(drmem[i].drc_index));
>>> +	new_drmem = (__be32 *)pr->prop->value;
>>> +	new_lmb_sets = of_read_number(new_drmem++, 1);
>>> +
>>> +	for (i = 0; i < old_lmb_sets; i++) {
>>> +		int j;
>>> +		struct of_drconf_cell_v2 old_cell, new_cell;
>>> +
>>> +		read_drconf_v2_cell(&old_cell, &old_drmem);
>>> +		read_drconf_v2_cell(&new_cell, &new_drmem);
>>> +
>>> +		for (j = 0; j < new_cell.seq_lmbs; j++) {
>>> +			if (pseries_memory_v2_find_drc(
>>> +				new_cell.drc_index + j,
>>> +				&old_base_addr,
>>> +				memblock_size,
>>> +				&old_cell))
>>> +				continue;
>>> +
>>> +			if ((old_cell.flags &
>>> +					DRCONF_MEM_ASSIGNED) &&
>>> +			    (!(new_cell.flags &
>>> +					DRCONF_MEM_ASSIGNED))) {
>>> +				rc = pseries_remove_memblock(
>>> +					old_base_addr,
>>> +					memblock_size);
>>> +			} else if ((!(old_cell.flags &
>>> +					DRCONF_MEM_ASSIGNED)) &&
>>> +				   (new_cell.flags &
>>> +					DRCONF_MEM_ASSIGNED)) {
>>> +				rc = memblock_add(
>>> +					old_base_addr, memblock_size);
>>> +			} else if ((old_cell.aa_index !=
>>> +				    new_cell.aa_index) &&
>>> +				   (new_cell.flags &
>>> +					DRCONF_MEM_ASSIGNED)) {
>>> +				dlpar_memory_readd_by_index(
>>> +					new_cell.drc_index + j);
>>> +			}
>>>  		}
>>>  	}
>>>
>>> -	return rc;
>>> +	return 0;
>>> +}
>>> +
>>> +struct assoc_arrays {
>>> +	u32 n_arrays;
>>> +	u32 array_sz;
>>> +	const __be32 *arrays;
>>> +};
>>> +
>>> +struct update_ala_memory_aai_struct {
>>> +	int aa_index;
>>> +};
>>> +
>>> +static void update_ala_memory_aai_cb(struct drmem_lmb *lmb,
>>> +					const __be32 **data)
>>> +{
>>> +	struct update_ala_memory_aai_struct *updt =
>>> +		(struct update_ala_memory_aai_struct *)*data;
>>> +
>>> +	if ((lmb->aa_index != updt->aa_index) &&
>>> +		(lmb->flags & DRCONF_MEM_ASSIGNED))
>>> +		dlpar_memory_readd_by_index(lmb->drc_index);
>>> +}
>>> +
>>> +static int pseries_update_ala_memory_aai_v1(int aa_index,
>>> +				const __be32 *dmprop)
>>> +{
>>> +	struct update_ala_memory_aai_struct data = {
>>> +		aa_index };
>>> +
>>> +	walk_drmem_v1_lmbs(dmprop, (const __be32 *)&data,
>>> +			update_ala_memory_aai_cb);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int pseries_update_ala_memory_aai_v2(int aa_index,
>>> +				const __be32 *dmprop)
>>> +{
>>> +	struct update_ala_memory_aai_struct data = {
>>> +		aa_index };
>>> +
>>> +	walk_drmem_v2_lmbs(dmprop, (const __be32 *)&data,
>>> +			update_ala_memory_aai_cb);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int pseries_update_ala_memory_aai(int v1, int aa_index,
>>> +				const __be32 *dmprop)
>>> +{
>>> +	if (v1)
>>> +		return pseries_update_ala_memory_aai_v1(aa_index, dmprop);
>>> +	else
>>> +		return pseries_update_ala_memory_aai_v2(aa_index, dmprop);
>>>  }
>>>
>>>  static int pseries_update_ala_memory(struct of_reconfig_data *pr)
>>>  {
>>>  	struct assoc_arrays new_ala, old_ala;
>>>  	struct device_node *dn;
>>> -	struct property *dmprop;
>>> +	const __be32 *dmprop;
>>> +	bool v1 = true;
>>>  	__be32 *p;
>>>  	int i, lim;
>>>
>>> @@ -1104,10 +1210,15 @@ static int pseries_update_ala_memory(struct of_reconfig_data *pr)
>>>  	if (!dn)
>>>  		return -ENODEV;
>>>
>>> -	dmprop = of_find_property(dn, "ibm,dynamic-memory", NULL);
>>> +	dmprop = of_get_property(dn, "ibm,dynamic-memory", NULL);
>>>  	if (!dmprop) {
>>> -		of_node_put(dn);
>>> -		return -ENODEV;
>>> +		v1 = false;
>>> +		dmprop = of_get_property(dn, "ibm,dynamic-memory-v2",
>>> +					NULL);
>>> +		if (!dmprop) {
>>> +			of_node_put(dn);
>>> +			return -ENODEV;
>>> +		}
>>>  	}
>>>
>>>  	/*
>>> @@ -1149,11 +1260,11 @@ static int pseries_update_ala_memory(struct of_reconfig_data *pr)
>>>  						new_ala.array_sz))
>>>  				continue;
>>>
>>> -			pseries_update_ala_memory_aai(i, dmprop);
>>> +			pseries_update_ala_memory_aai(v1, i, dmprop);
>>>  		}
>>>
>>>  		for (i = lim; i < new_ala.n_arrays; i++)
>>> -			pseries_update_ala_memory_aai(i, dmprop);
>>> +			pseries_update_ala_memory_aai(v1, i, dmprop);
>>>
>>>  	} else {
>>>  		/* Update all entries representing these rows;
>>> @@ -1161,7 +1272,7 @@ static int pseries_update_ala_memory(struct of_reconfig_data *pr)
>>>  		 * have equivalent values.
>>>  		 */
>>>  		for (i = 0; i < lim; i++)
>>> -			pseries_update_ala_memory_aai(i, dmprop);
>>> +			pseries_update_ala_memory_aai(v1, i, dmprop);
>>>  	}
>>>
>>>  	of_node_put(dn);
>>> @@ -1184,6 +1295,8 @@ static int pseries_memory_notifier(struct notifier_block *nb,
>>>  	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-v2"))
>>> +			err = pseries_update_drconf_memory_v2(rd);
>>>  		if (!strcmp(rd->prop->name,
>>>  				"ibm,associativity-lookup-arrays"))
>>>  			err = pseries_update_ala_memory(rd);
>>> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>>> index 4675e5a..00df576 100644
>>> --- a/drivers/of/fdt.c
>>> +++ b/drivers/of/fdt.c
>>> @@ -539,7 +539,7 @@ void *of_fdt_unflatten_tree(const unsigned long *blob,
>>>  EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
>>>
>>>  /* Everything below here references initial_boot_params directly. */
>>> -int __initdata dt_root_addr_cells;
>>> +int dt_root_addr_cells;
>>>  int __initdata dt_root_size_cells;
>>>
>>>  void *initial_boot_params;
>>> @@ -1013,7 +1013,7 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname,
>>>  	return 1;
>>>  }
>>>
>>> -u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
>>> +u64 dt_mem_next_cell(int s, const __be32 **cellp)
>>>  {
>>>  	const __be32 *p = *cellp;
>>>
>>> diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
>>> index 013c541..14c8681 100644
>>> --- a/include/linux/of_fdt.h
>>> +++ b/include/linux/of_fdt.h
>>> @@ -40,7 +40,7 @@ extern void *of_fdt_unflatten_tree(const unsigned long *blob,
>>>  				   struct device_node **mynodes);
>>>
>>>  /* TBD: Temporary export of fdt globals - remove when code fully merged */
>>> -extern int __initdata dt_root_addr_cells;
>>> +extern int dt_root_addr_cells;
>>>  extern int __initdata dt_root_size_cells;
>>>  extern void *initial_boot_params;
>>>
>>
> 



More information about the Linuxppc-dev mailing list