Checked my notes. I changed read_drconf_v1_cell/read_drconf_v2_cell to use of_read_number in place of dt_mem_next_cell, because the function is marked __init, and is not loaded in memory after a migration, so the system crashes. So, we need that modification, unless we also add some changes to kernel/drivers/of/fdt.c to the mix.
On 10/10/2018 12:34 PM, Michael Bringmann wrote: > On 10/10/2018 11:54 AM, Nathan Fontenot wrote: >> On 10/09/2018 03:36 PM, Michael Bringmann wrote: >>> powerpc/drmem: Export many of the functions of DRMEM to parse >>> "ibm,dynamic-memory" and "ibm,dynamic-memory-v2" during hotplug >>> operations and for Post Migration events. >>> >>> Also modify the DRMEM initialization code to allow it to, >>> >>> * Be called after system initialization >>> * Provide a separate user copy of the LMB array that is produces >>> * Free the user copy upon request >>> >>> In addition, a couple of changes were made to make the creation >>> of additional copies of the LMB array more useful including, >>> >>> * Add new iterator to work through a pair of drmem_info arrays. >>> * Modify DRMEM code to replace usages of dt_root_addr_cells, and >>> dt_mem_next_cell, as these are only available at first boot. >>> >>> Signed-off-by: Michael Bringmann <m...@linux.vnet.ibm.com> >>> --- >>> arch/powerpc/include/asm/drmem.h | 15 ++++++++ >>> arch/powerpc/mm/drmem.c | 75 >>> ++++++++++++++++++++++++++++---------- >>> 2 files changed, 70 insertions(+), 20 deletions(-) >>> >>> diff --git a/arch/powerpc/include/asm/drmem.h >>> b/arch/powerpc/include/asm/drmem.h >>> index 7c1d8e7..1fbb684 100644 >>> --- a/arch/powerpc/include/asm/drmem.h >>> +++ b/arch/powerpc/include/asm/drmem.h >>> @@ -35,6 +35,18 @@ struct drmem_lmb_info { >>> &drmem_info->lmbs[0], \ >>> &drmem_info->lmbs[drmem_info->n_lmbs - 1]) >>> >>> +#define for_each_dinfo_lmb(dinfo, lmb) \ >>> + for_each_drmem_lmb_in_range((lmb), \ >>> + &dinfo->lmbs[0], \ >>> + &dinfo->lmbs[dinfo->n_lmbs - 1]) >>> + >>> +#define for_each_pair_dinfo_lmb(dinfo1, lmb1, dinfo2, lmb2) \ >>> + for ((lmb1) = (&dinfo1->lmbs[0]), \ >>> + (lmb2) = (&dinfo2->lmbs[0]); \ >>> + ((lmb1) <= (&dinfo1->lmbs[dinfo1->n_lmbs - 1])) && \ >>> + ((lmb2) <= (&dinfo2->lmbs[dinfo2->n_lmbs - 1])); \ >>> + (lmb1)++, (lmb2)++) >>> + >> >> The macros for traversing seem to be getting a bit unwieldy with these >> updates. I wonder if we should move to just using walk routine >> for all traversing of the drmem lmbs. > > We can do that. One new routine + one API - several macros + 2 files changed. > >> >>> /* >>> * The of_drconf_cell_v1 struct defines the layout of the LMB data >>> * specified in the ibm,dynamic-memory device tree property. >>> @@ -94,6 +106,9 @@ void __init walk_drmem_lmbs(struct device_node *dn, >>> void (*func)(struct drmem_lmb *, const __be32 **)); >>> int drmem_update_dt(void); >>> >>> +struct drmem_lmb_info *drmem_lmbs_init(struct property *prop); >>> +void drmem_lmbs_free(struct drmem_lmb_info *dinfo); >>> + >>> #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 3f18036..13d2abb 100644 >>> --- a/arch/powerpc/mm/drmem.c >>> +++ b/arch/powerpc/mm/drmem.c >>> @@ -20,6 +20,7 @@ >>> >>> static struct drmem_lmb_info __drmem_info; >>> struct drmem_lmb_info *drmem_info = &__drmem_info; >>> +static int n_root_addr_cells; >>> >>> u64 drmem_lmb_memory_max(void) >>> { >>> @@ -193,12 +194,13 @@ 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; >>> >>> - lmb->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p); >>> + lmb->base_addr = of_read_number(p, n_root_addr_cells); >>> + p += n_root_addr_cells; >> >> Any reason this can't just be >> lmb->base_addr= dt_mem_next_cell(n_root_addr_cells, &p); > > Probably, not. I will rebuild/retest with this. > >> >>> lmb->drc_index = of_read_number(p++, 1); >>> >>> p++; /* skip reserved field */ >>> @@ -209,7 +211,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, >>> +static void __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm, >>> void (*func)(struct drmem_lmb *, const __be32 **)) >>> { >>> struct drmem_lmb lmb; >>> @@ -225,13 +227,14 @@ static void __init __walk_drmem_v1_lmbs(const __be32 >>> *prop, const __be32 *usm, >>> } >>> } >>> >>> -static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, >>> +static void read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, >>> const __be32 **prop) >>> { >>> const __be32 *p = *prop; >>> >>> dr_cell->seq_lmbs = of_read_number(p++, 1); >>> - dr_cell->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p); >>> + dr_cell->base_addr = of_read_number(p, n_root_addr_cells); >>> + p += n_root_addr_cells; >> >> Same here. > > Same. > >> >> -Nathan >> >>> dr_cell->drc_index = of_read_number(p++, 1); >>> dr_cell->aa_index = of_read_number(p++, 1); >>> dr_cell->flags = of_read_number(p++, 1); >>> @@ -239,7 +242,7 @@ static void __init read_drconf_v2_cell(struct >>> of_drconf_cell_v2 *dr_cell, >>> *prop = p; >>> } >>> >>> -static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 >>> *usm, >>> +static void __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm, >>> void (*func)(struct drmem_lmb *, const __be32 **)) >>> { >>> struct of_drconf_cell_v2 dr_cell; >>> @@ -275,6 +278,9 @@ void __init walk_drmem_lmbs_early(unsigned long node, >>> const __be32 *prop, *usm; >>> int len; >>> >>> + if (n_root_addr_cells == 0) >>> + n_root_addr_cells = dt_root_addr_cells; >>> + >>> prop = of_get_flat_dt_prop(node, "ibm,lmb-size", &len); >>> if (!prop || len < dt_root_size_cells * sizeof(__be32)) >>> return; >>> @@ -353,24 +359,26 @@ void __init walk_drmem_lmbs(struct device_node *dn, >>> } >>> } >>> >>> -static void __init init_drmem_v1_lmbs(const __be32 *prop) >>> +static void init_drmem_v1_lmbs(const __be32 *prop, >>> + struct drmem_lmb_info *dinfo) >>> { >>> struct drmem_lmb *lmb; >>>> - drmem_info->n_lmbs = of_read_number(prop++, 1); >>> - if (drmem_info->n_lmbs == 0) >>> + dinfo->n_lmbs = of_read_number(prop++, 1); >>> + if (dinfo->n_lmbs == 0) >>> return; >>> >>> - drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), >>> + dinfo->lmbs = kcalloc(dinfo->n_lmbs, sizeof(*lmb), >>> GFP_KERNEL); >>> - if (!drmem_info->lmbs) >>> + if (!dinfo->lmbs) >>> return; >>> >>> - for_each_drmem_lmb(lmb) >>> + for_each_dinfo_lmb(dinfo, lmb) >>> read_drconf_v1_cell(lmb, &prop); >>> } >>> >>> -static void __init init_drmem_v2_lmbs(const __be32 *prop) >>> +static void init_drmem_v2_lmbs(const __be32 *prop, >>> + struct drmem_lmb_info *dinfo) >>> { >>> struct drmem_lmb *lmb; >>> struct of_drconf_cell_v2 dr_cell; >>> @@ -386,12 +394,12 @@ static void __init init_drmem_v2_lmbs(const __be32 >>> *prop) >>> p = prop; >>> for (i = 0; i < lmb_sets; i++) { >>> read_drconf_v2_cell(&dr_cell, &p); >>> - drmem_info->n_lmbs += dr_cell.seq_lmbs; >>> + dinfo->n_lmbs += dr_cell.seq_lmbs; >>> } >>> >>> - drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), >>> + dinfo->lmbs = kcalloc(dinfo->n_lmbs, sizeof(*lmb), >>> GFP_KERNEL); >>> - if (!drmem_info->lmbs) >>> + if (!dinfo->lmbs) >>> return; >>> >>> /* second pass, read in the LMB information */ >>> @@ -402,10 +410,10 @@ static void __init init_drmem_v2_lmbs(const __be32 >>> *prop) >>> read_drconf_v2_cell(&dr_cell, &p); >>> >>> for (j = 0; j < dr_cell.seq_lmbs; j++) { >>> - lmb = &drmem_info->lmbs[lmb_index++]; >>> + lmb = &dinfo->lmbs[lmb_index++]; >>> >>> lmb->base_addr = dr_cell.base_addr; >>> - dr_cell.base_addr += drmem_info->lmb_size; >>> + dr_cell.base_addr += dinfo->lmb_size; >>> >>> lmb->drc_index = dr_cell.drc_index; >>> dr_cell.drc_index++; >>> @@ -416,11 +424,38 @@ static void __init init_drmem_v2_lmbs(const __be32 >>> *prop) >>> } >>> } >>> >>> +void drmem_lmbs_free(struct drmem_lmb_info *dinfo) >>> +{ >>> + if (dinfo) { >>> + kfree(dinfo->lmbs); >>> + kfree(dinfo); >>> + } >>> +} >>> + >>> +struct drmem_lmb_info *drmem_lmbs_init(struct property *prop) >>> +{ >>> + struct drmem_lmb_info *dinfo; >>> + >>> + dinfo = kzalloc(sizeof(*dinfo), GFP_KERNEL); >>> + if (!dinfo) >>> + return NULL; >>> + >>> + if (!strcmp("ibm,dynamic-memory", prop->name)) >>> + init_drmem_v1_lmbs(prop->value, dinfo); >>> + else if (!strcmp("ibm,dynamic-memory-v2", prop->name)) >>> + init_drmem_v2_lmbs(prop->value, dinfo); >>> + >>> + return dinfo; >>> +} >>> + >>> static int __init drmem_init(void) >>> { >>> struct device_node *dn; >>> const __be32 *prop; >>> >>> + if (n_root_addr_cells == 0) >>> + n_root_addr_cells = dt_root_addr_cells; >>> + >>> dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); >>> if (!dn) { >>> pr_info("No dynamic reconfiguration memory found\n"); >>> @@ -434,11 +469,11 @@ static int __init drmem_init(void) >>> >>> prop = of_get_property(dn, "ibm,dynamic-memory", NULL); >>> if (prop) { >>> - init_drmem_v1_lmbs(prop); >>> + init_drmem_v1_lmbs(prop, drmem_info); >>> } else { >>> prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL); >>> if (prop) >>> - init_drmem_v2_lmbs(prop); >>> + init_drmem_v2_lmbs(prop, drmem_info); >>> } >>> >>> of_node_put(dn); >>> >> >> > -- Michael W. Bringmann Linux Technology Center IBM Corporation Tie-Line 363-5196 External: (512) 286-5196 Cell: (512) 466-0650 m...@linux.vnet.ibm.com