aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/numa.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm/numa.c')
-rw-r--r--arch/powerpc/mm/numa.c185
1 files changed, 141 insertions, 44 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index d9a181351332..6cf5c71c431f 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -89,6 +89,46 @@ static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
89 return 0; 89 return 0;
90} 90}
91 91
92/*
93 * get_active_region_work_fn - A helper function for get_node_active_region
94 * Returns datax set to the start_pfn and end_pfn if they contain
95 * the initial value of datax->start_pfn between them
96 * @start_pfn: start page(inclusive) of region to check
97 * @end_pfn: end page(exclusive) of region to check
98 * @datax: comes in with ->start_pfn set to value to search for and
99 * goes out with active range if it contains it
100 * Returns 1 if search value is in range else 0
101 */
102static int __init get_active_region_work_fn(unsigned long start_pfn,
103 unsigned long end_pfn, void *datax)
104{
105 struct node_active_region *data;
106 data = (struct node_active_region *)datax;
107
108 if (start_pfn <= data->start_pfn && end_pfn > data->start_pfn) {
109 data->start_pfn = start_pfn;
110 data->end_pfn = end_pfn;
111 return 1;
112 }
113 return 0;
114
115}
116
117/*
118 * get_node_active_region - Return active region containing start_pfn
119 * @start_pfn: The page to return the region for.
120 * @node_ar: Returned set to the active region containing start_pfn
121 */
122static void __init get_node_active_region(unsigned long start_pfn,
123 struct node_active_region *node_ar)
124{
125 int nid = early_pfn_to_nid(start_pfn);
126
127 node_ar->nid = nid;
128 node_ar->start_pfn = start_pfn;
129 work_with_active_regions(nid, get_active_region_work_fn, node_ar);
130}
131
92static void __cpuinit map_cpu_to_node(int cpu, int node) 132static void __cpuinit map_cpu_to_node(int cpu, int node)
93{ 133{
94 numa_cpu_lookup_table[cpu] = node; 134 numa_cpu_lookup_table[cpu] = node;
@@ -150,6 +190,21 @@ static const int *of_get_associativity(struct device_node *dev)
150 return of_get_property(dev, "ibm,associativity", NULL); 190 return of_get_property(dev, "ibm,associativity", NULL);
151} 191}
152 192
193/*
194 * Returns the property linux,drconf-usable-memory if
195 * it exists (the property exists only in kexec/kdump kernels,
196 * added by kexec-tools)
197 */
198static const u32 *of_get_usable_memory(struct device_node *memory)
199{
200 const u32 *prop;
201 u32 len;
202 prop = of_get_property(memory, "linux,drconf-usable-memory", &len);
203 if (!prop || len < sizeof(unsigned int))
204 return 0;
205 return prop;
206}
207
153/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa 208/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
154 * info is found. 209 * info is found.
155 */ 210 */
@@ -487,14 +542,29 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
487} 542}
488 543
489/* 544/*
545 * Reads the counter for a given entry in
546 * linux,drconf-usable-memory property
547 */
548static inline int __init read_usm_ranges(const u32 **usm)
549{
550 /*
551 * For each lmb in ibm,dynamic-memory a corresponding
552 * entry in linux,drconf-usable-memory property contains
553 * a counter followed by that many (base, size) duple.
554 * read the counter from linux,drconf-usable-memory
555 */
556 return read_n_cells(n_mem_size_cells, usm);
557}
558
559/*
490 * Extract NUMA information from the ibm,dynamic-reconfiguration-memory 560 * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
491 * node. This assumes n_mem_{addr,size}_cells have been set. 561 * node. This assumes n_mem_{addr,size}_cells have been set.
492 */ 562 */
493static void __init parse_drconf_memory(struct device_node *memory) 563static void __init parse_drconf_memory(struct device_node *memory)
494{ 564{
495 const u32 *dm; 565 const u32 *dm, *usm;
496 unsigned int n, rc; 566 unsigned int n, rc, ranges, is_kexec_kdump = 0;
497 unsigned long lmb_size, size; 567 unsigned long lmb_size, base, size, sz;
498 int nid; 568 int nid;
499 struct assoc_arrays aa; 569 struct assoc_arrays aa;
500 570
@@ -510,6 +580,11 @@ static void __init parse_drconf_memory(struct device_node *memory)
510 if (rc) 580 if (rc)
511 return; 581 return;
512 582
583 /* check if this is a kexec/kdump kernel */
584 usm = of_get_usable_memory(memory);
585 if (usm != NULL)
586 is_kexec_kdump = 1;
587
513 for (; n != 0; --n) { 588 for (; n != 0; --n) {
514 struct of_drconf_cell drmem; 589 struct of_drconf_cell drmem;
515 590
@@ -521,21 +596,31 @@ static void __init parse_drconf_memory(struct device_node *memory)
521 || !(drmem.flags & DRCONF_MEM_ASSIGNED)) 596 || !(drmem.flags & DRCONF_MEM_ASSIGNED))
522 continue; 597 continue;
523 598
524 nid = of_drconf_to_nid_single(&drmem, &aa); 599 base = drmem.base_addr;
600 size = lmb_size;
601 ranges = 1;
525 602
526 fake_numa_create_new_node( 603 if (is_kexec_kdump) {
527 ((drmem.base_addr + lmb_size) >> PAGE_SHIFT), 604 ranges = read_usm_ranges(&usm);
605 if (!ranges) /* there are no (base, size) duple */
606 continue;
607 }
608 do {
609 if (is_kexec_kdump) {
610 base = read_n_cells(n_mem_addr_cells, &usm);
611 size = read_n_cells(n_mem_size_cells, &usm);
612 }
613 nid = of_drconf_to_nid_single(&drmem, &aa);
614 fake_numa_create_new_node(
615 ((base + size) >> PAGE_SHIFT),
528 &nid); 616 &nid);
529 617 node_set_online(nid);
530 node_set_online(nid); 618 sz = numa_enforce_memory_limit(base, size);
531 619 if (sz)
532 size = numa_enforce_memory_limit(drmem.base_addr, lmb_size); 620 add_active_range(nid, base >> PAGE_SHIFT,
533 if (!size) 621 (base >> PAGE_SHIFT)
534 continue; 622 + (sz >> PAGE_SHIFT));
535 623 } while (--ranges);
536 add_active_range(nid, drmem.base_addr >> PAGE_SHIFT,
537 (drmem.base_addr >> PAGE_SHIFT)
538 + (size >> PAGE_SHIFT));
539 } 624 }
540} 625}
541 626
@@ -837,38 +922,50 @@ void __init do_init_bootmem(void)
837 start_pfn, end_pfn); 922 start_pfn, end_pfn);
838 923
839 free_bootmem_with_active_regions(nid, end_pfn); 924 free_bootmem_with_active_regions(nid, end_pfn);
925 }
840 926
841 /* Mark reserved regions on this node */ 927 /* Mark reserved regions */
842 for (i = 0; i < lmb.reserved.cnt; i++) { 928 for (i = 0; i < lmb.reserved.cnt; i++) {
843 unsigned long physbase = lmb.reserved.region[i].base; 929 unsigned long physbase = lmb.reserved.region[i].base;
844 unsigned long size = lmb.reserved.region[i].size; 930 unsigned long size = lmb.reserved.region[i].size;
845 unsigned long start_paddr = start_pfn << PAGE_SHIFT; 931 unsigned long start_pfn = physbase >> PAGE_SHIFT;
846 unsigned long end_paddr = end_pfn << PAGE_SHIFT; 932 unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT);
847 933 struct node_active_region node_ar;
848 if (early_pfn_to_nid(physbase >> PAGE_SHIFT) != nid && 934
849 early_pfn_to_nid((physbase+size-1) >> PAGE_SHIFT) != nid) 935 get_node_active_region(start_pfn, &node_ar);
850 continue; 936 while (start_pfn < end_pfn) {
851 937 /*
852 if (physbase < end_paddr && 938 * if reserved region extends past active region
853 (physbase+size) > start_paddr) { 939 * then trim size to active region
854 /* overlaps */ 940 */
855 if (physbase < start_paddr) { 941 if (end_pfn > node_ar.end_pfn)
856 size -= start_paddr - physbase; 942 size = (node_ar.end_pfn << PAGE_SHIFT)
857 physbase = start_paddr; 943 - (start_pfn << PAGE_SHIFT);
858 } 944 dbg("reserve_bootmem %lx %lx nid=%d\n", physbase, size,
859 945 node_ar.nid);
860 if (size > end_paddr - physbase) 946 reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase,
861 size = end_paddr - physbase; 947 size, BOOTMEM_DEFAULT);
862 948 /*
863 dbg("reserve_bootmem %lx %lx\n", physbase, 949 * if reserved region is contained in the active region
864 size); 950 * then done.
865 reserve_bootmem_node(NODE_DATA(nid), physbase, 951 */
866 size, BOOTMEM_DEFAULT); 952 if (end_pfn <= node_ar.end_pfn)
867 } 953 break;
954
955 /*
956 * reserved region extends past the active region
957 * get next active region that contains this
958 * reserved region
959 */
960 start_pfn = node_ar.end_pfn;
961 physbase = start_pfn << PAGE_SHIFT;
962 get_node_active_region(start_pfn, &node_ar);
868 } 963 }
869 964
870 sparse_memory_present_with_active_regions(nid);
871 } 965 }
966
967 for_each_online_node(nid)
968 sparse_memory_present_with_active_regions(nid);
872} 969}
873 970
874void __init paging_init(void) 971void __init paging_init(void)