Hang was observed, in purgatory, on a machine configured with single LPAR. This was because one of the segments was loaded outside the actual Real Memory Area (RMA) due to wrongly deduced RMA top value. Currently, top of real memory area, which is crucial for loading kexec/kdump kernel, is obtained by iterating through mem nodes and setting its value based on the base and size values of the last mem node in the iteration. That can't always be correct as the order of iteration may not be same and RMA base & size are always based on the first memory property. Fix this by setting RMA top value based on the base and size values of the memory node that has the smallest base value (first memory property) among all the memory nodes. Also, correct the misnomers rmo_base and rmo_top to rma_base and rma_top respectively. While how RMA top is deduced was broken for sometime, the issue may not have been seen so far, for couple of possible reasons: 1. Only one mem node was available. 2. First memory property has been the last node in iteration when multiple mem nodes were present. Fixes: 02f4088ffded ("kexec fix ppc64 device-tree mem node") Reported-by: Ankit Kumar <ankit at linux.vnet.ibm.com> Cc: Michael Ellerman <mpe at ellerman.id.au> Cc: Geoff Levand <geoff at infradead.org> Signed-off-by: Hari Bathini <hbathini at linux.vnet.ibm.com> --- kexec/arch/ppc64/kexec-ppc64.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/kexec/arch/ppc64/kexec-ppc64.c b/kexec/arch/ppc64/kexec-ppc64.c index 6e8c175..a7d708b 100644 --- a/kexec/arch/ppc64/kexec-ppc64.c +++ b/kexec/arch/ppc64/kexec-ppc64.c @@ -38,7 +38,7 @@ static struct memory_range *exclude_range = NULL; static struct memory_range *memory_range = NULL; static struct memory_range *base_memory_range = NULL; -static uint64_t rmo_top; +static uint64_t rma_top; uint64_t memory_max = 0; uint64_t memory_limit; static int nr_memory_ranges, nr_exclude_ranges; @@ -385,7 +385,7 @@ int get_devtree_value(const char *fname, unsigned long long *value) */ static int get_devtree_details(unsigned long kexec_flags) { - uint64_t rmo_base; + uint64_t rma_base = -1, base; uint64_t tce_base; unsigned int tce_size; uint64_t htab_base, htab_size; @@ -696,10 +696,13 @@ static int get_devtree_details(unsigned long kexec_flags) perror(fname); goto error_openfile; } - rmo_base = be64_to_cpu(((uint64_t *)buf)[0]); - rmo_top = rmo_base + be64_to_cpu(((uint64_t *)buf)[1]); - if (rmo_top > 0x30000000UL) - rmo_top = 0x30000000UL; + base = be64_to_cpu(((uint64_t *)buf)[0]); + if (base < rma_base) { + rma_base = base; + rma_top = base + be64_to_cpu(((uint64_t *)buf)[1]); + if (rma_top > 0x30000000UL) + rma_top = 0x30000000UL; + } fclose(file); closedir(cdir); @@ -811,14 +814,14 @@ int setup_memory_ranges(unsigned long kexec_flags) j++; if (j >= max_memory_ranges) realloc_memory_ranges(); - /* Limit the end to rmo_top */ - if (memory_range[j-1].start >= rmo_top) { + /* Limit the end to rma_top */ + if (memory_range[j-1].start >= rma_top) { j--; break; } - if ((memory_range[j-1].start < rmo_top) && - (memory_range[j-1].end >= rmo_top)) { - memory_range[j-1].end = rmo_top; + if ((memory_range[j-1].start < rma_top) && + (memory_range[j-1].end >= rma_top)) { + memory_range[j-1].end = rma_top; break; } continue; @@ -833,14 +836,14 @@ int setup_memory_ranges(unsigned long kexec_flags) j++; if (j >= max_memory_ranges) realloc_memory_ranges(); - /* Limit range to rmo_top */ - if (memory_range[j-1].start >= rmo_top) { + /* Limit range to rma_top */ + if (memory_range[j-1].start >= rma_top) { j--; break; } - if ((memory_range[j-1].start < rmo_top) && - (memory_range[j-1].end >= rmo_top)) { - memory_range[j-1].end = rmo_top; + if ((memory_range[j-1].start < rma_top) && + (memory_range[j-1].end >= rma_top)) { + memory_range[j-1].end = rma_top; break; } }