aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/numa.c77
1 files changed, 61 insertions, 16 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index d9a181351332..be05457631d4 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -150,6 +150,21 @@ static const int *of_get_associativity(struct device_node *dev)
150 return of_get_property(dev, "ibm,associativity", NULL); 150 return of_get_property(dev, "ibm,associativity", NULL);
151} 151}
152 152
153/*
154 * Returns the property linux,drconf-usable-memory if
155 * it exists (the property exists only in kexec/kdump kernels,
156 * added by kexec-tools)
157 */
158static const u32 *of_get_usable_memory(struct device_node *memory)
159{
160 const u32 *prop;
161 u32 len;
162 prop = of_get_property(memory, "linux,drconf-usable-memory", &len);
163 if (!prop || len < sizeof(unsigned int))
164 return 0;
165 return prop;
166}
167
153/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa 168/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
154 * info is found. 169 * info is found.
155 */ 170 */
@@ -487,14 +502,29 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
487} 502}
488 503
489/* 504/*
505 * Reads the counter for a given entry in
506 * linux,drconf-usable-memory property
507 */
508static inline int __init read_usm_ranges(const u32 **usm)
509{
510 /*
511 * For each lmb in ibm,dynamic-memory a corresponding
512 * entry in linux,drconf-usable-memory property contains
513 * a counter followed by that many (base, size) duple.
514 * read the counter from linux,drconf-usable-memory
515 */
516 return read_n_cells(n_mem_size_cells, usm);
517}
518
519/*
490 * Extract NUMA information from the ibm,dynamic-reconfiguration-memory 520 * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
491 * node. This assumes n_mem_{addr,size}_cells have been set. 521 * node. This assumes n_mem_{addr,size}_cells have been set.
492 */ 522 */
493static void __init parse_drconf_memory(struct device_node *memory) 523static void __init parse_drconf_memory(struct device_node *memory)
494{ 524{
495 const u32 *dm; 525 const u32 *dm, *usm;
496 unsigned int n, rc; 526 unsigned int n, rc, ranges, is_kexec_kdump = 0;
497 unsigned long lmb_size, size; 527 unsigned long lmb_size, base, size, sz;
498 int nid; 528 int nid;
499 struct assoc_arrays aa; 529 struct assoc_arrays aa;
500 530
@@ -510,6 +540,11 @@ static void __init parse_drconf_memory(struct device_node *memory)
510 if (rc) 540 if (rc)
511 return; 541 return;
512 542
543 /* check if this is a kexec/kdump kernel */
544 usm = of_get_usable_memory(memory);
545 if (usm != NULL)
546 is_kexec_kdump = 1;
547
513 for (; n != 0; --n) { 548 for (; n != 0; --n) {
514 struct of_drconf_cell drmem; 549 struct of_drconf_cell drmem;
515 550
@@ -521,21 +556,31 @@ static void __init parse_drconf_memory(struct device_node *memory)
521 || !(drmem.flags & DRCONF_MEM_ASSIGNED)) 556 || !(drmem.flags & DRCONF_MEM_ASSIGNED))
522 continue; 557 continue;
523 558
524 nid = of_drconf_to_nid_single(&drmem, &aa); 559 base = drmem.base_addr;
560 size = lmb_size;
561 ranges = 1;
525 562
526 fake_numa_create_new_node( 563 if (is_kexec_kdump) {
527 ((drmem.base_addr + lmb_size) >> PAGE_SHIFT), 564 ranges = read_usm_ranges(&usm);
565 if (!ranges) /* there are no (base, size) duple */
566 continue;
567 }
568 do {
569 if (is_kexec_kdump) {
570 base = read_n_cells(n_mem_addr_cells, &usm);
571 size = read_n_cells(n_mem_size_cells, &usm);
572 }
573 nid = of_drconf_to_nid_single(&drmem, &aa);
574 fake_numa_create_new_node(
575 ((base + size) >> PAGE_SHIFT),
528 &nid); 576 &nid);
529 577 node_set_online(nid);
530 node_set_online(nid); 578 sz = numa_enforce_memory_limit(base, size);
531 579 if (sz)
532 size = numa_enforce_memory_limit(drmem.base_addr, lmb_size); 580 add_active_range(nid, base >> PAGE_SHIFT,
533 if (!size) 581 (base >> PAGE_SHIFT)
534 continue; 582 + (sz >> PAGE_SHIFT));
535 583 } while (--ranges);
536 add_active_range(nid, drmem.base_addr >> PAGE_SHIFT,
537 (drmem.base_addr >> PAGE_SHIFT)
538 + (size >> PAGE_SHIFT));
539 } 584 }
540} 585}
541 586