aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/powerpc/kernel/prom.c40
-rw-r--r--arch/powerpc/mm/numa.c77
2 files changed, 95 insertions, 22 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 87d83c56b31e..09455e1c27c5 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -888,9 +888,10 @@ static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
888 */ 888 */
889static int __init early_init_dt_scan_drconf_memory(unsigned long node) 889static int __init early_init_dt_scan_drconf_memory(unsigned long node)
890{ 890{
891 cell_t *dm, *ls; 891 cell_t *dm, *ls, *usm;
892 unsigned long l, n, flags; 892 unsigned long l, n, flags;
893 u64 base, size, lmb_size; 893 u64 base, size, lmb_size;
894 unsigned int is_kexec_kdump = 0, rngs;
894 895
895 ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l); 896 ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
896 if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t)) 897 if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
@@ -905,6 +906,12 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
905 if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t)) 906 if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
906 return 0; 907 return 0;
907 908
909 /* check if this is a kexec/kdump kernel. */
910 usm = (cell_t *)of_get_flat_dt_prop(node, "linux,drconf-usable-memory",
911 &l);
912 if (usm != NULL)
913 is_kexec_kdump = 1;
914
908 for (; n != 0; --n) { 915 for (; n != 0; --n) {
909 base = dt_mem_next_cell(dt_root_addr_cells, &dm); 916 base = dt_mem_next_cell(dt_root_addr_cells, &dm);
910 flags = dm[3]; 917 flags = dm[3];
@@ -915,13 +922,34 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
915 if ((flags & 0x80) || !(flags & 0x8)) 922 if ((flags & 0x80) || !(flags & 0x8))
916 continue; 923 continue;
917 size = lmb_size; 924 size = lmb_size;
918 if (iommu_is_off) { 925 rngs = 1;
919 if (base >= 0x80000000ul) 926 if (is_kexec_kdump) {
927 /*
928 * For each lmb in ibm,dynamic-memory, a corresponding
929 * entry in linux,drconf-usable-memory property contains
930 * a counter 'p' followed by 'p' (base, size) duple.
931 * Now read the counter from
932 * linux,drconf-usable-memory property
933 */
934 rngs = dt_mem_next_cell(dt_root_size_cells, &usm);
935 if (!rngs) /* there are no (base, size) duple */
920 continue; 936 continue;
921 if ((base + size) > 0x80000000ul)
922 size = 0x80000000ul - base;
923 } 937 }
924 lmb_add(base, size); 938 do {
939 if (is_kexec_kdump) {
940 base = dt_mem_next_cell(dt_root_addr_cells,
941 &usm);
942 size = dt_mem_next_cell(dt_root_size_cells,
943 &usm);
944 }
945 if (iommu_is_off) {
946 if (base >= 0x80000000ul)
947 continue;
948 if ((base + size) > 0x80000000ul)
949 size = 0x80000000ul - base;
950 }
951 lmb_add(base, size);
952 } while (--rngs);
925 } 953 }
926 lmb_dump_all(); 954 lmb_dump_all();
927 return 0; 955 return 0;
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