Skip to content

Commit adfefc6

Browse files
hbathinimpe
authored andcommitted
powerpc/drmem: Make LMB walk a bit more flexible
Currently, numa & prom are the only users of drmem LMB walk code. Loading kdump with kexec_file also needs to walk the drmem LMBs to setup the usable memory ranges for kdump kernel. But there are couple of issues in using the code as is. One, walk_drmem_lmb() code is built into the .init section currently, while kexec_file needs it later. Two, there is no scope to pass data to the callback function for processing and/or erroring out on certain conditions. Fix that by, moving drmem LMB walk code out of .init section, adding scope to pass data to the callback function and bailing out when an error is encountered in the callback function. Signed-off-by: Hari Bathini <[email protected]> Tested-by: Pingfan Liu <[email protected]> Reviewed-by: Thiago Jung Bauermann <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/159602282727.575379.3979857013827701828.stgit@hbathini
1 parent b8e55a3 commit adfefc6

File tree

4 files changed

+78
-44
lines changed

4 files changed

+78
-44
lines changed

arch/powerpc/include/asm/drmem.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,14 @@ static inline bool drmem_lmb_reserved(struct drmem_lmb *lmb)
9090
}
9191

9292
u64 drmem_lmb_memory_max(void);
93-
void __init walk_drmem_lmbs(struct device_node *dn,
94-
void (*func)(struct drmem_lmb *, const __be32 **));
93+
int walk_drmem_lmbs(struct device_node *dn, void *data,
94+
int (*func)(struct drmem_lmb *, const __be32 **, void *));
9595
int drmem_update_dt(void);
9696

9797
#ifdef CONFIG_PPC_PSERIES
98-
void __init walk_drmem_lmbs_early(unsigned long node,
99-
void (*func)(struct drmem_lmb *, const __be32 **));
98+
int __init
99+
walk_drmem_lmbs_early(unsigned long node, void *data,
100+
int (*func)(struct drmem_lmb *, const __be32 **, void *));
100101
#endif
101102

102103
static inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb)

arch/powerpc/kernel/prom.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,8 +470,9 @@ static bool validate_mem_limit(u64 base, u64 *size)
470470
* This contains a list of memory blocks along with NUMA affinity
471471
* information.
472472
*/
473-
static void __init early_init_drmem_lmb(struct drmem_lmb *lmb,
474-
const __be32 **usm)
473+
static int __init early_init_drmem_lmb(struct drmem_lmb *lmb,
474+
const __be32 **usm,
475+
void *data)
475476
{
476477
u64 base, size;
477478
int is_kexec_kdump = 0, rngs;
@@ -486,7 +487,7 @@ static void __init early_init_drmem_lmb(struct drmem_lmb *lmb,
486487
*/
487488
if ((lmb->flags & DRCONF_MEM_RESERVED) ||
488489
!(lmb->flags & DRCONF_MEM_ASSIGNED))
489-
return;
490+
return 0;
490491

491492
if (*usm)
492493
is_kexec_kdump = 1;
@@ -501,7 +502,7 @@ static void __init early_init_drmem_lmb(struct drmem_lmb *lmb,
501502
*/
502503
rngs = dt_mem_next_cell(dt_root_size_cells, usm);
503504
if (!rngs) /* there are no (base, size) duple */
504-
return;
505+
return 0;
505506
}
506507

507508
do {
@@ -526,6 +527,8 @@ static void __init early_init_drmem_lmb(struct drmem_lmb *lmb,
526527
if (lmb->flags & DRCONF_MEM_HOTREMOVABLE)
527528
memblock_mark_hotplug(base, size);
528529
} while (--rngs);
530+
531+
return 0;
529532
}
530533
#endif /* CONFIG_PPC_PSERIES */
531534

@@ -536,7 +539,7 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node,
536539
#ifdef CONFIG_PPC_PSERIES
537540
if (depth == 1 &&
538541
strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) {
539-
walk_drmem_lmbs_early(node, early_init_drmem_lmb);
542+
walk_drmem_lmbs_early(node, NULL, early_init_drmem_lmb);
540543
return 0;
541544
}
542545
#endif

arch/powerpc/mm/drmem.c

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <asm/prom.h>
1515
#include <asm/drmem.h>
1616

17+
static int n_root_addr_cells, n_root_size_cells;
18+
1719
static struct drmem_lmb_info __drmem_info;
1820
struct drmem_lmb_info *drmem_info = &__drmem_info;
1921

@@ -189,12 +191,13 @@ int drmem_update_dt(void)
189191
return rc;
190192
}
191193

192-
static void __init read_drconf_v1_cell(struct drmem_lmb *lmb,
194+
static void read_drconf_v1_cell(struct drmem_lmb *lmb,
193195
const __be32 **prop)
194196
{
195197
const __be32 *p = *prop;
196198

197-
lmb->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p);
199+
lmb->base_addr = of_read_number(p, n_root_addr_cells);
200+
p += n_root_addr_cells;
198201
lmb->drc_index = of_read_number(p++, 1);
199202

200203
p++; /* skip reserved field */
@@ -205,47 +208,50 @@ static void __init read_drconf_v1_cell(struct drmem_lmb *lmb,
205208
*prop = p;
206209
}
207210

208-
static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm,
209-
void (*func)(struct drmem_lmb *, const __be32 **))
211+
static int
212+
__walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm, void *data,
213+
int (*func)(struct drmem_lmb *, const __be32 **, void *))
210214
{
211215
struct drmem_lmb lmb;
212216
u32 i, n_lmbs;
217+
int ret = 0;
213218

214219
n_lmbs = of_read_number(prop++, 1);
215-
if (n_lmbs == 0)
216-
return;
217-
218220
for (i = 0; i < n_lmbs; i++) {
219221
read_drconf_v1_cell(&lmb, &prop);
220-
func(&lmb, &usm);
222+
ret = func(&lmb, &usm, data);
223+
if (ret)
224+
break;
221225
}
226+
227+
return ret;
222228
}
223229

