aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorChandru <chandru@in.ibm.com>2008-08-29 10:28:16 -0400
committerPaul Mackerras <paulus@samba.org>2008-09-15 14:07:58 -0400
commitcf00085d8045cddd80a8aabad97de96fa8131793 (patch)
tree22bc2935d93709ed6ae229b5737c5412cfaf5991 /arch/powerpc/mm
parent525c411d400603665f8416f7e84bb14a43830027 (diff)
powerpc: Add support for dynamic reconfiguration memory in kexec/kdump kernels
Kdump kernel needs to use only those memory regions that it is allowed to use (crashkernel, rtas, tce, etc.). Each of these regions have their own sizes and are currently added under 'linux,usable-memory' property under each memory@xxx node of the device tree. The ibm,dynamic-memory property of ibm,dynamic-reconfiguration-memory node (on POWER6) now stores in it the representation for most of the logical memory blocks with the size of each memory block being a constant (lmb_size). If one or more or part of the above mentioned regions lie under one of the lmb from ibm,dynamic-memory property, there is a need to identify those regions within the given lmb. This makes the kernel recognize a new 'linux,drconf-usable-memory' property added by kexec-tools. Each entry in this property is of the form of a count followed by that many (base, size) pairs for the above mentioned regions. The number of cells in the count value is given by the #size-cells property of the root node. Signed-off-by: Chandru Siddalingappa <chandru@in.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
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