diff options
-rw-r--r-- | arch/powerpc/kernel/prom.c | 55 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 2 | ||||
-rw-r--r-- | arch/powerpc/mm/numa.c | 65 |
3 files changed, 121 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index c18dbe77fdc2..1fc732a552db 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -804,6 +804,56 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) | |||
804 | return of_read_ulong(p, s); | 804 | return of_read_ulong(p, s); |
805 | } | 805 | } |
806 | 806 | ||
807 | #ifdef CONFIG_PPC_PSERIES | ||
808 | /* | ||
809 | * Interpret the ibm,dynamic-memory property in the | ||
810 | * /ibm,dynamic-reconfiguration-memory node. | ||
811 | * This contains a list of memory blocks along with NUMA affinity | ||
812 | * information. | ||
813 | */ | ||
814 | static int __init early_init_dt_scan_drconf_memory(unsigned long node) | ||
815 | { | ||
816 | cell_t *dm, *ls; | ||
817 | unsigned long l, n; | ||
818 | unsigned long base, size, lmb_size, flags; | ||
819 | |||
820 | ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l); | ||
821 | if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t)) | ||
822 | return 0; | ||
823 | lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls); | ||
824 | |||
825 | dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l); | ||
826 | if (dm == NULL || l < sizeof(cell_t)) | ||
827 | return 0; | ||
828 | |||
829 | n = *dm++; /* number of entries */ | ||
830 | if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t)) | ||
831 | return 0; | ||
832 | |||
833 | for (; n != 0; --n) { | ||
834 | base = dt_mem_next_cell(dt_root_addr_cells, &dm); | ||
835 | flags = dm[3]; | ||
836 | /* skip DRC index, pad, assoc. list index, flags */ | ||
837 | dm += 4; | ||
838 | /* skip this block if the reserved bit is set in flags (0x80) | ||
839 | or if the block is not assigned to this partition (0x8) */ | ||
840 | if ((flags & 0x80) || !(flags & 0x8)) | ||
841 | continue; | ||
842 | size = lmb_size; | ||
843 | if (iommu_is_off) { | ||
844 | if (base >= 0x80000000ul) | ||
845 | continue; | ||
846 | if ((base + size) > 0x80000000ul) | ||
847 | size = 0x80000000ul - base; | ||
848 | } | ||
849 | lmb_add(base, size); | ||
850 | } | ||
851 | lmb_dump_all(); | ||
852 | return 0; | ||
853 | } | ||
854 | #else | ||
855 | #define early_init_dt_scan_drconf_memory(node) 0 | ||
856 | #endif /* CONFIG_PPC_PSERIES */ | ||
807 | 857 | ||
808 | static int __init early_init_dt_scan_memory(unsigned long node, | 858 | static int __init early_init_dt_scan_memory(unsigned long node, |
809 | const char *uname, int depth, void *data) | 859 | const char *uname, int depth, void *data) |
@@ -812,6 +862,11 @@ static int __init early_init_dt_scan_memory(unsigned long node, | |||
812 | cell_t *reg, *endp; | 862 | cell_t *reg, *endp; |
813 | unsigned long l; | 863 | unsigned long l; |
814 | 864 | ||
865 | /* Look for the ibm,dynamic-reconfiguration-memory node */ | ||
866 | if (depth == 1 && | ||
867 | strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) | ||
868 | return early_init_dt_scan_drconf_memory(node); | ||
869 | |||
815 | /* We are scanning "memory" nodes only */ | 870 | /* We are scanning "memory" nodes only */ |
816 | if (type == NULL) { | 871 | if (type == NULL) { |
817 | /* | 872 | /* |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 46cf32670ddb..520ef42f642e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -679,7 +679,7 @@ static unsigned char ibm_architecture_vec[] = { | |||
679 | /* option vector 5: PAPR/OF options */ | 679 | /* option vector 5: PAPR/OF options */ |
680 | 3 - 2, /* length */ | 680 | 3 - 2, /* length */ |
681 | 0, /* don't ignore, don't halt */ | 681 | 0, /* don't ignore, don't halt */ |
682 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES, | 682 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY, |
683 | }; | 683 | }; |
684 | 684 | ||
685 | /* Old method - ELF header with PT_NOTE sections */ | 685 | /* Old method - ELF header with PT_NOTE sections */ |
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 9da01dc8cfd9..262790910ff2 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c | |||
@@ -295,6 +295,63 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start, | |||
295 | return lmb_end_of_DRAM() - start; | 295 | return lmb_end_of_DRAM() - start; |
296 | } | 296 | } |
297 | 297 | ||
298 | /* | ||
299 | * Extract NUMA information from the ibm,dynamic-reconfiguration-memory | ||
300 | * node. This assumes n_mem_{addr,size}_cells have been set. | ||
301 | */ | ||
302 | static void __init parse_drconf_memory(struct device_node *memory) | ||
303 | { | ||
304 | const unsigned int *lm, *dm, *aa; | ||
305 | unsigned int ls, ld, la; | ||
306 | unsigned int n, aam, aalen; | ||
307 | unsigned long lmb_size, size; | ||
308 | int nid, default_nid = 0; | ||
309 | unsigned int start, ai, flags; | ||
310 | |||
311 | lm = get_property(memory, "ibm,lmb-size", &ls); | ||
312 | dm = get_property(memory, "ibm,dynamic-memory", &ld); | ||
313 | aa = get_property(memory, "ibm,associativity-lookup-arrays", &la); | ||
314 | if (!lm || !dm || !aa || | ||
315 | ls < sizeof(unsigned int) || ld < sizeof(unsigned int) || | ||
316 | la < 2 * sizeof(unsigned int)) | ||
317 | return; | ||
318 | |||
319 | lmb_size = read_n_cells(n_mem_size_cells, &lm); | ||
320 | n = *dm++; /* number of LMBs */ | ||
321 | aam = *aa++; /* number of associativity lists */ | ||
322 | aalen = *aa++; /* length of each associativity list */ | ||
323 | if (ld < (n * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int) || | ||
324 | la < (aam * aalen + 2) * sizeof(unsigned int)) | ||
325 | return; | ||
326 | |||
327 | for (; n != 0; --n) { | ||
328 | start = read_n_cells(n_mem_addr_cells, &dm); | ||
329 | ai = dm[2]; | ||
330 | flags = dm[3]; | ||
331 | dm += 4; | ||
332 | /* 0x80 == reserved, 0x8 = assigned to us */ | ||
333 | if ((flags & 0x80) || !(flags & 0x8)) | ||
334 | continue; | ||
335 | nid = default_nid; | ||
336 | /* flags & 0x40 means associativity index is invalid */ | ||
337 | if (min_common_depth > 0 && min_common_depth <= aalen && | ||
338 | (flags & 0x40) == 0 && ai < aam) { | ||
339 | /* this is like of_node_to_nid_single */ | ||
340 | nid = aa[ai * aalen + min_common_depth - 1]; | ||
341 | if (nid == 0xffff || nid >= MAX_NUMNODES) | ||
342 | nid = default_nid; | ||
343 | } | ||
344 | node_set_online(nid); | ||
345 | |||
346 | size = numa_enforce_memory_limit(start, lmb_size); | ||
347 | if (!size) | ||
348 | continue; | ||
349 | |||
350 | add_active_range(nid, start >> PAGE_SHIFT, | ||
351 | (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT)); | ||
352 | } | ||
353 | } | ||
354 | |||
298 | static int __init parse_numa_properties(void) | 355 | static int __init parse_numa_properties(void) |
299 | { | 356 | { |
300 | struct device_node *cpu = NULL; | 357 | struct device_node *cpu = NULL; |
@@ -385,6 +442,14 @@ new_range: | |||
385 | goto new_range; | 442 | goto new_range; |
386 | } | 443 | } |
387 | 444 | ||
445 | /* | ||
446 | * Now do the same thing for each LMB listed in the ibm,dynamic-memory | ||
447 | * property in the ibm,dynamic-reconfiguration-memory node. | ||
448 | */ | ||
449 | memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); | ||
450 | if (memory) | ||
451 | parse_drconf_memory(memory); | ||
452 | |||
388 | return 0; | 453 | return 0; |
389 | } | 454 | } |
390 | 455 | ||