aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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