powerpc/fadump: consider f/w load area
authorHari Bathini <hbathini@linux.ibm.com>
Wed, 11 Sep 2019 14:56:59 +0000 (20:26 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 13 Sep 2019 14:04:45 +0000 (00:04 +1000)
OPAL loads kernel & initrd at 512MB offset (256MB size), also exported
as ibm,opal/dump/fw-load-area. So, if boot memory size of FADump is
less than 768MB, kernel memory to be exported as '/proc/vmcore' would
be overwritten by f/w while loading kernel & initrd. To avoid such a
scenario, enforce a minimum boot memory size of 768MB on OPAL platform
and skip using FADump if a newer F/W version loads kernel & initrd
above 768MB.

Also, irrespective of RMA size, set the minimum boot memory size
expected on pseries platform at 320MB. This is to avoid inflating the
minimum memory requirements on systems with 512M/1024M RMA size.

Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/156821381414.5656.1592867278535469652.stgit@hbathini.in.ibm.com
arch/powerpc/include/asm/fadump-internal.h
arch/powerpc/kernel/fadump.c
arch/powerpc/platforms/powernv/opal-fadump.c
arch/powerpc/platforms/powernv/opal-fadump.h
arch/powerpc/platforms/pseries/rtas-fadump.c
arch/powerpc/platforms/pseries/rtas-fadump.h

index 6c2868d38bd327dfd84e83e664be43f18ec11a0e..a669aaa7c6107719e0cc2f37c985dfa990dc8396 100644 (file)
 #define RMA_START      0x0
 #define RMA_END                (ppc64_rma_size)
 
-/*
- * On some Power systems where RMO is 128MB, it still requires minimum of
- * 256MB for kernel to boot successfully. When kdump infrastructure is
- * configured to save vmcore over network, we run into OOM issue while
- * loading modules related to network setup. Hence we need additional 64M
- * of memory to avoid OOM issue.
- */
-#define MIN_BOOT_MEM   (((RMA_END < (0x1UL << 28)) ? (0x1UL << 28) : RMA_END) \
-                       + (0x1UL << 26))
-
 /* The upper limit percentage for user specified boot memory size (25%) */
 #define MAX_BOOT_MEM_RATIO                     4
 
@@ -128,6 +118,7 @@ struct fadump_ops {
        u64     (*fadump_init_mem_struct)(struct fw_dump *fadump_conf);
        u64     (*fadump_get_metadata_size)(void);
        int     (*fadump_setup_metadata)(struct fw_dump *fadump_conf);
+       u64     (*fadump_get_bootmem_min)(void);
        int     (*fadump_register)(struct fw_dump *fadump_conf);
        int     (*fadump_unregister)(struct fw_dump *fadump_conf);
        int     (*fadump_invalidate)(struct fw_dump *fadump_conf);
index 645d9d4d93324873961324541e1b4722d6f008f7..bd49b1f200bf07033fcafcf72ba127f7bb6d622e 100644 (file)
@@ -240,10 +240,10 @@ static void fadump_show_config(void)
  * that is required for a kernel to boot successfully.
  *
  */
-static inline unsigned long fadump_calculate_reserve_size(void)
+static inline u64 fadump_calculate_reserve_size(void)
 {
+       u64 base, size, bootmem_min;
        int ret;
-       unsigned long long base, size;
 
        if (fw_dump.reserve_bootvar)
                pr_warn("'fadump_reserve_mem=' parameter is deprecated in favor of 'crashkernel=' parameter.\n");
@@ -293,7 +293,8 @@ static inline unsigned long fadump_calculate_reserve_size(void)
        if (memory_limit && size > memory_limit)
                size = memory_limit;
 
-       return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM);
+       bootmem_min = fw_dump.ops->fadump_get_bootmem_min();
+       return (size > bootmem_min ? size : bootmem_min);
 }
 
 /*
@@ -323,8 +324,8 @@ static unsigned long get_fadump_area_size(void)
 
 int __init fadump_reserve_mem(void)
 {
+       u64 base, size, mem_boundary, bootmem_min, align = PAGE_SIZE;
        bool is_memblock_bottom_up = memblock_bottom_up();
-       u64 base, size, mem_boundary, align = PAGE_SIZE;
        int ret = 1;
 
        if (!fw_dump.fadump_enabled)
@@ -350,6 +351,13 @@ int __init fadump_reserve_mem(void)
                                ALIGN(fw_dump.boot_memory_size, align);
                }
 #endif
+
+               bootmem_min = fw_dump.ops->fadump_get_bootmem_min();
+               if (fw_dump.boot_memory_size < bootmem_min) {
+                       pr_err("Can't enable fadump with boot memory size (0x%lx) less than 0x%llx\n",
+                              fw_dump.boot_memory_size, bootmem_min);
+                       goto error_out;
+               }
        }
 
        /*
index a89d3a0cccaec92555c4b8452c42f1ba523d4320..006648e4d5e69c48899e5b12918e11f65ab38ca0 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/string.h>
 #include <linux/seq_file.h>
+#include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
 #include <linux/mm.h>
@@ -262,6 +263,11 @@ static int opal_fadump_setup_metadata(struct fw_dump *fadump_conf)
        return err;
 }
 
+static u64 opal_fadump_get_bootmem_min(void)
+{
+       return OPAL_FADUMP_MIN_BOOT_MEM;
+}
+
 static int opal_fadump_register(struct fw_dump *fadump_conf)
 {
        s64 rc = OPAL_PARAMETER;
@@ -606,6 +612,7 @@ static struct fadump_ops opal_fadump_ops = {
        .fadump_init_mem_struct         = opal_fadump_init_mem_struct,
        .fadump_get_metadata_size       = opal_fadump_get_metadata_size,
        .fadump_setup_metadata          = opal_fadump_setup_metadata,
+       .fadump_get_bootmem_min         = opal_fadump_get_bootmem_min,
        .fadump_register                = opal_fadump_register,
        .fadump_unregister              = opal_fadump_unregister,
        .fadump_invalidate              = opal_fadump_invalidate,
@@ -620,9 +627,9 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
        const __be32 *prop;
        unsigned long dn;
        u64 addr = 0;
+       int i, len;
        s64 ret;
 
-
        /*
         * Check if Firmware-Assisted Dump is supported. if yes, check
         * if dump has been initiated on last reboot.
@@ -638,6 +645,27 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
                return;
        }
 
+       prop = of_get_flat_dt_prop(dn, "fw-load-area", &len);
+       if (prop) {
+               /*
+                * Each f/w load area is an (address,size) pair,
+                * 2 cells each, totalling 4 cells per range.
+                */
+               for (i = 0; i < len / (sizeof(*prop) * 4); i++) {
+                       u64 base, end;
+
+                       base = of_read_number(prop + (i * 4) + 0, 2);
+                       end = base;
+                       end += of_read_number(prop + (i * 4) + 2, 2);
+                       if (end > OPAL_FADUMP_MIN_BOOT_MEM) {
+                               pr_err("F/W load area: 0x%llx-0x%llx\n",
+                                      base, end);
+                               pr_err("F/W version not supported!\n");
+                               return;
+                       }
+               }
+       }
+
        fadump_conf->ops                = &opal_fadump_ops;
        fadump_conf->fadump_supported   = 1;
 
