diff options
author | Chandru <chandru@in.ibm.com> | 2008-08-29 10:28:16 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-09-15 14:07:58 -0400 |
commit | cf00085d8045cddd80a8aabad97de96fa8131793 (patch) | |
tree | 22bc2935d93709ed6ae229b5737c5412cfaf5991 /arch/powerpc/mm/numa.c | |
parent | 525c411d400603665f8416f7e84bb14a43830027 (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/powerpc/mm/numa.c')
-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 | ||