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 <m...@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;
>>>
>>
> 

Reply via email to