diff options
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/numa.c | 77 |
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 | */ | ||
158 | static 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 | */ | ||
508 | static 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 | */ |
493 | static void __init parse_drconf_memory(struct device_node *memory) | 523 | static 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 | ||