224-
static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
230+
static void read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
225231
const __be32 **prop)
226232
{
227233
const __be32 *p = *prop;
228234

229235
dr_cell->seq_lmbs = of_read_number(p++, 1);
230-
dr_cell->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p);
236+
dr_cell->base_addr = of_read_number(p, n_root_addr_cells);
237+
p += n_root_addr_cells;
231238
dr_cell->drc_index = of_read_number(p++, 1);
232239
dr_cell->aa_index = of_read_number(p++, 1);
233240
dr_cell->flags = of_read_number(p++, 1);
234241

235242
*prop = p;
236243
}
237244

238-
static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
239-
void (*func)(struct drmem_lmb *, const __be32 **))
245+
static int
246+
__walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm, void *data,
247+
int (*func)(struct drmem_lmb *, const __be32 **, void *))
240248
{
241249
struct of_drconf_cell_v2 dr_cell;
242250
struct drmem_lmb lmb;
243251
u32 i, j, lmb_sets;
252+
int ret = 0;
244253

245254
lmb_sets = of_read_number(prop++, 1);
246-
if (lmb_sets == 0)
247-
return;
248-
249255
for (i = 0; i < lmb_sets; i++) {
250256
read_drconf_v2_cell(&dr_cell, &prop);
251257

@@ -259,42 +265,51 @@ static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
259265
lmb.aa_index = dr_cell.aa_index;
260266
lmb.flags = dr_cell.flags;
261267

262-
func(&lmb, &usm);
268+
ret = func(&lmb, &usm, data);
269+
if (ret)
270+
break;
263271
}
264272
}
273+
274+
return ret;
265275
}
266276

267277
#ifdef CONFIG_PPC_PSERIES
268-
void __init walk_drmem_lmbs_early(unsigned long node,
269-
void (*func)(struct drmem_lmb *, const __be32 **))
278+
int __init walk_drmem_lmbs_early(unsigned long node, void *data,
279+
int (*func)(struct drmem_lmb *, const __be32 **, void *))
270280
{
271281
const __be32 *prop, *usm;
272-
int len;
282+
int len, ret = -ENODEV;
273283

274284
prop = of_get_flat_dt_prop(node, "ibm,lmb-size", &len);
275285
if (!prop || len < dt_root_size_cells * sizeof(__be32))
276-
return;
286+
return ret;
287+
288+
/* Get the address & size cells */
289+
n_root_addr_cells = dt_root_addr_cells;
290+
n_root_size_cells = dt_root_size_cells;
277291

278292
drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop);
279293

280294
usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory", &len);
281295

282296
prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &len);
283297
if (prop) {
284-
__walk_drmem_v1_lmbs(prop, usm, func);
298+
ret = __walk_drmem_v1_lmbs(prop, usm, data, func);
285299
} else {
286300
prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2",
287301
&len);
288302
if (prop)
289-
__walk_drmem_v2_lmbs(prop, usm, func);
303+
ret = __walk_drmem_v2_lmbs(prop, usm, data, func);
290304
}
291305