index d0e17d6a2b5c11b9dbab2696fde3c3e6061c47a2..e630cb0f108ff06e06ccb717fc2cc07509166cec 100644 (file)
 
 #include <asm/reg.h>
 
+/*
+ * With kernel & initrd loaded at 512MB (with 256MB size), enforce a minimum
+ * boot memory size of 768MB to ensure f/w loading kernel and initrd doesn't
+ * mess with crash'ed kernel's memory during MPIPL.
+ */
+#define OPAL_FADUMP_MIN_BOOT_MEM               (0x30000000UL)
+
 /*
  * OPAL FADump metadata structure format version
  *
index bf1e8fc549b50d540c6001ff16d630bb5b8a40e3..1d8f2871fa344bb09e8b08407d4ace22f7451517 100644 (file)
@@ -116,6 +116,11 @@ static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
        return addr;
 }
 
+static u64 rtas_fadump_get_bootmem_min(void)
+{
+       return RTAS_FADUMP_MIN_BOOT_MEM;
+}
+
 static int rtas_fadump_register(struct fw_dump *fadump_conf)
 {
        unsigned int wait_time;
@@ -467,6 +472,7 @@ static void rtas_fadump_trigger(struct fadump_crash_info_header *fdh,
 
 static struct fadump_ops rtas_fadump_ops = {
        .fadump_init_mem_struct         = rtas_fadump_init_mem_struct,
+       .fadump_get_bootmem_min         = rtas_fadump_get_bootmem_min,
        .fadump_register                = rtas_fadump_register,
        .fadump_unregister              = rtas_fadump_unregister,
        .fadump_invalidate              = rtas_fadump_invalidate,
index 531f3f3e42b3f710d6c13c2bce0826fc34b25a76..6602ff69e10d11e4455ffe34f67e2a68ea5f2e03 100644 (file)
@@ -9,6 +9,15 @@
 #ifndef _PSERIES_RTAS_FADUMP_H
 #define _PSERIES_RTAS_FADUMP_H
 
+/*
+ * On some Power systems where RMO is 128MB, it still requires minimum of
+ * 256MB for kernel to boot successfully. When kdump infrastructure is
+ * configured to save vmcore over network, we run into OOM issue while
+ * loading modules related to network setup. Hence we need additional 64M
+ * of memory to avoid OOM issue.
+ */
+#define RTAS_FADUMP_MIN_BOOT_MEM       ((0x1UL << 28) + (0x1UL << 26))
+
 /* Firmware provided dump sections */
 #define RTAS_FADUMP_CPU_STATE_DATA     0x0001
 #define RTAS_FADUMP_HPTE_REGION                0x0002