292306
memblock_dump_all();
307+
return ret;
293308
}
294309

295310
#endif
296311

297-
static int __init init_drmem_lmb_size(struct device_node *dn)
312+
static int init_drmem_lmb_size(struct device_node *dn)
298313
{
299314
const __be32 *prop;
300315
int len;
@@ -303,12 +318,12 @@ static int __init init_drmem_lmb_size(struct device_node *dn)
303318
return 0;
304319

305320
prop = of_get_property(dn, "ibm,lmb-size", &len);
306-
if (!prop || len < dt_root_size_cells * sizeof(__be32)) {
321+
if (!prop || len < n_root_size_cells * sizeof(__be32)) {
307322
pr_info("Could not determine LMB size\n");
308323
return -1;
309324
}
310325

311-
drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop);
326+
drmem_info->lmb_size = of_read_number(prop, n_root_size_cells);
312327
return 0;
313328
}
314329

@@ -329,24 +344,36 @@ static const __be32 *of_get_usable_memory(struct device_node *dn)
329344
return prop;
330345
}
331346

332-
void __init walk_drmem_lmbs(struct device_node *dn,
333-
void (*func)(struct drmem_lmb *, const __be32 **))
347+
int walk_drmem_lmbs(struct device_node *dn, void *data,
348+
int (*func)(struct drmem_lmb *, const __be32 **, void *))
334349
{
335350
const __be32 *prop, *usm;
351+
int ret = -ENODEV;
352+
353+
if (!of_root)
354+
return ret;
355+
356+
/* Get the address & size cells */
357+
of_node_get(of_root);
358+
n_root_addr_cells = of_n_addr_cells(of_root);
359+
n_root_size_cells = of_n_size_cells(of_root);
360+
of_node_put(of_root);
336361

337362
if (init_drmem_lmb_size(dn))
338-
return;
363+
return ret;
339364

340365
usm = of_get_usable_memory(dn);
341366

342367
prop = of_get_property(dn, "ibm,dynamic-memory", NULL);
343368
if (prop) {
344-
__walk_drmem_v1_lmbs(prop, usm, func);
369+
ret = __walk_drmem_v1_lmbs(prop, usm, data, func);
345370
} else {
346371
prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL);
347372
if (prop)
348-
__walk_drmem_v2_lmbs(prop, usm, func);
373+
ret = __walk_drmem_v2_lmbs(prop, usm, data, func);
349374
}
375+
376+
return ret;
350377
}
351378

352379
static void __init init_drmem_v1_lmbs(const __be32 *prop)

arch/powerpc/mm/numa.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -645,8 +645,9 @@ static inline int __init read_usm_ranges(const __be32 **usm)
645645
* Extract NUMA information from the ibm,dynamic-reconfiguration-memory
646646
* node. This assumes n_mem_{addr,size}_cells have been set.
647647
*/
648-
static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
649-
const __be32 **usm)
648+
static int __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
649+
const __be32 **usm,
650+
void *data)
650651
{
651652
unsigned int ranges, is_kexec_kdump = 0;
652653
unsigned long base, size, sz;
@@ -658,7 +659,7 @@ static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
658659
*/
659660
if ((lmb->flags & DRCONF_MEM_RESERVED)
660661
|| !(lmb->flags & DRCONF_MEM_ASSIGNED))
661-
return;
662+
return 0;
662663

663664
if (*usm)
664665
is_kexec_kdump = 1;
@@ -670,7 +671,7 @@ static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
670671
if (is_kexec_kdump) {
671672
ranges = read_usm_ranges(usm);
672673
if (!ranges) /* there are no (base, size) duple */
673-
return;
674+
return 0;
674675
}
675676

676677
do {
@@ -687,6 +688,8 @@ static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
687688
if (sz)
688689
memblock_set_node(base, sz, &memblock.memory, nid);
689690
} while (--ranges);
691+
692+
return 0;
690693
}
691694

692695
static int __init parse_numa_properties(void)
@@ -788,7 +791,7 @@ static int __init parse_numa_properties(void)
788791
*/
789792
memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
790793
if (memory) {
791-
walk_drmem_lmbs(memory, numa_setup_drmem_lmb);
794+
walk_drmem_lmbs(memory, NULL, numa_setup_drmem_lmb);
792795
of_node_put(memory);
793796
}
794797

0 commit comments

Comments
 (0)