* [PATCH v4 16/25] powerpc/fadump: consider reserved ranges while reserving memory
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Commit 0962e8004e97 ("powerpc/prom: Scan reserved-ranges node for
memory reservations") enabled support to parse reserved-ranges DT
node and reserve kernel memory falling in these ranges for F/W
purposes. Ensure memory in these ranges is not overlapped with
memory reserved for FADump.
Also, use a smaller offset, instead of the size of the memory to
be reserved, by which to skip memory before making another attempt
at reserving memory, after the previous attempt to reserve memory
for FADump failed due to memory holes and/or reserved ranges, to
reduce the likelihood of memory reservation failure.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/kernel/fadump-common.h | 13 +++
arch/powerpc/kernel/fadump.c | 143 ++++++++++++++++++++++++++++++++++-
2 files changed, 149 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index 06d9ecf..968745a 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -86,7 +86,7 @@ struct fadump_crash_info_header {
struct cpumask online_mask;
};
-struct fad_crash_memory_ranges {
+struct fadump_memory_range {
unsigned long long base;
unsigned long long size;
};
@@ -94,6 +94,17 @@ struct fad_crash_memory_ranges {
/* Platform specific callback functions */
struct fadump_ops;
+/*
+ * Amount of memory (1024MB) to skip before making another attempt at
+ * reserving memory (after the previous attempt to reserve memory for
+ * FADump failed due to memory holes and/or reserved ranges) to reduce
+ * the likelihood of memory reservation failure.
+ */
+#define FADUMP_OFFSET_SIZE 0x40000000U
+
+/* Maximum no. of reserved ranges supported for processing. */
+#define FADUMP_MAX_RESERVED_RANGES 128
+
/* Maximum number of memory regions kernel supports */
#define FADUMP_MAX_MEM_REGS 128
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index abf4f334..bface37 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -36,11 +36,14 @@
static struct fw_dump fw_dump;
static DEFINE_MUTEX(fadump_mutex);
-struct fad_crash_memory_ranges *crash_memory_ranges;
+struct fadump_memory_range *crash_memory_ranges;
int crash_memory_ranges_size;
int crash_mem_ranges;
int max_crash_mem_ranges;
+struct fadump_memory_range reserved_ranges[FADUMP_MAX_RESERVED_RANGES];
+int reserved_ranges_cnt;
+
#ifdef CONFIG_CMA
static struct cma *fadump_cma;
@@ -104,12 +107,116 @@ int __init fadump_cma_init(void)
static int __init fadump_cma_init(void) { return 1; }
#endif /* CONFIG_CMA */
+/*
+ * Sort the reserved ranges in-place and merge adjacent ranges
+ * to minimize the reserved ranges count.
+ */
+static void __init sort_and_merge_reserved_ranges(void)
+{
+ unsigned long long base, size;
+ struct fadump_memory_range tmp_range;
+ int i, j, idx;
+
+ if (!reserved_ranges_cnt)
+ return;
+
+ /* Sort the reserved ranges */
+ for (i = 0; i < reserved_ranges_cnt; i++) {
+ idx = i;
+ for (j = i + 1; j < reserved_ranges_cnt; j++) {
+ if (reserved_ranges[idx].base > reserved_ranges[j].base)
+ idx = j;
+ }
+ if (idx != i) {
+ tmp_range = reserved_ranges[idx];
+ reserved_ranges[idx] = reserved_ranges[i];
+ reserved_ranges[i] = tmp_range;
+ }
+ }
+
+ /* Merge adjacent reserved ranges */
+ idx = 0;
+ for (i = 1; i < reserved_ranges_cnt; i++) {
+ base = reserved_ranges[i-1].base;
+ size = reserved_ranges[i-1].size;
+ if (reserved_ranges[i].base == (base + size))
+ reserved_ranges[idx].size += reserved_ranges[i].size;
+ else {
+ idx++;
+ if (i == idx)
+ continue;
+
+ reserved_ranges[idx] = reserved_ranges[i];
+ }
+ }
+ reserved_ranges_cnt = idx + 1;
+}
+
+static int __init add_reserved_range(unsigned long base,
+ unsigned long size)
+{
+ int i;
+
+ if (reserved_ranges_cnt == FADUMP_MAX_RESERVED_RANGES) {
+ /* Compact reserved ranges and try again. */
+ sort_and_merge_reserved_ranges();
+ if (reserved_ranges_cnt == FADUMP_MAX_RESERVED_RANGES)
+ return 0;
+ }
+
+ i = reserved_ranges_cnt++;
+ reserved_ranges[i].base = base;
+ reserved_ranges[i].size = size;
+ return 1;
+}
+
+/*
+ * Scan reserved-ranges to consider them while reserving/releasing
+ * memory for FADump.
+ */
+static void __init early_init_dt_scan_reserved_ranges(unsigned long node)
+{
+ int len, ret;
+ unsigned long i;
+ const __be32 *prop;
+
+ /* reserved-ranges already scanned */
+ if (reserved_ranges_cnt != 0)
+ return;
+
+ prop = of_get_flat_dt_prop(node, "reserved-ranges", &len);
+
+ if (!prop)
+ return;
+
+ /*
+ * Each reserved range is an (address,size) pair, 2 cells each,
+ * totalling 4 cells per range.
+ */
+ for (i = 0; i < len / (sizeof(*prop) * 4); i++) {
+ u64 base, size;
+
+ base = of_read_number(prop + (i * 4) + 0, 2);
+ size = of_read_number(prop + (i * 4) + 2, 2);
+
+ if (size) {
+ ret = add_reserved_range(base, size);
+ if (ret == 0)
+ pr_warn("some reserved ranges are ignored!\n");
+ }
+ }
+}
+
/* Scan the Firmware Assisted dump configuration details. */
int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
int depth, void *data)
{
- if (depth != 1)
+ if (depth != 1) {
+ if (depth == 0)
+ early_init_dt_scan_reserved_ranges(node);
+
return 0;
+ }
if (strcmp(uname, "rtas") == 0)
return rtas_fadump_dt_scan(&fw_dump, node);
@@ -355,6 +462,26 @@ static int __init fadump_get_boot_mem_regions(void)
return ret;
}
+static bool overlaps_with_reserved_ranges(ulong base, ulong end)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < reserved_ranges_cnt; i++) {
+ ulong rbase = (ulong)reserved_ranges[i].base;
+ ulong rend = rbase + (ulong)reserved_ranges[i].size;
+
+ if (end <= rbase)
+ break;
+
+ if ((end > rbase) && (base < rend)) {
+ ret = 1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
static void __init fadump_reserve_crash_area(unsigned long base,
unsigned long size)
{
@@ -388,6 +515,9 @@ int __init fadump_reserve_mem(void)
goto error_out;
}
+ /* Compact reserved ranges */
+ sort_and_merge_reserved_ranges();
+
/*
* Initialize boot memory size
* If dump is active then we have already calculated the size during
@@ -447,10 +577,11 @@ int __init fadump_reserve_mem(void)
*/
while (base <= (memory_boundary - size)) {
if (memblock_is_region_memory(base, size) &&
- !memblock_is_region_reserved(base, size))
+ !memblock_is_region_reserved(base, size) &&
+ !overlaps_with_reserved_ranges(base, (base+size)))
break;
- base += size;
+ base += FADUMP_OFFSET_SIZE;
}
if (base > (memory_boundary - size)) {
@@ -579,7 +710,7 @@ static void free_crash_memory_ranges(void)
*/
static int allocate_crash_memory_ranges(void)
{
- struct fad_crash_memory_ranges *new_array;
+ struct fadump_memory_range *new_array;
u64 new_size;
new_size = crash_memory_ranges_size + PAGE_SIZE;
@@ -596,7 +727,7 @@ static int allocate_crash_memory_ranges(void)
crash_memory_ranges = new_array;
crash_memory_ranges_size = new_size;
max_crash_mem_ranges = (new_size /
- sizeof(struct fad_crash_memory_ranges));
+ sizeof(struct fadump_memory_range));
return 0;
}
^ permalink raw reply related
* [PATCH v4 15/25] powerpc/fadump: Update documentation about OPAL platform support
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
With FADump support now available on both pseries and OPAL platforms,
update FADump documentation with these details.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Documentation/powerpc/firmware-assisted-dump.txt | 104 +++++++++++++---------
1 file changed, 63 insertions(+), 41 deletions(-)
diff --git a/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt
index 0c6a28c..cd48776 100644
--- a/Documentation/powerpc/firmware-assisted-dump.txt
+++ b/Documentation/powerpc/firmware-assisted-dump.txt
@@ -70,7 +70,8 @@ as follows:
normal.
-- The freshly booted kernel will notice that there is a new
- node (ibm,dump-kernel) in the device tree, indicating that
+ node (ibm,dump-kernel on PSeries or ibm,opal/dump/result-table
+ on OPAL platform) in the device tree, indicating that
there is crash data available from a previous boot. During
the early boot OS will reserve rest of the memory above
boot memory size effectively booting with restricted memory
@@ -93,7 +94,9 @@ as follows:
Please note that the firmware-assisted dump feature
is only available on Power6 and above systems with recent
-firmware versions.
+firmware versions on PSeries (PowerVM) platform and Power9
+and above systems with recent firmware versions on PowerNV
+(OPAL) platform.
Implementation details:
----------------------
@@ -108,57 +111,76 @@ that are run. If there is dump data, then the
/sys/kernel/fadump_release_mem file is created, and the reserved
memory is held.
-If there is no waiting dump data, then only the memory required
-to hold CPU state, HPTE region, boot memory dump and elfcore
-header, is usually reserved at an offset greater than boot memory
-size (see Fig. 1). This area is *not* released: this region will
-be kept permanently reserved, so that it can act as a receptacle
-for a copy of the boot memory content in addition to CPU state
-and HPTE region, in the case a crash does occur. Since this reserved
-memory area is used only after the system crash, there is no point in
-blocking this significant chunk of memory from production kernel.
-Hence, the implementation uses the Linux kernel's Contiguous Memory
-Allocator (CMA) for memory reservation if CMA is configured for kernel.
-With CMA reservation this memory will be available for applications to
-use it, while kernel is prevented from using it. With this FADump will
-still be able to capture all of the kernel memory and most of the user
-space memory except the user pages that were present in CMA region.
+If there is no waiting dump data, then only the memory required to
+hold CPU state, HPTE region, boot memory dump, FADump header and
+elfcore header, is usually reserved at an offset greater than boot
+memory size (see Fig. 1). This area is *not* released: this region
+will be kept permanently reserved, so that it can act as a receptacle
+for a copy of the boot memory content in addition to CPU state and
+HPTE region, in the case a crash does occur.
+
+Since this reserved memory area is used only after the system crash,
+there is no point in blocking this significant chunk of memory from
+production kernel. Hence, the implementation uses the Linux kernel's
+Contiguous Memory Allocator (CMA) for memory reservation if CMA is
+configured for kernel. With CMA reservation this memory will be
+available for applications to use it, while kernel is prevented from
+using it. With this FADump will still be able to capture all of the
+kernel memory and most of the user space memory except the user pages
+that were present in CMA region.
o Memory Reservation during first kernel
- Low memory Top of memory
- 0 boot memory size |<--Reserved dump area --->| |
- | | | Permanent Reservation | |
- V V | (Preserve area) | V
- +-----------+----------/ /---+---+----+--------+---+----+------+
- | | |CPU|HPTE| DUMP |HDR|ELF | |
- +-----------+----------/ /---+---+----+--------+---+----+------+
- | ^ ^
- | | |
- \ / |
- ----------------------------------- FADump Header
- Boot memory content gets transferred (meta area)
- to reserved area by firmware at the
- time of crash
+ Low memory Top of memory
+ 0 boot memory size |<--- Reserved dump area --->| |
+ | | | Permanent Reservation | |
+ V V | (Preserve area) | V
+ +-----------+-----/ /---+---+----+-------+-----+-----+----+--+
+ | | |///|////| DUMP | HDR | ELF |////| |
+ +-----------+-----/ /---+---+----+-------+-----+-----+----+--+
+ | ^ ^ ^ ^ ^
+ | | | | | |
+ \ CPU HPTE / | |
+ ------------------------------ | |
+ Boot memory content gets transferred | |
+ to reserved area by firmware at the | |
+ time of crash. | |
+ FADump Header |
+ (meta area) |
+ |
+ |
+ Metadata: This area holds a metadata struture whose
+ address is registered with f/w and retrieved in the
+ second kernel after crash, on platforms that support
+ tags (OPAL). Having such structure with info needed
+ to process the crashdump eases dump capture process.
Fig. 1
o Memory Reservation during second kernel after crash
- Low memory Top of memory
- 0 boot memory size |
- | |<------------- Reserved dump area --------------->|
- V V |<---- Preserve area ----->| V
- +-----------+----------/ /---+---+----+--------+---+----+------+
- | | |CPU|HPTE| DUMP |HDR|ELF | |
- +-----------+----------/ /---+---+----+--------+---+----+------+
- | |
- V V
- Used by second /proc/vmcore
+ Low memory Top of memory
+ 0 boot memory size |
+ | |<------------ Reserved dump area -------------->|
+ V V |<---- Preserve area ------->| |
+ +-----------+-----/ /---+---+----+-------+-----+-----+----+--+
+ | | |///|////| DUMP | HDR | ELF |////| |
+ +-----------+-----/ /---+---+----+-------+-----+-----+----+--+
+ | |
+ V V
+ Used by second /proc/vmcore
kernel to boot
+
+ +---+
+ |///| -> Regions (CPU, HPTE & Metadata) marked like this in the above
+ +---+ figures are not always present. For example, OPAL platform
+ does not have CPU & HPTE regions while Metadata region is
+ not supported on pSeries currently.
+
Fig. 2
+
Currently the dump will be copied from /proc/vmcore to a new file upon
user intervention. The dump data available through /proc/vmcore will be
in ELF format. Hence the existing kdump infrastructure (kdump scripts)
^ permalink raw reply related
* [PATCH v4 14/25] powernv/fadump: process the crashdump by exporting it as /proc/vmcore
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Add support in the kernel to process the crash'ed kernel's memory
preserved during MPIPL and export it as /proc/vmcore file for the
userland scripts to filter and analyze it later.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/platforms/powernv/opal-fadump.c | 190 ++++++++++++++++++++++++++
1 file changed, 187 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
index 9c68c83..dffc0e7 100644
--- a/arch/powerpc/platforms/powernv/opal-fadump.c
+++ b/arch/powerpc/platforms/powernv/opal-fadump.c
@@ -18,6 +18,7 @@
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <linux/mm.h>
+#include <linux/crash_dump.h>
#include <asm/page.h>
#include <asm/opal.h>
@@ -25,6 +26,7 @@
#include "../../kernel/fadump-common.h"
#include "opal-fadump.h"
+static const struct opal_fadump_mem_struct *opal_fdm_active;
static struct opal_fadump_mem_struct *opal_fdm;
static void opal_fadump_update_config(struct fw_dump *fadump_conf,
@@ -41,6 +43,50 @@ static void opal_fadump_update_config(struct fw_dump *fadump_conf,
fadump_conf->boot_mem_dest_addr);
fadump_conf->fadumphdr_addr = fdm->fadumphdr_addr;
+
+ /* Start address of preserve area (permanent reservation) */
+ fadump_conf->preserv_area_start = fadump_conf->boot_mem_dest_addr;
+ pr_debug("Preserve area start address: 0x%lx\n",
+ fadump_conf->preserv_area_start);
+}
+
+/*
+ * This function is called in the capture kernel to get configuration details
+ * from metadata setup by the first kernel.
+ */
+static void opal_fadump_get_config(struct fw_dump *fadump_conf,
+ const struct opal_fadump_mem_struct *fdm)
+{
+ unsigned long base, size, last_end, hole_size;
+ int i;
+
+ if (!fadump_conf->dump_active)
+ return;
+
+ last_end = 0;
+ hole_size = 0;
+ fadump_conf->boot_memory_size = 0;
+
+ if (fdm->region_cnt)
+ pr_debug("Boot memory regions:\n");
+
+ for (i = 0; i < fdm->region_cnt; i++) {
+ base = fdm->rgn[i].src;
+ size = fdm->rgn[i].size;
+ pr_debug("\t%d. base: 0x%lx, size: 0x%lx\n",
+ (i + 1), base, size);
+
+ fadump_conf->boot_mem_addr[i] = base;
+ fadump_conf->boot_mem_size[i] = size;
+ fadump_conf->boot_memory_size += size;
+ hole_size += (base - last_end);
+
+ last_end = base + size;
+ }
+
+ fadump_conf->boot_mem_top = (fadump_conf->boot_memory_size + hole_size);
+ fadump_conf->boot_mem_regs_cnt = fdm->region_cnt;
+ opal_fadump_update_config(fadump_conf, fdm);
}
static ulong opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
@@ -174,27 +220,127 @@ static int opal_fadump_unregister_fadump(struct fw_dump *fadump_conf)
static int opal_fadump_invalidate_fadump(struct fw_dump *fadump_conf)
{
- return -EIO;
+ s64 rc;
+
+ rc = opal_mpipl_update(OPAL_MPIPL_FREE_PRESERVED_MEMORY, 0, 0, 0);
+ if (rc) {
+ pr_err("Failed to invalidate - unexpected Error(%lld).\n", rc);
+ return -EIO;
+ }
+
+ fadump_conf->dump_active = 0;
+ opal_fdm_active = NULL;
+ return 0;
+}
+
+/*
+ * Convert CPU state data saved at the time of crash into ELF notes.
+ */
+static int __init opal_fadump_build_cpu_notes(struct fw_dump *fadump_conf)
+{
+ u32 num_cpus, *note_buf;
+ struct fadump_crash_info_header *fdh = NULL;
+
+ num_cpus = 1;
+ /* Allocate buffer to hold cpu crash notes. */
+ fadump_conf->cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
+ fadump_conf->cpu_notes_buf_size =
+ PAGE_ALIGN(fadump_conf->cpu_notes_buf_size);
+ note_buf = fadump_cpu_notes_buf_alloc(fadump_conf->cpu_notes_buf_size);
+ if (!note_buf) {
+ pr_err("Failed to allocate 0x%lx bytes for cpu notes buffer\n",
+ fadump_conf->cpu_notes_buf_size);
+ return -ENOMEM;
+ }
+ fadump_conf->cpu_notes_buf = __pa(note_buf);
+
+ pr_debug("Allocated buffer for cpu notes of size %ld at %p\n",
+ (num_cpus * sizeof(note_buf_t)), note_buf);
+
+ if (fadump_conf->fadumphdr_addr)
+ fdh = __va(fadump_conf->fadumphdr_addr);
+
+ if (fdh && (fdh->crashing_cpu != FADUMP_CPU_UNKNOWN)) {
+ note_buf = fadump_regs_to_elf_notes(note_buf, &(fdh->regs));
+ final_note(note_buf);
+
+ pr_debug("Updating elfcore header (%llx) with cpu notes\n",
+ fdh->elfcorehdr_addr);
+ fadump_update_elfcore_header(fadump_conf,
+ __va(fdh->elfcorehdr_addr));
+ }
+
+ return 0;
}
static int __init opal_fadump_process_fadump(struct fw_dump *fadump_conf)
{
- return -EINVAL;
+ struct fadump_crash_info_header *fdh;
+ int rc = 0;
+
+ if (!opal_fdm_active || !fadump_conf->fadumphdr_addr)
+ return -EINVAL;
+
+ /* Validate the fadump crash info header */
+ fdh = __va(fadump_conf->fadumphdr_addr);
+ if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) {
+ pr_err("Crash info header is not valid.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * TODO: To build cpu notes, find a way to map PIR to logical id.
+ * Also, we may need different method for pseries and powernv.
+ * The currently booted kernel could have a different PIR to
+ * logical id mapping. So, try saving info of previous kernel's
+ * paca to get the right PIR to logical id mapping.
+ */
+ rc = opal_fadump_build_cpu_notes(fadump_conf);
+ if (rc)
+ return rc;
+
+ /*
+ * We are done validating dump info and elfcore header is now ready
+ * to be exported. set elfcorehdr_addr so that vmcore module will
+ * export the elfcore header through '/proc/vmcore'.
+ */
+ elfcorehdr_addr = fdh->elfcorehdr_addr;
+
+ return rc;
}
static void opal_fadump_region_show(struct fw_dump *fadump_conf,
struct seq_file *m)
{
int i;
- const struct opal_fadump_mem_struct *fdm_ptr = opal_fdm;
+ const struct opal_fadump_mem_struct *fdm_ptr;
u64 dumped_bytes = 0;
+ if (fadump_conf->dump_active)
+ fdm_ptr = opal_fdm_active;
+ else
+ fdm_ptr = opal_fdm;
+
for (i = 0; i < fdm_ptr->region_cnt; i++) {
+ /*
+ * Only regions that are registered for MPIPL
+ * would have dump data.
+ */
+ if ((fadump_conf->dump_active) &&
+ (i < fdm_ptr->registered_regions))
+ dumped_bytes = fdm_ptr->rgn[i].size;
+
seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest);
seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
fdm_ptr->rgn[i].size, dumped_bytes);
}
+
+ /* Dump is active. Show reserved area start address. */
+ if (fadump_conf->dump_active) {
+ seq_printf(m, "\nMemory above %#016lx is reserved for saving crash dump\n",
+ fadump_conf->reserve_dump_area_start);
+ }
}
static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
@@ -225,6 +371,7 @@ static struct fadump_ops opal_fadump_ops = {
int __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, ulong node)
{
unsigned long dn;
+ const __be32 *prop;
/*
* Check if Firmware-Assisted Dump is supported. if yes, check
@@ -251,5 +398,42 @@ int __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, ulong node)
*/
fadump_conf->max_copy_size = _ALIGN_DOWN(U32_MAX, PAGE_SIZE);
+ /*
+ * Check if dump has been initiated on last reboot.
+ */
+ prop = of_get_flat_dt_prop(dn, "mpipl-boot", NULL);
+ if (prop) {
+ u64 addr = 0;
+ s64 ret;
+ const struct opal_fadump_mem_struct *r_opal_fdm_active;
+
+ ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr);
+ if ((ret != OPAL_SUCCESS) || !addr) {
+ pr_err("Failed to get Kernel metadata (%lld)\n", ret);
+ return 1;
+ }
+
+ addr = be64_to_cpu(addr);
+ pr_debug("Kernel metadata addr: %llx\n", addr);
+
+ opal_fdm_active = __va(addr);
+ r_opal_fdm_active = (void *)addr;
+ if (r_opal_fdm_active->version != OPAL_FADUMP_VERSION) {
+ pr_err("FADump active but version (%u) unsupported!\n",
+ r_opal_fdm_active->version);
+ return 1;
+ }
+
+ /* Kernel regions not registered with f/w for MPIPL */
+ if (r_opal_fdm_active->registered_regions == 0) {
+ opal_fdm_active = NULL;
+ return 1;
+ }
+
+ pr_info("Firmware-assisted dump is active.\n");
+ fadump_conf->dump_active = 1;
+ opal_fadump_get_config(fadump_conf, r_opal_fdm_active);
+ }
+
return 1;
}
^ permalink raw reply related
* [PATCH v4 13/25] powernv/fadump: support copying multiple kernel memory regions
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Firmware uses 32-bit field for region size while copying/backing-up
memory during MPIPL. So, the maximum copy size for a region would
be a page less than 4GB (aligned to pagesize) but FADump capture
kernel usually needs more memory than that to be preserved to avoid
running into out of memory errors.
So, request firmware to copy multiple kernel memory regions instead
of just one (which worked fine for pseries as 64-bit field was used
for size there). With support to copy multiple kernel memory regions,
also handle holes in the memory area to be preserved. Support as many
as 128 kernel memory regions. This allows having an adequate FADump
capture kernel size for different scenarios.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/kernel/fadump-common.c | 15 ++
arch/powerpc/kernel/fadump-common.h | 16 ++
arch/powerpc/kernel/fadump.c | 173 ++++++++++++++++++++++----
arch/powerpc/platforms/powernv/opal-fadump.c | 25 +++-
arch/powerpc/platforms/powernv/opal-fadump.h | 5 -
arch/powerpc/platforms/pseries/rtas-fadump.c | 12 ++
arch/powerpc/platforms/pseries/rtas-fadump.h | 5 +
7 files changed, 211 insertions(+), 40 deletions(-)
diff --git a/arch/powerpc/kernel/fadump-common.c b/arch/powerpc/kernel/fadump-common.c
index 76c1233..731b929 100644
--- a/arch/powerpc/kernel/fadump-common.c
+++ b/arch/powerpc/kernel/fadump-common.c
@@ -125,10 +125,19 @@ static int is_fadump_memory_area_contiguous(unsigned long d_start,
*/
int is_fadump_boot_mem_contiguous(struct fw_dump *fadump_conf)
{
- unsigned long d_start = RMA_START;
- unsigned long d_end = RMA_START + fadump_conf->boot_memory_size;
+ int i, ret = 0;
+ unsigned long d_start, d_end;
- return is_fadump_memory_area_contiguous(d_start, d_end);
+ for (i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
+ d_start = fadump_conf->boot_mem_addr[i];
+ d_end = d_start + fadump_conf->boot_mem_size[i];
+
+ ret = is_fadump_memory_area_contiguous(d_start, d_end);
+ if (!ret)
+ break;
+ }
+
+ return ret;
}
/*
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index 89b8916..06d9ecf 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -94,6 +94,9 @@ struct fad_crash_memory_ranges {
/* Platform specific callback functions */
struct fadump_ops;
+/* Maximum number of memory regions kernel supports */
+#define FADUMP_MAX_MEM_REGS 128
+
/* Firmware-assisted dump configuration details. */
struct fw_dump {
unsigned long reserve_dump_area_start;
@@ -109,14 +112,23 @@ struct fw_dump {
unsigned long cpu_state_data_size;
unsigned long hpte_region_size;
+
unsigned long boot_memory_size;
+ unsigned long boot_mem_dest_addr;
+ unsigned long boot_mem_regs_cnt;
+ unsigned long boot_mem_addr[FADUMP_MAX_MEM_REGS];
+ unsigned long boot_mem_size[FADUMP_MAX_MEM_REGS];
+ unsigned long boot_mem_top;
unsigned long fadumphdr_addr;
unsigned long cpu_notes_buf;
unsigned long cpu_notes_buf_size;
- unsigned long boot_mem_dest_addr;
-
+ /*
+ * Maximum size supported by firmware to copy from source to
+ * destination address per entry.
+ */
+ unsigned long max_copy_size;
u64 kernel_metadata;
int ibm_configure_kernel_dump;
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 4dd8037..abf4f334 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -128,6 +128,7 @@ int is_fadump_memory_area(u64 addr, ulong size)
{
u64 d_start = fw_dump.reserve_dump_area_start;
u64 d_end = d_start + fw_dump.reserve_dump_area_size;
+ u64 b_end = fw_dump.boot_mem_top;
if (!fw_dump.dump_registered)
return 0;
@@ -135,7 +136,7 @@ int is_fadump_memory_area(u64 addr, ulong size)
if (((addr + size) > d_start) && (addr <= d_end))
return 1;
- return (addr + size) > RMA_START && addr <= fw_dump.boot_memory_size;
+ return (((addr + size) > RMA_START) && (addr <= b_end));
}
int should_fadump_crash(void)
@@ -153,6 +154,8 @@ int is_fadump_active(void)
/* Print firmware assisted dump configurations for debugging purpose. */
static void fadump_show_config(void)
{
+ int i;
+
pr_debug("Support for firmware-assisted dump (fadump): %s\n",
(fw_dump.fadump_supported ? "present" : "no support"));
@@ -166,7 +169,13 @@ static void fadump_show_config(void)
pr_debug("Dump section sizes:\n");
pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size);
pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size);
- pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size);
+ pr_debug(" Boot memory size : %lx\n", fw_dump.boot_memory_size);
+ pr_debug(" Boot memory top : %lx\n", fw_dump.boot_mem_top);
+ pr_debug("Boot meory regions count : %lx\n", fw_dump.boot_mem_regs_cnt);
+ for (i = 0; i < fw_dump.boot_mem_regs_cnt; i++) {
+ pr_debug("%d. base = %lx, size = %lx\n", (i+1),
+ fw_dump.boot_mem_addr[i], fw_dump.boot_mem_size[i]);
+ }
}
/**
@@ -264,6 +273,88 @@ static unsigned long get_fadump_area_size(void)
return size;
}
+static int __init add_boot_mem_region(unsigned long rstart,
+ unsigned long rsize)
+{
+ int i = fw_dump.boot_mem_regs_cnt++;
+
+ if (fw_dump.boot_mem_regs_cnt > FADUMP_MAX_MEM_REGS) {
+ fw_dump.boot_mem_regs_cnt = FADUMP_MAX_MEM_REGS;
+ return 0;
+ }
+
+ pr_debug("Added boot memory range[%d] [%#016lx-%#016lx)\n",
+ i, rstart, (rstart + rsize));
+ fw_dump.boot_mem_addr[i] = rstart;
+ fw_dump.boot_mem_size[i] = rsize;
+ return 1;
+}
+
+/*
+ * Firmware usually has a hard limit on the data it can copy per region.
+ * Honour that by splitting a memory range into multiple regions.
+ */
+static int __init add_boot_mem_regions(unsigned long mstart,
+ unsigned long msize)
+{
+ unsigned long rstart, rsize, max_size;
+ int ret = 1;
+
+ rstart = mstart;
+ max_size = fw_dump.max_copy_size ? fw_dump.max_copy_size : msize;
+ while (msize) {
+ if (msize > max_size)
+ rsize = max_size;
+ else
+ rsize = msize;
+
+ ret = add_boot_mem_region(rstart, rsize);
+ if (!ret)
+ break;
+
+ msize -= rsize;
+ rstart += rsize;
+ }
+
+ return ret;
+}
+
+static int __init fadump_get_boot_mem_regions(void)
+{
+ int ret = 1;
+ struct memblock_region *reg;
+ unsigned long base, size, cur_size, hole_size, last_end;
+ unsigned long mem_size = fw_dump.boot_memory_size;
+
+ fw_dump.boot_mem_regs_cnt = 0;
+
+ last_end = 0;
+ hole_size = 0;
+ cur_size = 0;
+ for_each_memblock(memory, reg) {
+ base = reg->base;
+ size = reg->size;
+ hole_size += (base - last_end);
+
+ if ((cur_size + size) >= mem_size) {
+ size = (mem_size - cur_size);
+ ret = add_boot_mem_regions(base, size);
+ break;
+ }
+
+ mem_size -= size;
+ cur_size += size;
+ ret = add_boot_mem_regions(base, size);
+ if (!ret)
+ break;
+
+ last_end = base + size;
+ }
+ fw_dump.boot_mem_top = fw_dump.boot_memory_size + hole_size;
+
+ return ret;
+}
+
static void __init fadump_reserve_crash_area(unsigned long base,
unsigned long size)
{
@@ -310,6 +401,10 @@ int __init fadump_reserve_mem(void)
ALIGN(fw_dump.boot_memory_size,
FADUMP_CMA_ALIGNMENT);
#endif
+ if (!fadump_get_boot_mem_regions()) {
+ pr_err("Too many holes in boot memory area to enable fadump\n");
+ goto error_out;
+ }
}
size = get_fadump_area_size();
@@ -319,7 +414,8 @@ int __init fadump_reserve_mem(void)
else
memory_boundary = memblock_end_of_DRAM();
- base = fw_dump.boot_memory_size;
+ base = fw_dump.boot_mem_top;
+ base = PAGE_ALIGN(base);
if (fw_dump.dump_active) {
pr_info("Firmware-assisted dump is active.\n");
@@ -612,36 +708,39 @@ static int fadump_init_elfcore_header(char *bufp)
static int fadump_setup_crash_memory_ranges(void)
{
struct memblock_region *reg;
- unsigned long long start, end;
- int ret;
+ unsigned long long start, end, offset;
+ int i, ret;
pr_debug("Setup crash memory ranges.\n");
crash_mem_ranges = 0;
+ offset = fw_dump.boot_mem_top;
/*
- * add the first memory chunk (RMA_START through boot_memory_size) as
- * a separate memory chunk. The reason is, at the time crash firmware
- * will move the content of this memory chunk to different location
- * specified during fadump registration. We need to create a separate
- * program header for this chunk with the correct offset.
+ * Boot memory region(s) registered with firmware are moved to
+ * a different location at the time of crash. Create separate program
+ * header(s) for this memory chunk(s) with the correct offset.
*/
- ret = fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size);
- if (ret)
- return ret;
+ for (i = 0; i < fw_dump.boot_mem_regs_cnt; i++) {
+ start = fw_dump.boot_mem_addr[i];
+ end = start + fw_dump.boot_mem_size[i];
+ ret = fadump_add_crash_memory(start, end);
+ if (ret)
+ return ret;
+ }
for_each_memblock(memory, reg) {
start = (unsigned long long)reg->base;
end = start + (unsigned long long)reg->size;
/*
- * skip the first memory chunk that is already added (RMA_START
+ * Skip the first memory chunk that is already added (RMA_START
* through boot_memory_size). This logic needs a relook if and
* when RMA_START changes to a non-zero value.
*/
BUILD_BUG_ON(RMA_START != 0);
- if (start < fw_dump.boot_memory_size) {
- if (end > fw_dump.boot_memory_size)
- start = fw_dump.boot_memory_size;
+ if (start < offset) {
+ if (end > offset)
+ start = offset;
else
continue;
}
@@ -662,17 +761,35 @@ static int fadump_setup_crash_memory_ranges(void)
*/
static inline unsigned long fadump_relocate(unsigned long paddr)
{
- if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
- return fw_dump.boot_mem_dest_addr + paddr;
- else
- return paddr;
+ unsigned long raddr, rstart, rend, rlast, hole_size;
+ int i;
+
+ hole_size = 0;
+ rlast = 0;
+ raddr = paddr;
+ for (i = 0; i < fw_dump.boot_mem_regs_cnt; i++) {
+ rstart = fw_dump.boot_mem_addr[i];
+ rend = rstart + fw_dump.boot_mem_size[i];
+ hole_size += (rstart - rlast);
+
+ if (paddr >= rstart && paddr < rend) {
+ raddr += fw_dump.boot_mem_dest_addr - hole_size;
+ break;
+ }
+
+ rlast = rend;
+ }
+
+ pr_debug("vmcoreinfo: paddr = 0x%lx, raddr = 0x%lx\n", paddr, raddr);
+ return raddr;
}
static int fadump_create_elfcore_headers(char *bufp)
{
struct elfhdr *elf;
struct elf_phdr *phdr;
- int i;
+ unsigned long long raddr, offset;
+ int i, j;
fadump_init_elfcore_header(bufp);
elf = (struct elfhdr *)bufp;
@@ -715,7 +832,9 @@ static int fadump_create_elfcore_headers(char *bufp)
(elf->e_phnum)++;
/* setup PT_LOAD sections. */
-
+ j = 0;
+ offset = 0;
+ raddr = fw_dump.boot_mem_addr[0];
for (i = 0; i < crash_mem_ranges; i++) {
unsigned long long mbase, msize;
mbase = crash_memory_ranges[i].base;
@@ -730,13 +849,17 @@ static int fadump_create_elfcore_headers(char *bufp)
phdr->p_flags = PF_R|PF_W|PF_X;
phdr->p_offset = mbase;
- if (mbase == RMA_START) {
+ if (mbase == raddr) {
/*
* The entire RMA region will be moved by firmware
* to the specified destination_address. Hence set
* the correct offset.
*/
- phdr->p_offset = fw_dump.boot_mem_dest_addr;
+ phdr->p_offset = fw_dump.boot_mem_dest_addr + offset;
+ if (j < (fw_dump.boot_mem_regs_cnt - 1)) {
+ offset += fw_dump.boot_mem_size[j];
+ raddr = fw_dump.boot_mem_addr[++j];
+ }
}
phdr->p_paddr = mbase;
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
index 2179126..9c68c83 100644
--- a/arch/powerpc/platforms/powernv/opal-fadump.c
+++ b/arch/powerpc/platforms/powernv/opal-fadump.c
@@ -30,6 +30,8 @@ static struct opal_fadump_mem_struct *opal_fdm;
static void opal_fadump_update_config(struct fw_dump *fadump_conf,
const struct opal_fadump_mem_struct *fdm)
{
+ pr_debug("Boot memory regions count: %d\n", fdm->region_cnt);
+
/*
* The destination address of the first boot memory region is the
* destination address of boot memory regions.
@@ -44,15 +46,22 @@ static void opal_fadump_update_config(struct fw_dump *fadump_conf,
static ulong opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
{
ulong addr = fadump_conf->reserve_dump_area_start;
+ int i;
opal_fdm = __va(fadump_conf->kernel_metadata);
opal_fdm->version = OPAL_FADUMP_VERSION;
- opal_fdm->region_cnt = 1;
+ opal_fdm->region_cnt = 0;
opal_fdm->registered_regions = 0;
- opal_fdm->rgn[0].src = RMA_START;
- opal_fdm->rgn[0].dest = addr;
- opal_fdm->rgn[0].size = fadump_conf->boot_memory_size;
- addr += fadump_conf->boot_memory_size;
+
+ /* RMA regions */
+ for (i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
+ opal_fdm->rgn[i].src = fadump_conf->boot_mem_addr[i];
+ opal_fdm->rgn[i].dest = addr;
+ opal_fdm->rgn[i].size = fadump_conf->boot_mem_size[i];
+
+ opal_fdm->region_cnt++;
+ addr += fadump_conf->boot_mem_size[i];
+ }
/*
* Kernel metadata is passed to f/w and retrieved in capture kerenl.
@@ -236,5 +245,11 @@ int __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, ulong node)
fadump_conf->fadump_platform = FADUMP_PLATFORM_POWERNV;
fadump_conf->fadump_supported = 1;
+ /*
+ * Firmware currently supports only 32-bit value for size,
+ * align it to pagesize.
+ */
+ fadump_conf->max_copy_size = _ALIGN_DOWN(U32_MAX, PAGE_SIZE);
+
return 1;
}
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.h b/arch/powerpc/platforms/powernv/opal-fadump.h
index 7e5a579..423c9b2 100644
--- a/arch/powerpc/platforms/powernv/opal-fadump.h
+++ b/arch/powerpc/platforms/powernv/opal-fadump.h
@@ -16,9 +16,6 @@
/* OPAL FADump structure format version */
#define OPAL_FADUMP_VERSION 0x1
-/* Maximum number of memory regions kernel supports */
-#define OPAL_FADUMP_MAX_MEM_REGS 128
-
/*
* FADump memory structure for storing kernel metadata needed to
* register-for/process crash dump. The address of this structure will
@@ -31,7 +28,7 @@ struct opal_fadump_mem_struct {
u16 region_cnt; /* number of regions */
u16 registered_regions; /* Regions registered for MPIPL */
u64 fadumphdr_addr;
- struct opal_mpipl_region rgn[OPAL_FADUMP_MAX_MEM_REGS];
+ struct opal_mpipl_region rgn[FADUMP_MAX_MEM_REGS];
} __attribute__((packed));
#endif /* __PPC64_OPAL_FA_DUMP_H__ */
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c
index f2bcb1d..4372fb3 100644
--- a/arch/powerpc/platforms/pseries/rtas-fadump.c
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.c
@@ -56,7 +56,14 @@ static void rtas_fadump_update_config(struct fw_dump *fadump_conf,
static void rtas_fadump_get_config(struct fw_dump *fadump_conf,
const struct rtas_fadump_mem_struct *fdm)
{
- fadump_conf->boot_memory_size = be64_to_cpu(fdm->rmr_region.source_len);
+ fadump_conf->boot_mem_addr[0] =
+ be64_to_cpu(fdm->rmr_region.source_address);
+ fadump_conf->boot_mem_size[0] =
+ be64_to_cpu(fdm->rmr_region.source_len);
+ fadump_conf->boot_memory_size = fadump_conf->boot_mem_size[0];
+
+ fadump_conf->boot_mem_top = fadump_conf->boot_memory_size;
+ fadump_conf->boot_mem_regs_cnt = 1;
rtas_fadump_update_config(fadump_conf, fdm);
}
@@ -535,6 +542,9 @@ int __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, ulong node)
fadump_conf->fadump_platform = FADUMP_PLATFORM_PSERIES;
fadump_conf->fadump_supported = 1;
+ /* Firmware supports 64-bit value for size, align it to pagesize. */
+ fadump_conf->max_copy_size = _ALIGN_DOWN(U64_MAX, PAGE_SIZE);
+
/*
* The 'ibm,kernel-dump' rtas node is present only if there is
* dump data waiting for us.
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h
index 0cc6dfe3..25da5b8 100644
--- a/arch/powerpc/platforms/pseries/rtas-fadump.h
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.h
@@ -67,6 +67,11 @@ struct rtas_fadump_mem_struct {
/* Kernel dump sections */
struct rtas_fadump_section cpu_state_data;
struct rtas_fadump_section hpte_region;
+
+ /*
+ * TODO: Extend multiple boot memory regions support in the kernel
+ * for this platform.
+ */
struct rtas_fadump_section rmr_region;
};
^ permalink raw reply related
* [PATCH v4 12/25] powernv/fadump: define register/un-register callback functions
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Make OPAL calls to register and un-register with firmware for MPIPL.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/platforms/powernv/opal-fadump.c | 71 +++++++++++++++++++++++++-
1 file changed, 69 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
index 4b8504e..2179126 100644
--- a/arch/powerpc/platforms/powernv/opal-fadump.c
+++ b/arch/powerpc/platforms/powernv/opal-fadump.c
@@ -27,6 +27,20 @@
static struct opal_fadump_mem_struct *opal_fdm;
+static void opal_fadump_update_config(struct fw_dump *fadump_conf,
+ const struct opal_fadump_mem_struct *fdm)
+{
+ /*
+ * The destination address of the first boot memory region is the
+ * destination address of boot memory regions.
+ */
+ fadump_conf->boot_mem_dest_addr = fdm->rgn[0].dest;
+ pr_debug("Destination address of boot memory regions: %#016lx\n",
+ fadump_conf->boot_mem_dest_addr);
+
+ fadump_conf->fadumphdr_addr = fdm->fadumphdr_addr;
+}
+
static ulong opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
{
ulong addr = fadump_conf->reserve_dump_area_start;
@@ -47,6 +61,8 @@ static ulong opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest +
fadump_conf->boot_memory_size);
+ opal_fadump_update_config(fadump_conf, opal_fdm);
+
return addr;
}
@@ -88,12 +104,63 @@ static int opal_fadump_setup_kernel_metadata(struct fw_dump *fadump_conf)
static int opal_fadump_register_fadump(struct fw_dump *fadump_conf)
{
- return -EIO;
+ int i, err = -EIO;
+ s64 rc;
+
+ for (i = 0; i < opal_fdm->region_cnt; i++) {
+ rc = opal_mpipl_update(OPAL_MPIPL_ADD_RANGE,
+ opal_fdm->rgn[i].src,
+ opal_fdm->rgn[i].dest,
+ opal_fdm->rgn[i].size);
+ if (rc != OPAL_SUCCESS)
+ break;
+
+ opal_fdm->registered_regions++;
+ }
+
+ switch (rc) {
+ case OPAL_SUCCESS:
+ pr_info("Registration is successful!\n");
+ fadump_conf->dump_registered = 1;
+ err = 0;
+ break;
+ case OPAL_UNSUPPORTED:
+ pr_err("Support not available.\n");
+ fadump_conf->fadump_supported = 0;
+ fadump_conf->fadump_enabled = 0;
+ break;
+ case OPAL_INTERNAL_ERROR:
+ pr_err("Failed to register. Hardware Error(%lld).\n", rc);
+ break;
+ case OPAL_PARAMETER:
+ pr_err("Failed to register. Parameter Error(%lld).\n", rc);
+ break;
+ case OPAL_PERMISSION:
+ pr_err("Already registered!\n");
+ fadump_conf->dump_registered = 1;
+ err = -EEXIST;
+ break;
+ default:
+ pr_err("Failed to register. Unknown Error(%lld).\n", rc);
+ break;
+ }
+
+ return err;
}
static int opal_fadump_unregister_fadump(struct fw_dump *fadump_conf)
{
- return -EIO;
+ s64 rc;
+
+ rc = opal_mpipl_update(OPAL_MPIPL_REMOVE_ALL, 0, 0, 0);
+ if (rc) {
+ pr_err("Failed to un-register - unexpected Error(%lld).\n", rc);
+ return -EIO;
+ }
+
+ opal_fdm->registered_regions = 0;
+ fadump_conf->dump_registered = 0;
+ return 0;
}
static int opal_fadump_invalidate_fadump(struct fw_dump *fadump_conf)
^ permalink raw reply related
* [PATCH v4 11/25] powernv/fadump: register kernel metadata address with opal
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
OPAL allows registering address with it in the first kernel and
retrieving it after MPIPL. Setup kernel metadata and register its
address with OPAL to use it for processing the crash dump.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/kernel/fadump-common.h | 4 +
arch/powerpc/kernel/fadump.c | 65 ++++++++++++++---------
arch/powerpc/platforms/powernv/opal-fadump.c | 73 ++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/opal-fadump.h | 37 +++++++++++++
arch/powerpc/platforms/pseries/rtas-fadump.c | 32 +++++++++--
5 files changed, 177 insertions(+), 34 deletions(-)
create mode 100644 arch/powerpc/platforms/powernv/opal-fadump.h
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index 928d364..89b8916 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -117,6 +117,8 @@ struct fw_dump {
unsigned long boot_mem_dest_addr;
+ u64 kernel_metadata;
+
int ibm_configure_kernel_dump;
unsigned long fadump_enabled:1;
@@ -131,6 +133,8 @@ struct fw_dump {
struct fadump_ops {
ulong (*init_fadump_mem_struct)(struct fw_dump *fadump_config);
+ ulong (*get_kernel_metadata_size)(void);
+ int (*setup_kernel_metadata)(struct fw_dump *fadump_config);
int (*register_fadump)(struct fw_dump *fadump_config);
int (*unregister_fadump)(struct fw_dump *fadump_config);
int (*invalidate_fadump)(struct fw_dump *fadump_config);
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 517a40b..4dd8037 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -258,6 +258,9 @@ static unsigned long get_fadump_area_size(void)
size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2);
size = PAGE_ALIGN(size);
+
+ /* This is to hold kernel metadata on platforms that support it */
+ size += fw_dump.ops->get_kernel_metadata_size();
return size;
}
@@ -283,17 +286,17 @@ static void __init fadump_reserve_crash_area(unsigned long base,
int __init fadump_reserve_mem(void)
{
+ int ret = 1;
unsigned long base, size, memory_boundary;
if (!fw_dump.fadump_enabled)
return 0;
if (!fw_dump.fadump_supported) {
- printk(KERN_INFO "Firmware-assisted dump is not supported on"
- " this hardware\n");
- fw_dump.fadump_enabled = 0;
- return 0;
+ pr_info("Firmware-Assisted Dump is not supported on this hardware\n");
+ goto error_out;
}
+
/*
* Initialize boot memory size
* If dump is active then we have already calculated the size during
@@ -310,11 +313,13 @@ int __init fadump_reserve_mem(void)
}
size = get_fadump_area_size();
+ fw_dump.reserve_dump_area_size = size;
if (memory_limit)
memory_boundary = memory_limit;
else
memory_boundary = memblock_end_of_DRAM();
+ base = fw_dump.boot_memory_size;
if (fw_dump.dump_active) {
pr_info("Firmware-assisted dump is active.\n");
@@ -332,13 +337,11 @@ int __init fadump_reserve_mem(void)
* dump is written to disk by userspace tool. This memory
* will be released for general use once the dump is saved.
*/
- base = fw_dump.boot_memory_size;
size = memory_boundary - base;
fadump_reserve_crash_area(base, size);
pr_debug("fadumphdr_addr = %#016lx\n", fw_dump.fadumphdr_addr);
fw_dump.reserve_dump_area_start = base;
- fw_dump.reserve_dump_area_size = size;
} else {
/*
* Reserve memory at an offset closer to bottom of the RAM to
@@ -346,30 +349,42 @@ int __init fadump_reserve_mem(void)
* use memblock_find_in_range() here since it doesn't allocate
* from bottom to top.
*/
- for (base = fw_dump.boot_memory_size;
- base <= (memory_boundary - size);
- base += size) {
+ while (base <= (memory_boundary - size)) {
if (memblock_is_region_memory(base, size) &&
!memblock_is_region_reserved(base, size))
break;
+
+ base += size;
}
- if ((base > (memory_boundary - size)) ||
- memblock_reserve(base, size)) {
+
+ if (base > (memory_boundary - size)) {
+ pr_err("Failed to find memory chunk for reservation\n");
+ goto error_out;
+ }
+ fw_dump.reserve_dump_area_start = base;
+
+ /*
+ * Calculate the kernel metadata address and register it with
+ * f/w if the platform supports.
+ */
+ if (fw_dump.ops->setup_kernel_metadata(&fw_dump) < 0)
+ goto error_out;
+
+ if (memblock_reserve(base, size)) {
pr_err("Failed to reserve memory\n");
- return 0;
+ goto error_out;
}
- pr_info("Reserved %ldMB of memory at %ldMB for firmware-"
- "assisted dump (System RAM: %ldMB)\n",
- (unsigned long)(size >> 20),
- (unsigned long)(base >> 20),
+ pr_info("Reserved %ldMB of memory at %#016lx (System RAM: %ldMB)\n",
+ (unsigned long)(size >> 20), base,
(unsigned long)(memblock_phys_mem_size() >> 20));
- fw_dump.reserve_dump_area_start = base;
- fw_dump.reserve_dump_area_size = size;
- return fadump_cma_init();
+ ret = fadump_cma_init();
}
- return 1;
+ return ret;
+error_out:
+ fw_dump.fadump_enabled = 0;
+ return 0;
}
unsigned long __init arch_reserved_kernel_pages(void)
@@ -886,14 +901,14 @@ static void fadump_invalidate_release_mem(void)
* later for releasing the memory for general use.
*/
reserved_area_start = fw_dump.reserve_dump_area_start;
- reserved_area_end = reserved_area_start +
- fw_dump.reserve_dump_area_size;
+ reserved_area_end =
+ memory_limit ? memory_limit : memblock_end_of_DRAM();
+
/*
- * Setup reserve_dump_area_start and its size so that we can
- * reuse this reserved memory for Re-registration.
+ * Setup reserve_dump_area_start so that we can reuse this
+ * reserved memory for Re-registration.
*/
fw_dump.reserve_dump_area_start = destination_address;
- fw_dump.reserve_dump_area_size = get_fadump_area_size();
fadump_release_memory(reserved_area_start, reserved_area_end);
if (fw_dump.cpu_notes_buf) {
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
index d8ee836..4b8504e 100644
--- a/arch/powerpc/platforms/powernv/opal-fadump.c
+++ b/arch/powerpc/platforms/powernv/opal-fadump.c
@@ -17,14 +17,73 @@
#include <linux/seq_file.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
+#include <linux/mm.h>
+#include <asm/page.h>
#include <asm/opal.h>
#include "../../kernel/fadump-common.h"
+#include "opal-fadump.h"
+
+static struct opal_fadump_mem_struct *opal_fdm;
static ulong opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
{
- return fadump_conf->reserve_dump_area_start;
+ ulong addr = fadump_conf->reserve_dump_area_start;
+
+ opal_fdm = __va(fadump_conf->kernel_metadata);
+ opal_fdm->version = OPAL_FADUMP_VERSION;
+ opal_fdm->region_cnt = 1;
+ opal_fdm->registered_regions = 0;
+ opal_fdm->rgn[0].src = RMA_START;
+ opal_fdm->rgn[0].dest = addr;
+ opal_fdm->rgn[0].size = fadump_conf->boot_memory_size;
+ addr += fadump_conf->boot_memory_size;
+
+ /*
+ * Kernel metadata is passed to f/w and retrieved in capture kerenl.
+ * So, use it to save fadump header address instead of calculating it.
+ */
+ opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest +
+ fadump_conf->boot_memory_size);
+
+ return addr;
+}
+
+static ulong opal_fadump_get_kernel_metadata_size(void)
+{
+ ulong size = sizeof(struct opal_fadump_mem_struct);
+
+ size = PAGE_ALIGN(size);
+ return size;
+}
+
+static int opal_fadump_setup_kernel_metadata(struct fw_dump *fadump_conf)
+{
+ int err = 0;
+ s64 ret;
+
+ /*
+ * Use the last page(s) in FADump memory reservation for
+ * kernel metadata.
+ */
+ fadump_conf->kernel_metadata = (fadump_conf->reserve_dump_area_start +
+ fadump_conf->reserve_dump_area_size -
+ opal_fadump_get_kernel_metadata_size());
+ pr_info("Kernel metadata addr: %llx\n", fadump_conf->kernel_metadata);
+
+ /*
+ * Register metadata address with f/w. Can be retrieved in
+ * the capture kernel.
+ */
+ ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL,
+ fadump_conf->kernel_metadata);
+ if (ret != OPAL_SUCCESS) {
+ pr_err("Failed to set kernel metadata tag!\n");
+ err = -EPERM;
+ }
+
+ return err;
}
static int opal_fadump_register_fadump(struct fw_dump *fadump_conf)
@@ -50,6 +109,16 @@ static int __init opal_fadump_process_fadump(struct fw_dump *fadump_conf)
static void opal_fadump_region_show(struct fw_dump *fadump_conf,
struct seq_file *m)
{
+ int i;
+ const struct opal_fadump_mem_struct *fdm_ptr = opal_fdm;
+ u64 dumped_bytes = 0;
+
+ for (i = 0; i < fdm_ptr->region_cnt; i++) {
+ seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
+ fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest);
+ seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
+ fdm_ptr->rgn[i].size, dumped_bytes);
+ }
}
static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
@@ -67,6 +136,8 @@ static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
static struct fadump_ops opal_fadump_ops = {
.init_fadump_mem_struct = opal_fadump_init_mem_struct,
+ .get_kernel_metadata_size = opal_fadump_get_kernel_metadata_size,
+ .setup_kernel_metadata = opal_fadump_setup_kernel_metadata,
.register_fadump = opal_fadump_register_fadump,
.unregister_fadump = opal_fadump_unregister_fadump,
.invalidate_fadump = opal_fadump_invalidate_fadump,
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.h b/arch/powerpc/platforms/powernv/opal-fadump.h
new file mode 100644
index 0000000..7e5a579
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-fadump.h
@@ -0,0 +1,37 @@
+/*
+ * Firmware-Assisted Dump support on POWER platform (OPAL).
+ *
+ * Copyright 2019, IBM Corp.
+ * Author: Hari Bathini <hbathini@linux.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __PPC64_OPAL_FA_DUMP_H__
+#define __PPC64_OPAL_FA_DUMP_H__
+
+/* OPAL FADump structure format version */
+#define OPAL_FADUMP_VERSION 0x1
+
+/* Maximum number of memory regions kernel supports */
+#define OPAL_FADUMP_MAX_MEM_REGS 128
+
+/*
+ * FADump memory structure for storing kernel metadata needed to
+ * register-for/process crash dump. The address of this structure will
+ * be registered with f/w for retrieving during crash dump.
+ */
+struct opal_fadump_mem_struct {
+
+ u8 version;
+ u8 reserved[3];
+ u16 region_cnt; /* number of regions */
+ u16 registered_regions; /* Regions registered for MPIPL */
+ u64 fadumphdr_addr;
+ struct opal_mpipl_region rgn[OPAL_FADUMP_MAX_MEM_REGS];
+} __attribute__((packed));
+
+#endif /* __PPC64_OPAL_FA_DUMP_H__ */
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c
index 7ce84f8..f2bcb1d 100644
--- a/arch/powerpc/platforms/pseries/rtas-fadump.c
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.c
@@ -123,6 +123,21 @@ static ulong rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
return addr;
}
+/*
+ * On this platform, the metadata struture is passed while registering
+ * for FADump and the same is returned by f/w in capture kernel.
+ * No additional provision to setup metadata separately.
+ */
+static ulong rtas_fadump_get_kernel_metadata_size(void)
+{
+ return 0;
+}
+
+static int rtas_fadump_setup_kernel_metadata(struct fw_dump *fadump_conf)
+{
+ return 0;
+}
+
static int rtas_fadump_register_fadump(struct fw_dump *fadump_conf)
{
int rc, err = -EIO;
@@ -488,15 +503,16 @@ static void rtas_fadump_trigger(struct fadump_crash_info_header *fdh,
rtas_os_term((char *)msg);
}
-
static struct fadump_ops rtas_fadump_ops = {
- .init_fadump_mem_struct = rtas_fadump_init_mem_struct,
- .register_fadump = rtas_fadump_register_fadump,
- .unregister_fadump = rtas_fadump_unregister_fadump,
- .invalidate_fadump = rtas_fadump_invalidate_fadump,
- .process_fadump = rtas_fadump_process_fadump,
- .fadump_region_show = rtas_fadump_region_show,
- .fadump_trigger = rtas_fadump_trigger,
+ .init_fadump_mem_struct = rtas_fadump_init_mem_struct,
+ .get_kernel_metadata_size = rtas_fadump_get_kernel_metadata_size,
+ .setup_kernel_metadata = rtas_fadump_setup_kernel_metadata,
+ .register_fadump = rtas_fadump_register_fadump,
+ .unregister_fadump = rtas_fadump_unregister_fadump,
+ .invalidate_fadump = rtas_fadump_invalidate_fadump,
+ .process_fadump = rtas_fadump_process_fadump,
+ .fadump_region_show = rtas_fadump_region_show,
+ .fadump_trigger = rtas_fadump_trigger,
};
int __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, ulong node)
^ permalink raw reply related
* [PATCH v4 10/25] powernv/fadump: add fadump support on powernv
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Add basic callback functions for FADump on PowerNV platform.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/Kconfig | 5 +
arch/powerpc/kernel/fadump-common.h | 10 +++
arch/powerpc/kernel/fadump.c | 3 +
arch/powerpc/platforms/powernv/Makefile | 1
arch/powerpc/platforms/powernv/opal-fadump.c | 102 ++++++++++++++++++++++++++
5 files changed, 119 insertions(+), 2 deletions(-)
create mode 100644 arch/powerpc/platforms/powernv/opal-fadump.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index f516796..0ce0a80 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -566,7 +566,7 @@ config CRASH_DUMP
config FA_DUMP
bool "Firmware-assisted dump"
- depends on PPC64 && PPC_RTAS
+ depends on PPC64 && (PPC_RTAS || PPC_POWERNV)
select CRASH_CORE
select CRASH_DUMP
help
@@ -577,7 +577,8 @@ config FA_DUMP
is meant to be a kdump replacement offering robustness and
speed not possible without system firmware assistance.
- If unsure, say "N"
+ If unsure, say "y". Only special kernels like petitboot may
+ need to say "N" here.
config IRQ_ALL_CPUS
bool "Distribute interrupts on all CPUs by default"
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index 0231a0b..928d364 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -54,6 +54,7 @@
enum fadump_platform_type {
FADUMP_PLATFORM_UNKNOWN = 0,
FADUMP_PLATFORM_PSERIES,
+ FADUMP_PLATFORM_POWERNV,
};
/*
@@ -157,4 +158,13 @@ static inline int rtas_fadump_dt_scan(struct fw_dump *fadump_config, ulong node)
}
#endif
+#ifdef CONFIG_PPC_POWERNV
+extern int opal_fadump_dt_scan(struct fw_dump *fadump_config, ulong node);
+#else
+static inline int opal_fadump_dt_scan(struct fw_dump *fadump_config, ulong node)
+{
+ return 1;
+}
+#endif
+
#endif /* __PPC64_FA_DUMP_INTERNAL_H__ */
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index e995db1..517a40b 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -114,6 +114,9 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
if (strcmp(uname, "rtas") == 0)
return rtas_fadump_dt_scan(&fw_dump, node);
+ if (strcmp(uname, "ibm,opal") == 0)
+ return opal_fadump_dt_scan(&fw_dump, node);
+
return 0;
}
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index da2e99e..43a6e1c 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -6,6 +6,7 @@ obj-y += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
obj-y += opal-kmsg.o opal-powercap.o opal-psr.o opal-sensor-groups.o
obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o
+obj-$(CONFIG_FA_DUMP) += opal-fadump.o
obj-$(CONFIG_PCI) += pci.o pci-ioda.o npu-dma.o pci-ioda-tce.o
obj-$(CONFIG_CXL_BASE) += pci-cxl.o
obj-$(CONFIG_EEH) += eeh-powernv.o
diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
new file mode 100644
index 0000000..d8ee836
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-fadump.c
@@ -0,0 +1,102 @@
+/*
+ * Firmware-Assisted Dump support on POWER platform (OPAL).
+ *
+ * Copyright 2019, IBM Corp.
+ * Author: Hari Bathini <hbathini@linux.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "opal fadump: " fmt
+
+#include <linux/string.h>
+#include <linux/seq_file.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
+
+#include <asm/opal.h>
+
+#include "../../kernel/fadump-common.h"
+
+static ulong opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
+{
+ return fadump_conf->reserve_dump_area_start;
+}
+
+static int opal_fadump_register_fadump(struct fw_dump *fadump_conf)
+{
+ return -EIO;
+}
+
+static int opal_fadump_unregister_fadump(struct fw_dump *fadump_conf)
+{
+ return -EIO;
+}
+
+static int opal_fadump_invalidate_fadump(struct fw_dump *fadump_conf)
+{
+ return -EIO;
+}
+
+static int __init opal_fadump_process_fadump(struct fw_dump *fadump_conf)
+{
+ return -EINVAL;
+}
+
+static void opal_fadump_region_show(struct fw_dump *fadump_conf,
+ struct seq_file *m)
+{
+}
+
+static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
+ const char *msg)
+{
+ int rc;
+
+ rc = opal_cec_reboot2(OPAL_REBOOT_MPIPL, msg);
+ if (rc == OPAL_UNSUPPORTED) {
+ pr_emerg("Reboot type %d not supported.\n",
+ OPAL_REBOOT_MPIPL);
+ } else if (rc == OPAL_HARDWARE)
+ pr_emerg("No backend support for MPIPL!\n");
+}
+
+static struct fadump_ops opal_fadump_ops = {
+ .init_fadump_mem_struct = opal_fadump_init_mem_struct,
+ .register_fadump = opal_fadump_register_fadump,
+ .unregister_fadump = opal_fadump_unregister_fadump,
+ .invalidate_fadump = opal_fadump_invalidate_fadump,
+ .process_fadump = opal_fadump_process_fadump,
+ .fadump_region_show = opal_fadump_region_show,
+ .fadump_trigger = opal_fadump_trigger,
+};
+
+int __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, ulong node)
+{
+ unsigned long dn;
+
+ /*
+ * Check if Firmware-Assisted Dump is supported. if yes, check
+ * if dump has been initiated on last reboot.
+ */
+ dn = of_get_flat_dt_subnode_by_name(node, "dump");
+ if (dn == -FDT_ERR_NOTFOUND) {
+ pr_debug("FADump support is missing!\n");
+ return 1;
+ }
+
+ if (!of_flat_dt_is_compatible(dn, "ibm,opal-dump")) {
+ pr_err("Support missing for this f/w version!\n");
+ return 1;
+ }
+
+ fadump_conf->ops = &opal_fadump_ops;
+ fadump_conf->fadump_platform = FADUMP_PLATFORM_POWERNV;
+ fadump_conf->fadump_supported = 1;
+
+ return 1;
+}
^ permalink raw reply related
* [PATCH v4 09/25] opal: add MPIPL interface definitions
From: Hari Bathini @ 2019-07-16 11:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/include/asm/opal-api.h | 50 +++++++++++++++++++++++++++-
arch/powerpc/include/asm/opal.h | 6 +++
arch/powerpc/platforms/powernv/opal-call.c | 3 ++
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 383242e..c8a5665 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -208,7 +208,10 @@
#define OPAL_HANDLE_HMI2 166
#define OPAL_NX_COPROC_INIT 167
#define OPAL_XIVE_GET_VP_STATE 170
-#define OPAL_LAST 170
+#define OPAL_MPIPL_UPDATE 173
+#define OPAL_MPIPL_REGISTER_TAG 174
+#define OPAL_MPIPL_QUERY_TAG 175
+#define OPAL_LAST 175
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
@@ -980,6 +983,50 @@ struct opal_sg_list {
};
/*
+ * Firmware-Assisted Dump (FADump) using MPIPL
+ */
+
+/* MPIPL update operations */
+enum opal_mpipl_ops {
+ OPAL_MPIPL_ADD_RANGE = 0,
+ OPAL_MPIPL_REMOVE_RANGE = 1,
+ OPAL_MPIPL_REMOVE_ALL = 2,
+ OPAL_MPIPL_FREE_PRESERVED_MEMORY = 3,
+};
+
+/*
+ * Each tag maps to a metadata type. Use these tags to register/query
+ * corresponding metadata address with/from OPAL.
+ */
+enum opal_mpipl_tags {
+ OPAL_MPIPL_TAG_CPU = 0,
+ OPAL_MPIPL_TAG_OPAL = 1,
+ OPAL_MPIPL_TAG_KERNEL = 2,
+ OPAL_MPIPL_TAG_BOOT_MEM = 3,
+};
+
+/* Preserved memory details */
+struct opal_mpipl_region {
+ __be64 src;
+ __be64 dest;
+ __be64 size;
+};
+
+/* FADump structure format version */
+#define MPIPL_FADUMP_VERSION 0x01
+
+/* Metadata provided by OPAL. */
+struct opal_mpipl_fadump {
+ u8 version;
+ u8 reserved[7];
+ __be32 crashing_pir;
+ __be32 cpu_data_version;
+ __be32 cpu_data_size;
+ __be32 region_cnt;
+ struct opal_mpipl_region region[];
+} __attribute__((packed));
+
+/*
* Dump region ID range usable by the OS
*/
#define OPAL_DUMP_REGION_HOST_START 0x80
@@ -1059,6 +1106,7 @@ enum {
OPAL_REBOOT_NORMAL = 0,
OPAL_REBOOT_PLATFORM_ERROR = 1,
OPAL_REBOOT_FULL_IPL = 2,
+ OPAL_REBOOT_MPIPL = 3,
};
/* Argument to OPAL_PCI_TCE_KILL */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 57bd029..878110a 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -39,6 +39,12 @@ int64_t opal_npu_spa_clear_cache(uint64_t phb_id, uint32_t bdfn,
uint64_t PE_handle);
int64_t opal_npu_tl_set(uint64_t phb_id, uint32_t bdfn, long cap,
uint64_t rate_phys, uint32_t size);
+
+int64_t opal_mpipl_update(enum opal_mpipl_ops op, u64 src,
+ u64 dest, u64 size);
+int64_t opal_mpipl_register_tag(enum opal_mpipl_tags tag, uint64_t addr);
+int64_t opal_mpipl_query_tag(enum opal_mpipl_tags tag, uint64_t *addr);
+
int64_t opal_console_write(int64_t term_number, __be64 *length,
const uint8_t *buffer);
int64_t opal_console_read(int64_t term_number, __be64 *length,
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 29ca523..fc8cc7c 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -287,3 +287,6 @@ OPAL_CALL(opal_pci_set_pbcq_tunnel_bar, OPAL_PCI_SET_PBCQ_TUNNEL_BAR);
OPAL_CALL(opal_sensor_read_u64, OPAL_SENSOR_READ_U64);
OPAL_CALL(opal_sensor_group_enable, OPAL_SENSOR_GROUP_ENABLE);
OPAL_CALL(opal_nx_coproc_init, OPAL_NX_COPROC_INIT);
+OPAL_CALL(opal_mpipl_update, OPAL_MPIPL_UPDATE);
+OPAL_CALL(opal_mpipl_register_tag, OPAL_MPIPL_REGISTER_TAG);
+OPAL_CALL(opal_mpipl_query_tag, OPAL_MPIPL_QUERY_TAG);
^ permalink raw reply related
* [PATCH v4 08/25] powerpc/fadump: use FADump instead of fadump for how it is pronounced
From: Hari Bathini @ 2019-07-16 11:32 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
fadump is pronounced f-a-dump. Update documentation accordingly. Also,
update how fadump_region contents look like with recent changes.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Documentation/powerpc/firmware-assisted-dump.txt | 71 ++++++++++++----------
1 file changed, 39 insertions(+), 32 deletions(-)
diff --git a/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt
index e9b4e3c..0c6a28c 100644
--- a/Documentation/powerpc/firmware-assisted-dump.txt
+++ b/Documentation/powerpc/firmware-assisted-dump.txt
@@ -8,18 +8,18 @@ a crashed system, and to do so from a fully-reset system, and
to minimize the total elapsed time until the system is back
in production use.
-- Firmware assisted dump (fadump) infrastructure is intended to replace
+- Firmware-Assisted Dump (FADump) infrastructure is intended to replace
the existing phyp assisted dump.
- Fadump uses the same firmware interfaces and memory reservation model
as phyp assisted dump.
-- Unlike phyp dump, fadump exports the memory dump through /proc/vmcore
+- Unlike phyp dump, FADump exports the memory dump through /proc/vmcore
in the ELF format in the same way as kdump. This helps us reuse the
kdump infrastructure for dump capture and filtering.
- Unlike phyp dump, userspace tool does not need to refer any sysfs
interface while reading /proc/vmcore.
-- Unlike phyp dump, fadump allows user to release all the memory reserved
+- Unlike phyp dump, FADump allows user to release all the memory reserved
for dump, with a single operation of echo 1 > /sys/kernel/fadump_release_mem.
-- Once enabled through kernel boot parameter, fadump can be
+- Once enabled through kernel boot parameter, FADump can be
started/stopped through /sys/kernel/fadump_registered interface (see
sysfs files section below) and can be easily integrated with kdump
service start/stop init scripts.
@@ -33,7 +33,7 @@ dump offers several strong, practical advantages:
in a clean, consistent state.
-- Once the dump is copied out, the memory that held the dump
is immediately available to the running kernel. And therefore,
- unlike kdump, fadump doesn't need a 2nd reboot to get back
+ unlike kdump, FADump doesn't need a 2nd reboot to get back
the system to the production configuration.
The above can only be accomplished by coordination with,
@@ -61,7 +61,7 @@ as follows:
boot successfully. For syntax of crashkernel= parameter,
refer to Documentation/kdump/kdump.rst. If any offset is
provided in crashkernel= parameter, it will be ignored
- as fadump uses a predefined offset to reserve memory
+ as FADump uses a predefined offset to reserve memory
for boot memory dump preservation in case of a crash.
-- After the low memory (boot memory) area has been saved, the
@@ -120,7 +120,7 @@ blocking this significant chunk of memory from production kernel.
Hence, the implementation uses the Linux kernel's Contiguous Memory
Allocator (CMA) for memory reservation if CMA is configured for kernel.
With CMA reservation this memory will be available for applications to
-use it, while kernel is prevented from using it. With this fadump will
+use it, while kernel is prevented from using it. With this FADump will
still be able to capture all of the kernel memory and most of the user
space memory except the user pages that were present in CMA region.
@@ -170,14 +170,14 @@ KDump, as dump mechanism.
The tools to examine the dump will be same as the ones
used for kdump.
-How to enable firmware-assisted dump (fadump):
+How to enable firmware-assisted dump (FADump):
---------------------------------------------
1. Set config option CONFIG_FA_DUMP=y and build kernel.
-2. Boot into linux kernel with 'fadump=on' kernel cmdline option.
- By default, fadump reserved memory will be initialized as CMA area.
- Alternatively, user can boot linux kernel with 'fadump=nocma' to
- prevent fadump to use CMA.
+2. Boot into linux kernel with 'FADump=on' kernel cmdline option.
+ By default, FADump reserved memory will be initialized as CMA area.
+ Alternatively, user can boot linux kernel with 'FADump=nocma' to
+ prevent FADump to use CMA.
3. Optionally, user can also set 'crashkernel=' kernel cmdline
to specify size of the memory to reserve for boot memory dump
preservation.
@@ -190,7 +190,7 @@ NOTE: 1. 'fadump_reserve_mem=' parameter has been deprecated. Instead
option is set at kernel cmdline.
3. if user wants to capture all of user space memory and ok with
reserved memory not available to production system, then
- 'fadump=nocma' kernel parameter can be used to fallback to
+ 'FADump=nocma' kernel parameter can be used to fallback to
old behaviour.
Sysfs/debugfs files:
@@ -203,29 +203,29 @@ Here is the list of files under kernel sysfs:
/sys/kernel/fadump_enabled
- This is used to display the fadump status.
- 0 = fadump is disabled
- 1 = fadump is enabled
+ This is used to display the FADump status.
+ 0 = FADump is disabled
+ 1 = FADump is enabled
This interface can be used by kdump init scripts to identify if
- fadump is enabled in the kernel and act accordingly.
+ FADump is enabled in the kernel and act accordingly.
/sys/kernel/fadump_registered
- This is used to display the fadump registration status as well
- as to control (start/stop) the fadump registration.
- 0 = fadump is not registered.
- 1 = fadump is registered and ready to handle system crash.
+ This is used to display the FADump registration status as well
+ as to control (start/stop) the FADump registration.
+ 0 = FADump is not registered.
+ 1 = FADump is registered and ready to handle system crash.
- To register fadump echo 1 > /sys/kernel/fadump_registered and
+ To register FADump echo 1 > /sys/kernel/fadump_registered and
echo 0 > /sys/kernel/fadump_registered for un-register and stop the
- fadump. Once the fadump is un-registered, the system crash will not
+ FADump. Once the FADump is un-registered, the system crash will not
be handled and vmcore will not be captured. This interface can be
easily integrated with kdump service start/stop.
/sys/kernel/fadump_release_mem
- This file is available only when fadump is active during
+ This file is available only when FADump is active during
second kernel. This is used to release the reserved memory
region that are held for saving crash dump. To release the
reserved memory echo 1 to it:
@@ -244,26 +244,33 @@ Here is the list of files under powerpc debugfs:
/sys/kernel/debug/powerpc/fadump_region
- This file shows the reserved memory regions if fadump is
+ This file shows the reserved memory regions if FADump is
enabled otherwise this file is empty. The output format
- is:
+ for regions provided by f/w is:
<region>: [<start>-<end>] <reserved-size> bytes, Dumped: <dump-size>
+ and for kernel DUMP region is:
+
+ DUMP: Src: <src-addr>, Dest: <dest-addr>, Size: <size>, Dumped: # bytes
+
e.g.
- Contents when fadump is registered during first kernel
+ Contents when FADump is registered during first kernel
# cat /sys/kernel/debug/powerpc/fadump_region
CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x0
HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x0
- DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x0
+ DUMP: Src: 0x00000000000000, Dest: 0x0000006fff1020, Size: 0x10000000, Dumped: 0x0 bytes
+ #
- Contents when fadump is active during second kernel
+ Contents when FADump is active during second kernel
# cat /sys/kernel/debug/powerpc/fadump_region
CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x40020
HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x1000
- DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x10000000
- : [0x00000010000000-0x0000006ffaffff] 0x5ffb0000 bytes, Dumped: 0x5ffb0000
+ DUMP: Src: 0x00000000000000, Dest: 0x0000006fff1020, Size: 0x10000000, Dumped: 0x10000000 bytes
+
+ Memory above 0x0000000010000000 is reserved for saving crash dump
+ #
NOTE: Please refer to Documentation/filesystems/debugfs.txt on
how to mount the debugfs filesystem.
@@ -274,7 +281,7 @@ TODO:
o Need to come up with the better approach to find out more
accurate boot memory size that is required for a kernel to
boot successfully when booted with restricted memory.
- o The fadump implementation introduces a fadump crash info structure
+ o The FADump implementation introduces a FADump crash info structure
in the scratch area before the ELF core header. The idea of introducing
this structure is to pass some important crash info data to the second
kernel which will help second kernel to populate ELF core header with
^ permalink raw reply related
* [PATCH v4 06/25] pseries/fadump: define register/un-register callback functions
From: Hari Bathini @ 2019-07-16 11:32 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Make RTAS calls to register and un-register for FADump. Also, update
how fadump_region contents are diplayed to provide more information.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/kernel/fadump-common.h | 2
arch/powerpc/kernel/fadump.c | 164 ++------------------------
arch/powerpc/platforms/pseries/rtas-fadump.c | 163 +++++++++++++++++++++++++-
3 files changed, 176 insertions(+), 153 deletions(-)
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index 020d582..273247d 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -108,6 +108,8 @@ struct fw_dump {
unsigned long cpu_notes_buf;
unsigned long cpu_notes_buf_size;
+ unsigned long boot_mem_dest_addr;
+
int ibm_configure_kernel_dump;
unsigned long fadump_enabled:1;
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index a901ca1..650ebf8 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -36,7 +36,6 @@
#include "../platforms/pseries/rtas-fadump.h"
static struct fw_dump fw_dump;
-static struct rtas_fadump_mem_struct fdm;
static const struct rtas_fadump_mem_struct *fdm_active;
static DEFINE_MUTEX(fadump_mutex);
@@ -179,61 +178,6 @@ static void fadump_show_config(void)
pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size);
}
-static unsigned long init_fadump_mem_struct(struct rtas_fadump_mem_struct *fdm,
- unsigned long addr)
-{
- if (!fdm)
- return 0;
-
- memset(fdm, 0, sizeof(struct rtas_fadump_mem_struct));
- addr = addr & PAGE_MASK;
-
- fdm->header.dump_format_version = cpu_to_be32(0x00000001);
- fdm->header.dump_num_sections = cpu_to_be16(3);
- fdm->header.dump_status_flag = 0;
- fdm->header.offset_first_dump_section =
- cpu_to_be32((u32)offsetof(struct rtas_fadump_mem_struct, cpu_state_data));
-
- /*
- * Fields for disk dump option.
- * We are not using disk dump option, hence set these fields to 0.
- */
- fdm->header.dd_block_size = 0;
- fdm->header.dd_block_offset = 0;
- fdm->header.dd_num_blocks = 0;
- fdm->header.dd_offset_disk_path = 0;
-
- /* set 0 to disable an automatic dump-reboot. */
- fdm->header.max_time_auto = 0;
-
- /* Kernel dump sections */
- /* cpu state data section. */
- fdm->cpu_state_data.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
- fdm->cpu_state_data.source_data_type = cpu_to_be16(RTAS_FADUMP_CPU_STATE_DATA);
- fdm->cpu_state_data.source_address = 0;
- fdm->cpu_state_data.source_len = cpu_to_be64(fw_dump.cpu_state_data_size);
- fdm->cpu_state_data.destination_address = cpu_to_be64(addr);
- addr += fw_dump.cpu_state_data_size;
-
- /* hpte region section */
- fdm->hpte_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
- fdm->hpte_region.source_data_type = cpu_to_be16(RTAS_FADUMP_HPTE_REGION);
- fdm->hpte_region.source_address = 0;
- fdm->hpte_region.source_len = cpu_to_be64(fw_dump.hpte_region_size);
- fdm->hpte_region.destination_address = cpu_to_be64(addr);
- addr += fw_dump.hpte_region_size;
-
- /* RMA region section */
- fdm->rmr_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
- fdm->rmr_region.source_data_type = cpu_to_be16(RTAS_FADUMP_REAL_MODE_REGION);
- fdm->rmr_region.source_address = cpu_to_be64(RMA_START);
- fdm->rmr_region.source_len = cpu_to_be64(fw_dump.boot_memory_size);
- fdm->rmr_region.destination_address = cpu_to_be64(addr);
- addr += fw_dump.boot_memory_size;
-
- return addr;
-}
-
/**
* fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
*
@@ -480,61 +424,6 @@ static int __init early_fadump_reserve_mem(char *p)
}
early_param("fadump_reserve_mem", early_fadump_reserve_mem);
-static int register_fw_dump(struct rtas_fadump_mem_struct *fdm)
-{
- int rc, err;
- unsigned int wait_time;
-
- pr_debug("Registering for firmware-assisted kernel dump...\n");
-
- /* TODO: Add upper time limit for the delay */
- do {
- rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
- FADUMP_REGISTER, fdm,
- sizeof(struct rtas_fadump_mem_struct));
-
- wait_time = rtas_busy_delay_time(rc);
- if (wait_time)
- mdelay(wait_time);
-
- } while (wait_time);
-
- err = -EIO;
- switch (rc) {
- default:
- pr_err("Failed to register. Unknown Error(%d).\n", rc);
- break;
- case -1:
- printk(KERN_ERR "Failed to register firmware-assisted kernel"
- " dump. Hardware Error(%d).\n", rc);
- break;
- case -3:
- if (!is_fadump_boot_mem_contiguous(&fw_dump))
- pr_err("Can't have holes in boot memory area while registering fadump\n");
- else if (!is_fadump_reserved_mem_contiguous(&fw_dump))
- pr_err("Can't have holes in reserved memory area while"
- " registering fadump\n");
-
- printk(KERN_ERR "Failed to register firmware-assisted kernel"
- " dump. Parameter Error(%d).\n", rc);
- err = -EINVAL;
- break;
- case -9:
- printk(KERN_ERR "firmware-assisted kernel dump is already "
- " registered.");
- fw_dump.dump_registered = 1;
- err = -EEXIST;
- break;
- case 0:
- printk(KERN_INFO "firmware-assisted kernel dump registration"
- " is successful\n");
- fw_dump.dump_registered = 1;
- err = 0;
- break;
- }
- return err;
-}
-
void crash_fadump(struct pt_regs *regs, const char *str)
{
struct fadump_crash_info_header *fdh = NULL;
@@ -577,8 +466,7 @@ void crash_fadump(struct pt_regs *regs, const char *str)
fdh->online_mask = *cpu_online_mask;
- /* Call ibm,os-term rtas call to trigger firmware assisted dump */
- rtas_os_term((char *)str);
+ fw_dump.ops->fadump_trigger(fdh, str);
}
#define GPR_MASK 0xffffff0000000000
@@ -987,7 +875,7 @@ static int fadump_setup_crash_memory_ranges(void)
static inline unsigned long fadump_relocate(unsigned long paddr)
{
if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
- return be64_to_cpu(fdm.rmr_region.destination_address) + paddr;
+ return fw_dump.boot_mem_dest_addr + paddr;
else
return paddr;
}
@@ -1060,7 +948,7 @@ static int fadump_create_elfcore_headers(char *bufp)
* to the specified destination_address. Hence set
* the correct offset.
*/
- phdr->p_offset = be64_to_cpu(fdm.rmr_region.destination_address);
+ phdr->p_offset = fw_dump.boot_mem_dest_addr;
}
phdr->p_paddr = mbase;
@@ -1112,7 +1000,8 @@ static int register_fadump(void)
if (ret)
return ret;
- addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len);
+ addr = fw_dump.fadumphdr_addr;
+
/* Initialize fadump crash info header. */
addr = init_fadump_header(addr);
vaddr = __va(addr);
@@ -1121,34 +1010,8 @@ static int register_fadump(void)
fadump_create_elfcore_headers(vaddr);
/* register the future kernel dump with firmware. */
- return register_fw_dump(&fdm);
-}
-
-static int fadump_unregister_dump(struct rtas_fadump_mem_struct *fdm)
-{
- int rc = 0;
- unsigned int wait_time;
-
- pr_debug("Un-register firmware-assisted dump\n");
-
- /* TODO: Add upper time limit for the delay */
- do {
- rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
- FADUMP_UNREGISTER, fdm,
- sizeof(struct rtas_fadump_mem_struct));
-
- wait_time = rtas_busy_delay_time(rc);
- if (wait_time)
- mdelay(wait_time);
- } while (wait_time);
-
- if (rc) {
- printk(KERN_ERR "Failed to un-register firmware-assisted dump."
- " unexpected error(%d).\n", rc);
- return rc;
- }
- fw_dump.dump_registered = 0;
- return 0;
+ pr_debug("Registering for firmware-assisted kernel dump...\n");
+ return fw_dump.ops->register_fadump(&fw_dump);
}
static int fadump_invalidate_dump(const struct rtas_fadump_mem_struct *fdm)
@@ -1186,7 +1049,7 @@ void fadump_cleanup(void)
fadump_invalidate_dump(fdm_active);
} else if (fw_dump.dump_registered) {
/* Un-register Firmware-assisted dump if it was registered. */
- fadump_unregister_dump(&fdm);
+ fw_dump.ops->unregister_fadump(&fw_dump);
free_crash_memory_ranges();
}
}
@@ -1296,7 +1159,7 @@ static void fadump_invalidate_release_mem(void)
fw_dump.cpu_notes_buf_size = 0;
}
/* Initialize the kernel dump memory structure for FAD registration. */
- init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
+ fw_dump.ops->init_fadump_mem_struct(&fw_dump);
}
static ssize_t fadump_release_memory_store(struct kobject *kobj,
@@ -1361,12 +1224,12 @@ static ssize_t fadump_register_store(struct kobject *kobj,
goto unlock_out;
}
/* Un-register Firmware-assisted dump */
- fadump_unregister_dump(&fdm);
+ fw_dump.ops->unregister_fadump(&fw_dump);
break;
case 1:
if (fw_dump.dump_registered == 1) {
/* Un-register Firmware-assisted dump */
- fadump_unregister_dump(&fdm);
+ fw_dump.ops->unregister_fadump(&fw_dump);
}
/* Register Firmware-assisted dump */
ret = register_fadump();
@@ -1393,7 +1256,8 @@ static int fadump_region_show(struct seq_file *m, void *private)
fdm_ptr = fdm_active;
else {
mutex_unlock(&fadump_mutex);
- fdm_ptr = &fdm;
+ fw_dump.ops->fadump_region_show(&fw_dump, m);
+ return 0;
}
seq_printf(m,
@@ -1514,7 +1378,7 @@ int __init setup_fadump(void)
}
/* Initialize the kernel dump memory structure for FAD registration. */
else if (fw_dump.reserve_dump_area_size)
- init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
+ fw_dump.ops->init_fadump_mem_struct(&fw_dump);
fadump_init_files();
return 1;
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c
index 9e7c9bf..790a37d 100644
--- a/arch/powerpc/platforms/pseries/rtas-fadump.c
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.c
@@ -30,19 +30,152 @@
#include "../../kernel/fadump-common.h"
#include "rtas-fadump.h"
+static struct rtas_fadump_mem_struct fdm;
+
+static void rtas_fadump_update_config(struct fw_dump *fadump_conf,
+ const struct rtas_fadump_mem_struct *fdm)
+{
+ fadump_conf->boot_mem_dest_addr =
+ be64_to_cpu(fdm->rmr_region.destination_address);
+
+ fadump_conf->fadumphdr_addr = (fadump_conf->boot_mem_dest_addr +
+ fadump_conf->boot_memory_size);
+}
+
static ulong rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
{
- return fadump_conf->reserve_dump_area_start;
+ ulong addr = fadump_conf->reserve_dump_area_start;
+
+ memset(&fdm, 0, sizeof(struct rtas_fadump_mem_struct));
+ addr = addr & PAGE_MASK;
+
+ fdm.header.dump_format_version = cpu_to_be32(0x00000001);
+ fdm.header.dump_num_sections = cpu_to_be16(3);
+ fdm.header.dump_status_flag = 0;
+ fdm.header.offset_first_dump_section =
+ cpu_to_be32((u32)offsetof(struct rtas_fadump_mem_struct,
+ cpu_state_data));
+
+ /*
+ * Fields for disk dump option.
+ * We are not using disk dump option, hence set these fields to 0.
+ */
+ fdm.header.dd_block_size = 0;
+ fdm.header.dd_block_offset = 0;
+ fdm.header.dd_num_blocks = 0;
+ fdm.header.dd_offset_disk_path = 0;
+
+ /* set 0 to disable an automatic dump-reboot. */
+ fdm.header.max_time_auto = 0;
+
+ /* Kernel dump sections */
+ /* cpu state data section. */
+ fdm.cpu_state_data.request_flag =
+ cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
+ fdm.cpu_state_data.source_data_type =
+ cpu_to_be16(RTAS_FADUMP_CPU_STATE_DATA);
+ fdm.cpu_state_data.source_address = 0;
+ fdm.cpu_state_data.source_len =
+ cpu_to_be64(fadump_conf->cpu_state_data_size);
+ fdm.cpu_state_data.destination_address = cpu_to_be64(addr);
+ addr += fadump_conf->cpu_state_data_size;
+
+ /* hpte region section */
+ fdm.hpte_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
+ fdm.hpte_region.source_data_type =
+ cpu_to_be16(RTAS_FADUMP_HPTE_REGION);
+ fdm.hpte_region.source_address = 0;
+ fdm.hpte_region.source_len =
+ cpu_to_be64(fadump_conf->hpte_region_size);
+ fdm.hpte_region.destination_address = cpu_to_be64(addr);
+ addr += fadump_conf->hpte_region_size;
+
+ /* RMA region section */
+ fdm.rmr_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
+ fdm.rmr_region.source_data_type =
+ cpu_to_be16(RTAS_FADUMP_REAL_MODE_REGION);
+ fdm.rmr_region.source_address = cpu_to_be64(RMA_START);
+ fdm.rmr_region.source_len =
+ cpu_to_be64(fadump_conf->boot_memory_size);
+ fdm.rmr_region.destination_address = cpu_to_be64(addr);
+ addr += fadump_conf->boot_memory_size;
+
+ rtas_fadump_update_config(fadump_conf, &fdm);
+
+ return addr;
}
static int rtas_fadump_register_fadump(struct fw_dump *fadump_conf)
{
- return -EIO;
+ int rc, err = -EIO;
+ unsigned int wait_time;
+
+ /* TODO: Add upper time limit for the delay */
+ do {
+ rc = rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1,
+ NULL, FADUMP_REGISTER, &fdm,
+ sizeof(struct rtas_fadump_mem_struct));
+
+ wait_time = rtas_busy_delay_time(rc);
+ if (wait_time)
+ mdelay(wait_time);
+
+ } while (wait_time);
+
+ switch (rc) {
+ case 0:
+ pr_info("Registration is successful!\n");
+ fadump_conf->dump_registered = 1;
+ err = 0;
+ break;
+ case -1:
+ pr_err("Failed to register. Hardware Error(%d).\n", rc);
+ break;
+ case -3:
+ if (!is_fadump_boot_mem_contiguous(fadump_conf))
+ pr_err("Can't hot-remove boot memory area.\n");
+ else if (!is_fadump_reserved_mem_contiguous(fadump_conf))
+ pr_err("Can't hot-remove reserved memory area.\n");
+
+ pr_err("Failed to register. Parameter Error(%d).\n", rc);
+ err = -EINVAL;
+ break;
+ case -9:
+ pr_err("Already registered!\n");
+ fadump_conf->dump_registered = 1;
+ err = -EEXIST;
+ break;
+ default:
+ pr_err("Failed to register. Unknown Error(%d).\n", rc);
+ break;
+ }
+
+ return err;
}
static int rtas_fadump_unregister_fadump(struct fw_dump *fadump_conf)
{
- return -EIO;
+ int rc;
+ unsigned int wait_time;
+
+ /* TODO: Add upper time limit for the delay */
+ do {
+ rc = rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1,
+ NULL, FADUMP_UNREGISTER, &fdm,
+ sizeof(struct rtas_fadump_mem_struct));
+
+ wait_time = rtas_busy_delay_time(rc);
+ if (wait_time)
+ mdelay(wait_time);
+ } while (wait_time);
+
+ if (rc) {
+ pr_err("Failed to un-register - unexpected error(%d).\n", rc);
+ return -EIO;
+ }
+
+ fadump_conf->dump_registered = 0;
+ return 0;
}
static int rtas_fadump_invalidate_fadump(struct fw_dump *fadump_conf)
@@ -62,6 +195,30 @@ static int __init rtas_fadump_process_fadump(struct fw_dump *fadump_conf)
static void rtas_fadump_region_show(struct fw_dump *fadump_conf,
struct seq_file *m)
{
+ const struct rtas_fadump_mem_struct *fdm_ptr = &fdm;
+ const struct rtas_fadump_section *cpu_data_section;
+
+ cpu_data_section = &(fdm_ptr->cpu_state_data);
+ seq_printf(m, "CPU :[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\n",
+ be64_to_cpu(cpu_data_section->destination_address),
+ be64_to_cpu(cpu_data_section->destination_address) +
+ be64_to_cpu(cpu_data_section->source_len) - 1,
+ be64_to_cpu(cpu_data_section->source_len),
+ be64_to_cpu(cpu_data_section->bytes_dumped));
+
+ seq_printf(m, "HPTE:[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\n",
+ be64_to_cpu(fdm_ptr->hpte_region.destination_address),
+ be64_to_cpu(fdm_ptr->hpte_region.destination_address) +
+ be64_to_cpu(fdm_ptr->hpte_region.source_len) - 1,
+ be64_to_cpu(fdm_ptr->hpte_region.source_len),
+ be64_to_cpu(fdm_ptr->hpte_region.bytes_dumped));
+
+ seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
+ be64_to_cpu(fdm_ptr->rmr_region.source_address),
+ be64_to_cpu(fdm_ptr->rmr_region.destination_address));
+ seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
+ be64_to_cpu(fdm_ptr->rmr_region.source_len),
+ be64_to_cpu(fdm_ptr->rmr_region.bytes_dumped));
}
static void rtas_fadump_trigger(struct fadump_crash_info_header *fdh,
^ permalink raw reply related
* [PATCH v4 05/25] pseries/fadump: introduce callbacks for platform specific operations
From: Hari Bathini @ 2019-07-16 11:32 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Introduce callback functions for platform specific operations like
register, unregister, invalidate & such. Also, define place-holders
for the same on pSeries platform.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/kernel/fadump-common.h | 33 ++++++
arch/powerpc/kernel/fadump.c | 47 +--------
arch/powerpc/platforms/pseries/Makefile | 1
arch/powerpc/platforms/pseries/rtas-fadump.c | 134 ++++++++++++++++++++++++++
4 files changed, 171 insertions(+), 44 deletions(-)
create mode 100644 arch/powerpc/platforms/pseries/rtas-fadump.c
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index 09d6161..020d582 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -50,6 +50,12 @@
#define FADUMP_UNREGISTER 2
#define FADUMP_INVALIDATE 3
+/* Firmware-Assited Dump platforms */
+enum fadump_platform_type {
+ FADUMP_PLATFORM_UNKNOWN = 0,
+ FADUMP_PLATFORM_PSERIES,
+};
+
/*
* Copy the ascii values for first 8 characters from a string into u64
* variable at their respective indexes.
@@ -84,6 +90,9 @@ struct fad_crash_memory_ranges {
unsigned long long size;
};
+/* Platform specific callback functions */
+struct fadump_ops;
+
/* Firmware-assisted dump configuration details. */
struct fw_dump {
unsigned long reserve_dump_area_start;
@@ -106,6 +115,21 @@ struct fw_dump {
unsigned long dump_active:1;
unsigned long dump_registered:1;
unsigned long nocma:1;
+
+ enum fadump_platform_type fadump_platform;
+ struct fadump_ops *ops;
+};
+
+struct fadump_ops {
+ ulong (*init_fadump_mem_struct)(struct fw_dump *fadump_config);
+ int (*register_fadump)(struct fw_dump *fadump_config);
+ int (*unregister_fadump)(struct fw_dump *fadump_config);
+ int (*invalidate_fadump)(struct fw_dump *fadump_config);
+ int (*process_fadump)(struct fw_dump *fadump_config);
+ void (*fadump_region_show)(struct fw_dump *fadump_config,
+ struct seq_file *m);
+ void (*fadump_trigger)(struct fadump_crash_info_header *fdh,
+ const char *msg);
};
/* Helper functions */
@@ -116,4 +140,13 @@ void fadump_update_elfcore_header(struct fw_dump *fadump_config, char *bufp);
int is_fadump_boot_mem_contiguous(struct fw_dump *fadump_conf);
int is_fadump_reserved_mem_contiguous(struct fw_dump *fadump_conf);
+#ifdef CONFIG_PPC_PSERIES
+extern int rtas_fadump_dt_scan(struct fw_dump *fadump_config, ulong node);
+#else
+static inline int rtas_fadump_dt_scan(struct fw_dump *fadump_config, ulong node)
+{
+ return 1;
+}
+#endif
+
#endif /* __PPC64_FA_DUMP_INTERNAL_H__ */
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index f571cb3..a901ca1 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -112,24 +112,12 @@ static int __init fadump_cma_init(void) { return 1; }
int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
int depth, void *data)
{
- const __be32 *sections;
- int i, num_sections;
- int size;
- const __be32 *token;
+ int ret;
if (depth != 1 || strcmp(uname, "rtas") != 0)
return 0;
- /*
- * Check if Firmware Assisted dump is supported. if yes, check
- * if dump has been initiated on last reboot.
- */
- token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
- if (!token)
- return 1;
-
- fw_dump.fadump_supported = 1;
- fw_dump.ibm_configure_kernel_dump = be32_to_cpu(*token);
+ ret = rtas_fadump_dt_scan(&fw_dump, node);
/*
* The 'ibm,kernel-dump' rtas node is present only if there is
@@ -139,36 +127,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
if (fdm_active)
fw_dump.dump_active = 1;
- /* Get the sizes required to store dump data for the firmware provided
- * dump sections.
- * For each dump section type supported, a 32bit cell which defines
- * the ID of a supported section followed by two 32 bit cells which
- * gives teh size of the section in bytes.
- */
- sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
- &size);
-
- if (!sections)
- return 1;
-
- num_sections = size / (3 * sizeof(u32));
-
- for (i = 0; i < num_sections; i++, sections += 3) {
- u32 type = (u32)of_read_number(sections, 1);
-
- switch (type) {
- case RTAS_FADUMP_CPU_STATE_DATA:
- fw_dump.cpu_state_data_size =
- of_read_ulong(§ions[1], 2);
- break;
- case RTAS_FADUMP_HPTE_REGION:
- fw_dump.hpte_region_size =
- of_read_ulong(§ions[1], 2);
- break;
- }
- }
-
- return 1;
+ return ret;
}
/*
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index ab3d59a..e248724 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_IBMEBUS) += ibmebus.o
obj-$(CONFIG_PAPR_SCM) += papr_scm.o
obj-$(CONFIG_PPC_SPLPAR) += vphn.o
+obj-$(CONFIG_FA_DUMP) += rtas-fadump.o
ifdef CONFIG_PPC_PSERIES
obj-$(CONFIG_SUSPEND) += suspend.o
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c
new file mode 100644
index 0000000..9e7c9bf
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.c
@@ -0,0 +1,134 @@
+/*
+ * Firmware-Assisted Dump support on POWERVM platform.
+ *
+ * Copyright 2011, IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.ibm.com>
+ *
+ * Copyright 2019, IBM Corp.
+ * Author: Hari Bathini <hbathini@linux.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "rtas fadump: " fmt
+
+#include <linux/string.h>
+#include <linux/memblock.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/crash_dump.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/fadump.h>
+
+#include "../../kernel/fadump-common.h"
+#include "rtas-fadump.h"
+
+static ulong rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
+{
+ return fadump_conf->reserve_dump_area_start;
+}
+
+static int rtas_fadump_register_fadump(struct fw_dump *fadump_conf)
+{
+ return -EIO;
+}
+
+static int rtas_fadump_unregister_fadump(struct fw_dump *fadump_conf)
+{
+ return -EIO;
+}
+
+static int rtas_fadump_invalidate_fadump(struct fw_dump *fadump_conf)
+{
+ return -EIO;
+}
+
+/*
+ * Validate and process the dump data stored by firmware before exporting
+ * it through '/proc/vmcore'.
+ */
+static int __init rtas_fadump_process_fadump(struct fw_dump *fadump_conf)
+{
+ return -EINVAL;
+}
+
+static void rtas_fadump_region_show(struct fw_dump *fadump_conf,
+ struct seq_file *m)
+{
+}
+
+static void rtas_fadump_trigger(struct fadump_crash_info_header *fdh,
+ const char *msg)
+{
+ /* Call ibm,os-term rtas call to trigger firmware assisted dump */
+ rtas_os_term((char *)msg);
+}
+
+static struct fadump_ops rtas_fadump_ops = {
+ .init_fadump_mem_struct = rtas_fadump_init_mem_struct,
+ .register_fadump = rtas_fadump_register_fadump,
+ .unregister_fadump = rtas_fadump_unregister_fadump,
+ .invalidate_fadump = rtas_fadump_invalidate_fadump,
+ .process_fadump = rtas_fadump_process_fadump,
+ .fadump_region_show = rtas_fadump_region_show,
+ .fadump_trigger = rtas_fadump_trigger,
+};
+
+int __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, ulong node)
+{
+ const __be32 *sections;
+ int i, num_sections;
+ int size;
+ const __be32 *token;
+
+ /*
+ * Check if Firmware Assisted dump is supported. if yes, check
+ * if dump has been initiated on last reboot.
+ */
+ token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
+ if (!token)
+ return 1;
+
+ fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token);
+ fadump_conf->ops = &rtas_fadump_ops;
+ fadump_conf->fadump_platform = FADUMP_PLATFORM_PSERIES;
+ fadump_conf->fadump_supported = 1;
+
+ /* Get the sizes required to store dump data for the firmware provided
+ * dump sections.
+ * For each dump section type supported, a 32bit cell which defines
+ * the ID of a supported section followed by two 32 bit cells which
+ * gives the size of the section in bytes.
+ */
+ sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
+ &size);
+
+ if (!sections)
+ return 1;
+
+ num_sections = size / (3 * sizeof(u32));
+
+ for (i = 0; i < num_sections; i++, sections += 3) {
+ u32 type = (u32)of_read_number(sections, 1);
+
+ switch (type) {
+ case RTAS_FADUMP_CPU_STATE_DATA:
+ fadump_conf->cpu_state_data_size =
+ of_read_ulong(§ions[1], 2);
+ break;
+ case RTAS_FADUMP_HPTE_REGION:
+ fadump_conf->hpte_region_size =
+ of_read_ulong(§ions[1], 2);
+ break;
+ }
+ }
+
+ return 1;
+}
^ permalink raw reply related
* [PATCH v4 04/25] pseries/fadump: move rtas specific definitions to platform code
From: Hari Bathini @ 2019-07-16 11:32 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Currently, FADump is only supported on pSeries but that is going to
change soon with FADump support being added on PowerNV platform. So,
move rtas specific definitions to platform code to allow FADump
to have multiple platforms support.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/include/asm/fadump.h | 112 --------------------------
arch/powerpc/kernel/fadump-common.h | 20 ++++-
arch/powerpc/kernel/fadump.c | 90 +++++++++++----------
arch/powerpc/platforms/pseries/rtas-fadump.h | 107 +++++++++++++++++++++++++
4 files changed, 174 insertions(+), 155 deletions(-)
create mode 100644 arch/powerpc/platforms/pseries/rtas-fadump.h
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h
index 75179497..e608d34 100644
--- a/arch/powerpc/include/asm/fadump.h
+++ b/arch/powerpc/include/asm/fadump.h
@@ -11,116 +11,8 @@
#ifdef CONFIG_FA_DUMP
-/* Firmware provided dump sections */
-#define FADUMP_CPU_STATE_DATA 0x0001
-#define FADUMP_HPTE_REGION 0x0002
-#define FADUMP_REAL_MODE_REGION 0x0011
-
-/* Dump request flag */
-#define FADUMP_REQUEST_FLAG 0x00000001
-
-/* Dump status flag */
-#define FADUMP_ERROR_FLAG 0x2000
-
-#define FADUMP_CPU_ID_MASK ((1UL << 32) - 1)
-
-#define CPU_UNKNOWN (~((u32)0))
-
-/* Utility macros */
-#define SKIP_TO_NEXT_CPU(reg_entry) \
-({ \
- while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) \
- reg_entry++; \
- reg_entry++; \
-})
-
extern int crashing_cpu;
-/* Kernel Dump section info */
-struct fadump_section {
- __be32 request_flag;
- __be16 source_data_type;
- __be16 error_flags;
- __be64 source_address;
- __be64 source_len;
- __be64 bytes_dumped;
- __be64 destination_address;
-};
-
-/* ibm,configure-kernel-dump header. */
-struct fadump_section_header {
- __be32 dump_format_version;
- __be16 dump_num_sections;
- __be16 dump_status_flag;
- __be32 offset_first_dump_section;
-
- /* Fields for disk dump option. */
- __be32 dd_block_size;
- __be64 dd_block_offset;
- __be64 dd_num_blocks;
- __be32 dd_offset_disk_path;
-
- /* Maximum time allowed to prevent an automatic dump-reboot. */
- __be32 max_time_auto;
-};
-
-/*
- * Firmware Assisted dump memory structure. This structure is required for
- * registering future kernel dump with power firmware through rtas call.
- *
- * No disk dump option. Hence disk dump path string section is not included.
- */
-struct fadump_mem_struct {
- struct fadump_section_header header;
-
- /* Kernel dump sections */
- struct fadump_section cpu_state_data;
- struct fadump_section hpte_region;
- struct fadump_section rmr_region;
-};
-
-/*
- * Copy the ascii values for first 8 characters from a string into u64
- * variable at their respective indexes.
- * e.g.
- * The string "FADMPINF" will be converted into 0x4641444d50494e46
- */
-static inline u64 str_to_u64(const char *str)
-{
- u64 val = 0;
- int i;
-
- for (i = 0; i < sizeof(val); i++)
- val = (*str) ? (val << 8) | *str++ : val << 8;
- return val;
-}
-#define STR_TO_HEX(x) str_to_u64(x)
-#define REG_ID(x) str_to_u64(x)
-
-#define REGSAVE_AREA_MAGIC STR_TO_HEX("REGSAVE")
-
-/* The firmware-assisted dump format.
- *
- * The register save area is an area in the partition's memory used to preserve
- * the register contents (CPU state data) for the active CPUs during a firmware
- * assisted dump. The dump format contains register save area header followed
- * by register entries. Each list of registers for a CPU starts with
- * "CPUSTRT" and ends with "CPUEND".
- */
-
-/* Register save area header. */
-struct fadump_reg_save_area_header {
- __be64 magic_number;
- __be32 version;
- __be32 num_cpu_offset;
-};
-
-/* Register entry. */
-struct fadump_reg_entry {
- __be64 reg_id;
- __be64 reg_value;
-};
-
extern int is_fadump_memory_area(u64 addr, ulong size);
extern int early_init_dt_scan_fw_dump(unsigned long node,
const char *uname, int depth, void *data);
@@ -136,5 +28,5 @@ static inline int is_fadump_active(void) { return 0; }
static inline int should_fadump_crash(void) { return 0; }
static inline void crash_fadump(struct pt_regs *regs, const char *str) { }
static inline void fadump_cleanup(void) { }
-#endif
-#endif
+#endif /* !CONFIG_FA_DUMP */
+#endif /* __PPC64_FA_DUMP_H__ */
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index 6c1e310..09d6161 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -50,7 +50,25 @@
#define FADUMP_UNREGISTER 2
#define FADUMP_INVALIDATE 3
-#define FADUMP_CRASH_INFO_MAGIC str_to_u64("FADMPINF")
+/*
+ * Copy the ascii values for first 8 characters from a string into u64
+ * variable at their respective indexes.
+ * e.g.
+ * The string "FADMPINF" will be converted into 0x4641444d50494e46
+ */
+static inline u64 fadump_str_to_u64(const char *str)
+{
+ u64 val = 0;
+ int i;
+
+ for (i = 0; i < sizeof(val); i++)
+ val = (*str) ? (val << 8) | *str++ : val << 8;
+ return val;
+}
+
+#define FADUMP_CPU_UNKNOWN (~((u32)0))
+
+#define FADUMP_CRASH_INFO_MAGIC fadump_str_to_u64("FADMPINF")
/* fadump crash info structure */
struct fadump_crash_info_header {
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 48db521..f571cb3 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -33,10 +33,11 @@
#include <asm/setup.h>
#include "fadump-common.h"
+#include "../platforms/pseries/rtas-fadump.h"
static struct fw_dump fw_dump;
-static struct fadump_mem_struct fdm;
-static const struct fadump_mem_struct *fdm_active;
+static struct rtas_fadump_mem_struct fdm;
+static const struct rtas_fadump_mem_struct *fdm_active;
static DEFINE_MUTEX(fadump_mutex);
struct fad_crash_memory_ranges *crash_memory_ranges;
@@ -156,11 +157,11 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
u32 type = (u32)of_read_number(sections, 1);
switch (type) {
- case FADUMP_CPU_STATE_DATA:
+ case RTAS_FADUMP_CPU_STATE_DATA:
fw_dump.cpu_state_data_size =
of_read_ulong(§ions[1], 2);
break;
- case FADUMP_HPTE_REGION:
+ case RTAS_FADUMP_HPTE_REGION:
fw_dump.hpte_region_size =
of_read_ulong(§ions[1], 2);
break;
@@ -219,20 +220,20 @@ static void fadump_show_config(void)
pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size);
}
-static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm,
+static unsigned long init_fadump_mem_struct(struct rtas_fadump_mem_struct *fdm,
unsigned long addr)
{
if (!fdm)
return 0;
- memset(fdm, 0, sizeof(struct fadump_mem_struct));
+ memset(fdm, 0, sizeof(struct rtas_fadump_mem_struct));
addr = addr & PAGE_MASK;
fdm->header.dump_format_version = cpu_to_be32(0x00000001);
fdm->header.dump_num_sections = cpu_to_be16(3);
fdm->header.dump_status_flag = 0;
fdm->header.offset_first_dump_section =
- cpu_to_be32((u32)offsetof(struct fadump_mem_struct, cpu_state_data));
+ cpu_to_be32((u32)offsetof(struct rtas_fadump_mem_struct, cpu_state_data));
/*
* Fields for disk dump option.
@@ -248,24 +249,24 @@ static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm,
/* Kernel dump sections */
/* cpu state data section. */
- fdm->cpu_state_data.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG);
- fdm->cpu_state_data.source_data_type = cpu_to_be16(FADUMP_CPU_STATE_DATA);
+ fdm->cpu_state_data.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
+ fdm->cpu_state_data.source_data_type = cpu_to_be16(RTAS_FADUMP_CPU_STATE_DATA);
fdm->cpu_state_data.source_address = 0;
fdm->cpu_state_data.source_len = cpu_to_be64(fw_dump.cpu_state_data_size);
fdm->cpu_state_data.destination_address = cpu_to_be64(addr);
addr += fw_dump.cpu_state_data_size;
/* hpte region section */
- fdm->hpte_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG);
- fdm->hpte_region.source_data_type = cpu_to_be16(FADUMP_HPTE_REGION);
+ fdm->hpte_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
+ fdm->hpte_region.source_data_type = cpu_to_be16(RTAS_FADUMP_HPTE_REGION);
fdm->hpte_region.source_address = 0;
fdm->hpte_region.source_len = cpu_to_be64(fw_dump.hpte_region_size);
fdm->hpte_region.destination_address = cpu_to_be64(addr);
addr += fw_dump.hpte_region_size;
/* RMA region section */
- fdm->rmr_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG);
- fdm->rmr_region.source_data_type = cpu_to_be16(FADUMP_REAL_MODE_REGION);
+ fdm->rmr_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
+ fdm->rmr_region.source_data_type = cpu_to_be16(RTAS_FADUMP_REAL_MODE_REGION);
fdm->rmr_region.source_address = cpu_to_be64(RMA_START);
fdm->rmr_region.source_len = cpu_to_be64(fw_dump.boot_memory_size);
fdm->rmr_region.destination_address = cpu_to_be64(addr);
@@ -520,7 +521,7 @@ static int __init early_fadump_reserve_mem(char *p)
}
early_param("fadump_reserve_mem", early_fadump_reserve_mem);
-static int register_fw_dump(struct fadump_mem_struct *fdm)
+static int register_fw_dump(struct rtas_fadump_mem_struct *fdm)
{
int rc, err;
unsigned int wait_time;
@@ -531,7 +532,7 @@ static int register_fw_dump(struct fadump_mem_struct *fdm)
do {
rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
FADUMP_REGISTER, fdm,
- sizeof(struct fadump_mem_struct));
+ sizeof(struct rtas_fadump_mem_struct));
wait_time = rtas_busy_delay_time(rc);
if (wait_time)
@@ -627,7 +628,7 @@ static inline int fadump_gpr_index(u64 id)
int i = -1;
char str[3];
- if ((id & GPR_MASK) == REG_ID("GPR")) {
+ if ((id & GPR_MASK) == fadump_str_to_u64("GPR")) {
/* get the digits at the end */
id &= ~GPR_MASK;
id >>= 24;
@@ -649,30 +650,30 @@ static inline void fadump_set_regval(struct pt_regs *regs, u64 reg_id,
i = fadump_gpr_index(reg_id);
if (i >= 0)
regs->gpr[i] = (unsigned long)reg_val;
- else if (reg_id == REG_ID("NIA"))
+ else if (reg_id == fadump_str_to_u64("NIA"))
regs->nip = (unsigned long)reg_val;
- else if (reg_id == REG_ID("MSR"))
+ else if (reg_id == fadump_str_to_u64("MSR"))
regs->msr = (unsigned long)reg_val;
- else if (reg_id == REG_ID("CTR"))
+ else if (reg_id == fadump_str_to_u64("CTR"))
regs->ctr = (unsigned long)reg_val;
- else if (reg_id == REG_ID("LR"))
+ else if (reg_id == fadump_str_to_u64("LR"))
regs->link = (unsigned long)reg_val;
- else if (reg_id == REG_ID("XER"))
+ else if (reg_id == fadump_str_to_u64("XER"))
regs->xer = (unsigned long)reg_val;
- else if (reg_id == REG_ID("CR"))
+ else if (reg_id == fadump_str_to_u64("CR"))
regs->ccr = (unsigned long)reg_val;
- else if (reg_id == REG_ID("DAR"))
+ else if (reg_id == fadump_str_to_u64("DAR"))
regs->dar = (unsigned long)reg_val;
- else if (reg_id == REG_ID("DSISR"))
+ else if (reg_id == fadump_str_to_u64("DSISR"))
regs->dsisr = (unsigned long)reg_val;
}
-static struct fadump_reg_entry*
-fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs)
+static struct rtas_fadump_reg_entry*
+fadump_read_registers(struct rtas_fadump_reg_entry *reg_entry, struct pt_regs *regs)
{
memset(regs, 0, sizeof(struct pt_regs));
- while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) {
+ while (be64_to_cpu(reg_entry->reg_id) != fadump_str_to_u64("CPUEND")) {
fadump_set_regval(regs, be64_to_cpu(reg_entry->reg_id),
be64_to_cpu(reg_entry->reg_value));
reg_entry++;
@@ -695,10 +696,10 @@ fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs)
* state from fadump crash info structure populated by first kernel at the
* time of crash.
*/
-static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
+static int __init fadump_build_cpu_notes(const struct rtas_fadump_mem_struct *fdm)
{
- struct fadump_reg_save_area_header *reg_header;
- struct fadump_reg_entry *reg_entry;
+ struct rtas_fadump_reg_save_area_header *reg_header;
+ struct rtas_fadump_reg_entry *reg_entry;
struct fadump_crash_info_header *fdh = NULL;
void *vaddr;
unsigned long addr;
@@ -713,7 +714,8 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
vaddr = __va(addr);
reg_header = vaddr;
- if (be64_to_cpu(reg_header->magic_number) != REGSAVE_AREA_MAGIC) {
+ if (be64_to_cpu(reg_header->magic_number) !=
+ fadump_str_to_u64("REGSAVE")) {
printk(KERN_ERR "Unable to read register save area.\n");
return -ENOENT;
}
@@ -725,7 +727,7 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
num_cpus = be32_to_cpu(*((__be32 *)(vaddr)));
pr_debug("NumCpus : %u\n", num_cpus);
vaddr += sizeof(u32);
- reg_entry = (struct fadump_reg_entry *)vaddr;
+ reg_entry = (struct rtas_fadump_reg_entry *)vaddr;
/* Allocate buffer to hold cpu crash notes. */
fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
@@ -745,22 +747,22 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
fdh = __va(fw_dump.fadumphdr_addr);
for (i = 0; i < num_cpus; i++) {
- if (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUSTRT")) {
+ if (be64_to_cpu(reg_entry->reg_id) != fadump_str_to_u64("CPUSTRT")) {
printk(KERN_ERR "Unable to read CPU state data\n");
rc = -ENOENT;
goto error_out;
}
/* Lower 4 bytes of reg_value contains logical cpu id */
- cpu = be64_to_cpu(reg_entry->reg_value) & FADUMP_CPU_ID_MASK;
+ cpu = be64_to_cpu(reg_entry->reg_value) & RTAS_FADUMP_CPU_ID_MASK;
if (fdh && !cpumask_test_cpu(cpu, &fdh->online_mask)) {
- SKIP_TO_NEXT_CPU(reg_entry);
+ RTAS_FADUMP_SKIP_TO_NEXT_CPU(reg_entry);
continue;
}
pr_debug("Reading register data for cpu %d...\n", cpu);
if (fdh && fdh->crashing_cpu == cpu) {
regs = fdh->regs;
note_buf = fadump_regs_to_elf_notes(note_buf, ®s);
- SKIP_TO_NEXT_CPU(reg_entry);
+ RTAS_FADUMP_SKIP_TO_NEXT_CPU(reg_entry);
} else {
reg_entry++;
reg_entry = fadump_read_registers(reg_entry, ®s);
@@ -789,7 +791,7 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
* Validate and process the dump data stored by firmware before exporting
* it through '/proc/vmcore'.
*/
-static int __init process_fadump(const struct fadump_mem_struct *fdm_active)
+static int __init process_fadump(const struct rtas_fadump_mem_struct *fdm_active)
{
struct fadump_crash_info_header *fdh;
int rc = 0;
@@ -798,7 +800,7 @@ static int __init process_fadump(const struct fadump_mem_struct *fdm_active)
return -EINVAL;
/* Check if the dump data is valid. */
- if ((be16_to_cpu(fdm_active->header.dump_status_flag) == FADUMP_ERROR_FLAG) ||
+ if ((be16_to_cpu(fdm_active->header.dump_status_flag) == RTAS_FADUMP_ERROR_FLAG) ||
(fdm_active->cpu_state_data.error_flags != 0) ||
(fdm_active->rmr_region.error_flags != 0)) {
printk(KERN_ERR "Dump taken by platform is not valid\n");
@@ -1129,7 +1131,7 @@ static unsigned long init_fadump_header(unsigned long addr)
fdh->magic_number = FADUMP_CRASH_INFO_MAGIC;
fdh->elfcorehdr_addr = addr;
/* We will set the crashing cpu id in crash_fadump() during crash. */
- fdh->crashing_cpu = CPU_UNKNOWN;
+ fdh->crashing_cpu = FADUMP_CPU_UNKNOWN;
return addr;
}
@@ -1163,7 +1165,7 @@ static int register_fadump(void)
return register_fw_dump(&fdm);
}
-static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
+static int fadump_unregister_dump(struct rtas_fadump_mem_struct *fdm)
{
int rc = 0;
unsigned int wait_time;
@@ -1174,7 +1176,7 @@ static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
do {
rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
FADUMP_UNREGISTER, fdm,
- sizeof(struct fadump_mem_struct));
+ sizeof(struct rtas_fadump_mem_struct));
wait_time = rtas_busy_delay_time(rc);
if (wait_time)
@@ -1190,7 +1192,7 @@ static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
return 0;
}
-static int fadump_invalidate_dump(const struct fadump_mem_struct *fdm)
+static int fadump_invalidate_dump(const struct rtas_fadump_mem_struct *fdm)
{
int rc = 0;
unsigned int wait_time;
@@ -1201,7 +1203,7 @@ static int fadump_invalidate_dump(const struct fadump_mem_struct *fdm)
do {
rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
FADUMP_INVALIDATE, fdm,
- sizeof(struct fadump_mem_struct));
+ sizeof(struct rtas_fadump_mem_struct));
wait_time = rtas_busy_delay_time(rc);
if (wait_time)
@@ -1422,7 +1424,7 @@ static ssize_t fadump_register_store(struct kobject *kobj,
static int fadump_region_show(struct seq_file *m, void *private)
{
- const struct fadump_mem_struct *fdm_ptr;
+ const struct rtas_fadump_mem_struct *fdm_ptr;
if (!fw_dump.fadump_enabled)
return 0;
diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h
new file mode 100644
index 0000000..0cc6dfe3
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/rtas-fadump.h
@@ -0,0 +1,107 @@
+/*
+ * Firmware-Assisted Dump support on POWERVM platform.
+ *
+ * Copyright 2011, IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.ibm.com>
+ *
+ * Copyright 2019, IBM Corp.
+ * Author: Hari Bathini <hbathini@linux.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __PPC64_RTAS_FA_DUMP_H__
+#define __PPC64_RTAS_FA_DUMP_H__
+
+/* Firmware provided dump sections */
+#define RTAS_FADUMP_CPU_STATE_DATA 0x0001
+#define RTAS_FADUMP_HPTE_REGION 0x0002
+#define RTAS_FADUMP_REAL_MODE_REGION 0x0011
+
+/* Dump request flag */
+#define RTAS_FADUMP_REQUEST_FLAG 0x00000001
+
+/* Dump status flag */
+#define RTAS_FADUMP_ERROR_FLAG 0x2000
+
+/* Kernel Dump section info */
+struct rtas_fadump_section {
+ __be32 request_flag;
+ __be16 source_data_type;
+ __be16 error_flags;
+ __be64 source_address;
+ __be64 source_len;
+ __be64 bytes_dumped;
+ __be64 destination_address;
+};
+
+/* ibm,configure-kernel-dump header. */
+struct rtas_fadump_section_header {
+ __be32 dump_format_version;
+ __be16 dump_num_sections;
+ __be16 dump_status_flag;
+ __be32 offset_first_dump_section;
+
+ /* Fields for disk dump option. */
+ __be32 dd_block_size;
+ __be64 dd_block_offset;
+ __be64 dd_num_blocks;
+ __be32 dd_offset_disk_path;
+
+ /* Maximum time allowed to prevent an automatic dump-reboot. */
+ __be32 max_time_auto;
+};
+
+/*
+ * Firmware Assisted dump memory structure. This structure is required for
+ * registering future kernel dump with power firmware through rtas call.
+ *
+ * No disk dump option. Hence disk dump path string section is not included.
+ */
+struct rtas_fadump_mem_struct {
+ struct rtas_fadump_section_header header;
+
+ /* Kernel dump sections */
+ struct rtas_fadump_section cpu_state_data;
+ struct rtas_fadump_section hpte_region;
+ struct rtas_fadump_section rmr_region;
+};
+
+/*
+ * The firmware-assisted dump format.
+ *
+ * The register save area is an area in the partition's memory used to preserve
+ * the register contents (CPU state data) for the active CPUs during a firmware
+ * assisted dump. The dump format contains register save area header followed
+ * by register entries. Each list of registers for a CPU starts with "CPUSTRT"
+ * and ends with "CPUEND".
+ */
+
+/* Register save area header. */
+struct rtas_fadump_reg_save_area_header {
+ __be64 magic_number;
+ __be32 version;
+ __be32 num_cpu_offset;
+};
+
+/* Register entry. */
+struct rtas_fadump_reg_entry {
+ __be64 reg_id;
+ __be64 reg_value;
+};
+
+/* Utility macros */
+#define RTAS_FADUMP_SKIP_TO_NEXT_CPU(reg_entry) \
+({ \
+ while (be64_to_cpu(reg_entry->reg_id) != \
+ fadump_str_to_u64("CPUEND")) \
+ reg_entry++; \
+ reg_entry++; \
+})
+
+#define RTAS_FADUMP_CPU_ID_MASK ((1UL << 32) - 1)
+
+#endif /* __PPC64_RTAS_FA_DUMP_H__ */
^ permalink raw reply related
* [PATCH v4 03/25] powerpc/fadump: Improve fadump documentation
From: Hari Bathini @ 2019-07-16 11:32 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
The figures depicting FADump's (Firmware-Assisted Dump) memory layout
are missing some finer details like different memory regions and what
they represent. Improve the documentation by updating those details.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Documentation/powerpc/firmware-assisted-dump.txt | 65 ++++++++++++----------
1 file changed, 35 insertions(+), 30 deletions(-)
diff --git a/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt
index 0c41d6d..e9b4e3c 100644
--- a/Documentation/powerpc/firmware-assisted-dump.txt
+++ b/Documentation/powerpc/firmware-assisted-dump.txt
@@ -74,8 +74,9 @@ as follows:
there is crash data available from a previous boot. During
the early boot OS will reserve rest of the memory above
boot memory size effectively booting with restricted memory
- size. This will make sure that the second kernel will not
- touch any of the dump memory area.
+ size. This will make sure that this kernel (also, referred
+ to as second kernel or capture kernel) will not touch any
+ of the dump memory area.
-- User-space tools will read /proc/vmcore to obtain the contents
of memory, which holds the previous crashed kernel dump in ELF
@@ -125,48 +126,52 @@ space memory except the user pages that were present in CMA region.
o Memory Reservation during first kernel
- Low memory Top of memory
- 0 boot memory size |
- | | |<--Reserved dump area -->| |
- V V | Permanent Reservation | V
- +-----------+----------/ /---+---+----+-----------+----+------+
- | | |CPU|HPTE| DUMP |ELF | |
- +-----------+----------/ /---+---+----+-----------+----+------+
- | ^
- | |
- \ /
- -------------------------------------------
- Boot memory content gets transferred to
- reserved area by firmware at the time of
- crash
+ Low memory Top of memory
+ 0 boot memory size |<--Reserved dump area --->| |
+ | | | Permanent Reservation | |
+ V V | (Preserve area) | V
+ +-----------+----------/ /---+---+----+--------+---+----+------+
+ | | |CPU|HPTE| DUMP |HDR|ELF | |
+ +-----------+----------/ /---+---+----+--------+---+----+------+
+ | ^ ^
+ | | |
+ \ / |
+ ----------------------------------- FADump Header
+ Boot memory content gets transferred (meta area)
+ to reserved area by firmware at the
+ time of crash
+
Fig. 1
+
o Memory Reservation during second kernel after crash
- Low memory Top of memory
- 0 boot memory size |
- | |<------------- Reserved dump area ----------- -->|
- V V V
- +-----------+----------/ /---+---+----+-----------+----+------+
- | | |CPU|HPTE| DUMP |ELF | |
- +-----------+----------/ /---+---+----+-----------+----+------+
+ Low memory Top of memory
+ 0 boot memory size |
+ | |<------------- Reserved dump area --------------->|
+ V V |<---- Preserve area ----->| V
+ +-----------+----------/ /---+---+----+--------+---+----+------+
+ | | |CPU|HPTE| DUMP |HDR|ELF | |
+ +-----------+----------/ /---+---+----+--------+---+----+------+
| |
V V
Used by second /proc/vmcore
kernel to boot
Fig. 2
-Currently the dump will be copied from /proc/vmcore to a
-a new file upon user intervention. The dump data available through
-/proc/vmcore will be in ELF format. Hence the existing kdump
-infrastructure (kdump scripts) to save the dump works fine with
-minor modifications.
+Currently the dump will be copied from /proc/vmcore to a new file upon
+user intervention. The dump data available through /proc/vmcore will be
+in ELF format. Hence the existing kdump infrastructure (kdump scripts)
+to save the dump works fine with minor modifications. KDump scripts on
+major Distro releases have already been modified to work seemlessly (no
+user intervention in saving the dump) when FADump is used, instead of
+KDump, as dump mechanism.
The tools to examine the dump will be same as the ones
used for kdump.
How to enable firmware-assisted dump (fadump):
--------------------------------------
+---------------------------------------------
1. Set config option CONFIG_FA_DUMP=y and build kernel.
2. Boot into linux kernel with 'fadump=on' kernel cmdline option.
@@ -189,7 +194,7 @@ NOTE: 1. 'fadump_reserve_mem=' parameter has been deprecated. Instead
old behaviour.
Sysfs/debugfs files:
-------------
+-------------------
Firmware-assisted dump feature uses sysfs file system to hold
the control files and debugfs file to display memory reserved region.
^ permalink raw reply related
* [PATCH v4 02/25] powerpc/fadump: move internal code to a new file
From: Hari Bathini @ 2019-07-16 11:32 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Make way for refactoring platform specific FADump code by moving code
that could be referenced from multiple places to fadump-common.c file.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/kernel/Makefile | 2
arch/powerpc/kernel/fadump-common.c | 144 +++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/fadump-common.h | 8 ++
arch/powerpc/kernel/fadump.c | 146 ++---------------------------------
4 files changed, 162 insertions(+), 138 deletions(-)
create mode 100644 arch/powerpc/kernel/fadump-common.c
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 56dfa7a..439d548 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -78,7 +78,7 @@ obj-$(CONFIG_EEH) += eeh.o eeh_pe.o eeh_dev.o eeh_cache.o \
eeh_driver.o eeh_event.o eeh_sysfs.o
obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
-obj-$(CONFIG_FA_DUMP) += fadump.o
+obj-$(CONFIG_FA_DUMP) += fadump.o fadump-common.o
ifdef CONFIG_PPC32
obj-$(CONFIG_E500) += idle_e500.o
endif
diff --git a/arch/powerpc/kernel/fadump-common.c b/arch/powerpc/kernel/fadump-common.c
new file mode 100644
index 0000000..76c1233
--- /dev/null
+++ b/arch/powerpc/kernel/fadump-common.c
@@ -0,0 +1,144 @@
+/*
+ * Firmware-Assisted Dump internal code.
+ *
+ * Copyright 2011, IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.ibm.com>
+ *
+ * Copyright 2019, IBM Corp.
+ * Author: Hari Bathini <hbathini@linux.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "fadump: " fmt
+
+#include <linux/memblock.h>
+#include <linux/elf.h>
+#include <linux/mm.h>
+#include <linux/crash_core.h>
+
+#include "fadump-common.h"
+
+void *fadump_cpu_notes_buf_alloc(unsigned long size)
+{
+ void *vaddr;
+ struct page *page;
+ unsigned long order, count, i;
+
+ order = get_order(size);
+ vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
+ if (!vaddr)
+ return NULL;
+
+ count = 1 << order;
+ page = virt_to_page(vaddr);
+ for (i = 0; i < count; i++)
+ SetPageReserved(page + i);
+ return vaddr;
+}
+
+void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size)
+{
+ struct page *page;
+ unsigned long order, count, i;
+
+ order = get_order(size);
+ count = 1 << order;
+ page = virt_to_page(vaddr);
+ for (i = 0; i < count; i++)
+ ClearPageReserved(page + i);
+ __free_pages(page, order);
+}
+
+u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
+{
+ struct elf_prstatus prstatus;
+
+ memset(&prstatus, 0, sizeof(prstatus));
+ /*
+ * FIXME: How do i get PID? Do I really need it?
+ * prstatus.pr_pid = ????
+ */
+ elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
+ buf = append_elf_note(buf, CRASH_CORE_NOTE_NAME, NT_PRSTATUS,
+ &prstatus, sizeof(prstatus));
+ return buf;
+}
+
+void fadump_update_elfcore_header(struct fw_dump *fadump_conf, char *bufp)
+{
+ struct elfhdr *elf;
+ struct elf_phdr *phdr;
+
+ elf = (struct elfhdr *)bufp;
+ bufp += sizeof(struct elfhdr);
+
+ /* First note is a place holder for cpu notes info. */
+ phdr = (struct elf_phdr *)bufp;
+
+ if (phdr->p_type == PT_NOTE) {
+ phdr->p_paddr = fadump_conf->cpu_notes_buf;
+ phdr->p_offset = phdr->p_paddr;
+ phdr->p_memsz = fadump_conf->cpu_notes_buf_size;
+ phdr->p_filesz = phdr->p_memsz;
+ }
+}
+
+/*
+ * Returns 1, if there are no holes in memory area between d_start to d_end,
+ * 0 otherwise.
+ */
+static int is_fadump_memory_area_contiguous(unsigned long d_start,
+ unsigned long d_end)
+{
+ struct memblock_region *reg;
+ unsigned long start, end;
+ int ret = 0;
+
+ for_each_memblock(memory, reg) {
+ start = max_t(unsigned long, d_start, reg->base);
+ end = min_t(unsigned long, d_end, (reg->base + reg->size));
+ if (d_start < end) {
+ /* Memory hole from d_start to start */
+ if (start > d_start)
+ break;
+
+ if (end == d_end) {
+ ret = 1;
+ break;
+ }
+
+ d_start = end + 1;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Returns 1, if there are no holes in boot memory area,
+ * 0 otherwise.
+ */
+int is_fadump_boot_mem_contiguous(struct fw_dump *fadump_conf)
+{
+ unsigned long d_start = RMA_START;
+ unsigned long d_end = RMA_START + fadump_conf->boot_memory_size;
+
+ return is_fadump_memory_area_contiguous(d_start, d_end);
+}
+
+/*
+ * Returns 1, if there are no holes in reserved memory area,
+ * 0 otherwise.
+ */
+int is_fadump_reserved_mem_contiguous(struct fw_dump *fadump_conf)
+{
+ unsigned long d_start = fadump_conf->reserve_dump_area_start;
+ unsigned long d_end = d_start + fadump_conf->reserve_dump_area_size;
+
+ return is_fadump_memory_area_contiguous(d_start, d_end);
+}
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
index ba65e69..6c1e310 100644
--- a/arch/powerpc/kernel/fadump-common.h
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -90,4 +90,12 @@ struct fw_dump {
unsigned long nocma:1;
};
+/* Helper functions */
+void *fadump_cpu_notes_buf_alloc(unsigned long size);
+void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size);
+u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs);
+void fadump_update_elfcore_header(struct fw_dump *fadump_config, char *bufp);
+int is_fadump_boot_mem_contiguous(struct fw_dump *fadump_conf);
+int is_fadump_reserved_mem_contiguous(struct fw_dump *fadump_conf);
+
#endif /* __PPC64_FA_DUMP_INTERNAL_H__ */
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 4c3b874..48db521 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -37,9 +37,6 @@
static struct fw_dump fw_dump;
static struct fadump_mem_struct fdm;
static const struct fadump_mem_struct *fdm_active;
-#ifdef CONFIG_CMA
-static struct cma *fadump_cma;
-#endif
static DEFINE_MUTEX(fadump_mutex);
struct fad_crash_memory_ranges *crash_memory_ranges;
@@ -48,6 +45,8 @@ int crash_mem_ranges;
int max_crash_mem_ranges;
#ifdef CONFIG_CMA
+static struct cma *fadump_cma;
+
/*
* fadump_cma_init() - Initialize CMA area from a fadump reserved memory
*
@@ -109,8 +108,8 @@ static int __init fadump_cma_init(void) { return 1; }
#endif /* CONFIG_CMA */
/* Scan the Firmware Assisted dump configuration details. */
-int __init early_init_dt_scan_fw_dump(unsigned long node,
- const char *uname, int depth, void *data)
+int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
+ int depth, void *data)
{
const __be32 *sections;
int i, num_sections;
@@ -201,67 +200,6 @@ int is_fadump_active(void)
return fw_dump.dump_active;
}
-/*
- * Returns 1, if there are no holes in boot memory area,
- * 0 otherwise.
- */
-static int is_boot_memory_area_contiguous(void)
-{
- struct memblock_region *reg;
- unsigned long tstart, tend;
- unsigned long start_pfn = PHYS_PFN(RMA_START);
- unsigned long end_pfn = PHYS_PFN(RMA_START + fw_dump.boot_memory_size);
- unsigned int ret = 0;
-
- for_each_memblock(memory, reg) {
- tstart = max(start_pfn, memblock_region_memory_base_pfn(reg));
- tend = min(end_pfn, memblock_region_memory_end_pfn(reg));
- if (tstart < tend) {
- /* Memory hole from start_pfn to tstart */
- if (tstart > start_pfn)
- break;
-
- if (tend == end_pfn) {
- ret = 1;
- break;
- }
-
- start_pfn = tend + 1;
- }
- }
-
- return ret;
-}
-
-/*
- * Returns true, if there are no holes in reserved memory area,
- * false otherwise.
- */
-static bool is_reserved_memory_area_contiguous(void)
-{
- struct memblock_region *reg;
- unsigned long start, end;
- unsigned long d_start = fw_dump.reserve_dump_area_start;
- unsigned long d_end = d_start + fw_dump.reserve_dump_area_size;
-
- for_each_memblock(memory, reg) {
- start = max(d_start, (unsigned long)reg->base);
- end = min(d_end, (unsigned long)(reg->base + reg->size));
- if (d_start < end) {
- /* Memory hole from d_start to start */
- if (start > d_start)
- break;
-
- if (end == d_end)
- return true;
-
- d_start = end + 1;
- }
- }
-
- return false;
-}
-
/* Print firmware assisted dump configurations for debugging purpose. */
static void fadump_show_config(void)
{
@@ -611,9 +549,9 @@ static int register_fw_dump(struct fadump_mem_struct *fdm)
" dump. Hardware Error(%d).\n", rc);
break;
case -3:
- if (!is_boot_memory_area_contiguous())
+ if (!is_fadump_boot_mem_contiguous(&fw_dump))
pr_err("Can't have holes in boot memory area while registering fadump\n");
- else if (!is_reserved_memory_area_contiguous())
+ else if (!is_fadump_reserved_mem_contiguous(&fw_dump))
pr_err("Can't have holes in reserved memory area while"
" registering fadump\n");
@@ -743,72 +681,6 @@ fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs)
return reg_entry;
}
-static u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
-{
- struct elf_prstatus prstatus;
-
- memset(&prstatus, 0, sizeof(prstatus));
- /*
- * FIXME: How do i get PID? Do I really need it?
- * prstatus.pr_pid = ????
- */
- elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
- buf = append_elf_note(buf, CRASH_CORE_NOTE_NAME, NT_PRSTATUS,
- &prstatus, sizeof(prstatus));
- return buf;
-}
-
-static void fadump_update_elfcore_header(char *bufp)
-{
- struct elfhdr *elf;
- struct elf_phdr *phdr;
-
- elf = (struct elfhdr *)bufp;
- bufp += sizeof(struct elfhdr);
-
- /* First note is a place holder for cpu notes info. */
- phdr = (struct elf_phdr *)bufp;
-
- if (phdr->p_type == PT_NOTE) {
- phdr->p_paddr = fw_dump.cpu_notes_buf;
- phdr->p_offset = phdr->p_paddr;
- phdr->p_filesz = fw_dump.cpu_notes_buf_size;
- phdr->p_memsz = fw_dump.cpu_notes_buf_size;
- }
- return;
-}
-
-static void *fadump_cpu_notes_buf_alloc(unsigned long size)
-{
- void *vaddr;
- struct page *page;
- unsigned long order, count, i;
-
- order = get_order(size);
- vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
- if (!vaddr)
- return NULL;
-
- count = 1 << order;
- page = virt_to_page(vaddr);
- for (i = 0; i < count; i++)
- SetPageReserved(page + i);
- return vaddr;
-}
-
-static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size)
-{
- struct page *page;
- unsigned long order, count, i;
-
- order = get_order(size);
- count = 1 << order;
- page = virt_to_page(vaddr);
- for (i = 0; i < count; i++)
- ClearPageReserved(page + i);
- __free_pages(page, order);
-}
-
/*
* Read CPU state dump data and convert it into ELF notes.
* The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be
@@ -898,9 +770,9 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
final_note(note_buf);
if (fdh) {
- pr_debug("Updating elfcore header (%llx) with cpu notes\n",
- fdh->elfcorehdr_addr);
- fadump_update_elfcore_header((char *)__va(fdh->elfcorehdr_addr));
+ addr = fdh->elfcorehdr_addr;
+ pr_debug("Updating elfcore header(%lx) with cpu notes\n", addr);
+ fadump_update_elfcore_header(&fw_dump, (char *)__va(addr));
}
return 0;
^ permalink raw reply related
* [PATCH v4 01/25] powerpc/fadump: move internal macros/definitions to a new header
From: Hari Bathini @ 2019-07-16 11:32 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
In-Reply-To: <156327668777.27462.5297279227799429100.stgit@hbathini.in.ibm.com>
Though asm/fadump.h is meant to be used by other components dealing
with FADump, it also has macros/definitions internal to FADump code.
Move them to a new header file used within FADump code. This also
makes way for refactoring platform specific FADump code.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/include/asm/fadump.h | 71 ---------------------------
arch/powerpc/kernel/fadump-common.h | 93 +++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/fadump.c | 2 +
3 files changed, 95 insertions(+), 71 deletions(-)
create mode 100644 arch/powerpc/kernel/fadump-common.h
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h
index 17d9b6a..75179497 100644
--- a/arch/powerpc/include/asm/fadump.h
+++ b/arch/powerpc/include/asm/fadump.h
@@ -11,34 +11,6 @@
#ifdef CONFIG_FA_DUMP
-/*
- * The RMA region will be saved for later dumping when kernel crashes.
- * RMA is Real Mode Area, the first block of logical memory address owned
- * by logical partition, containing the storage that may be accessed with
- * translate off.
- */
-#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 aditional 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
-
-#define memblock_num_regions(memblock_type) (memblock.memblock_type.cnt)
-
-/* Alignement per CMA requirement. */
-#define FADUMP_CMA_ALIGNMENT (PAGE_SIZE << \
- max_t(unsigned long, MAX_ORDER - 1, pageblock_order))
-
/* Firmware provided dump sections */
#define FADUMP_CPU_STATE_DATA 0x0001
#define FADUMP_HPTE_REGION 0x0002
@@ -47,11 +19,6 @@
/* Dump request flag */
#define FADUMP_REQUEST_FLAG 0x00000001
-/* FAD commands */
-#define FADUMP_REGISTER 1
-#define FADUMP_UNREGISTER 2
-#define FADUMP_INVALIDATE 3
-
/* Dump status flag */
#define FADUMP_ERROR_FLAG 0x2000
@@ -112,29 +79,6 @@ struct fadump_mem_struct {
struct fadump_section rmr_region;
};
-/* Firmware-assisted dump configuration details. */
-struct fw_dump {
- unsigned long cpu_state_data_size;
- unsigned long hpte_region_size;
- unsigned long boot_memory_size;
- unsigned long reserve_dump_area_start;
- unsigned long reserve_dump_area_size;
- /* cmd line option during boot */
- unsigned long reserve_bootvar;
-
- unsigned long fadumphdr_addr;
- unsigned long cpu_notes_buf;
- unsigned long cpu_notes_buf_size;
-
- int ibm_configure_kernel_dump;
-
- unsigned long fadump_enabled:1;
- unsigned long fadump_supported:1;
- unsigned long dump_active:1;
- unsigned long dump_registered:1;
- unsigned long nocma:1;
-};
-
/*
* Copy the ascii values for first 8 characters from a string into u64
* variable at their respective indexes.
@@ -153,7 +97,6 @@ static inline u64 str_to_u64(const char *str)
#define STR_TO_HEX(x) str_to_u64(x)
#define REG_ID(x) str_to_u64(x)
-#define FADUMP_CRASH_INFO_MAGIC STR_TO_HEX("FADMPINF")
#define REGSAVE_AREA_MAGIC STR_TO_HEX("REGSAVE")
/* The firmware-assisted dump format.
@@ -178,20 +121,6 @@ struct fadump_reg_entry {
__be64 reg_value;
};
-/* fadump crash info structure */
-struct fadump_crash_info_header {
- u64 magic_number;
- u64 elfcorehdr_addr;
- u32 crashing_cpu;
- struct pt_regs regs;
- struct cpumask online_mask;
-};
-
-struct fad_crash_memory_ranges {
- unsigned long long base;
- unsigned long long size;
-};
-
extern int is_fadump_memory_area(u64 addr, ulong size);
extern int early_init_dt_scan_fw_dump(unsigned long node,
const char *uname, int depth, void *data);
diff --git a/arch/powerpc/kernel/fadump-common.h b/arch/powerpc/kernel/fadump-common.h
new file mode 100644
index 0000000..ba65e69
--- /dev/null
+++ b/arch/powerpc/kernel/fadump-common.h
@@ -0,0 +1,93 @@
+/*
+ * Firmware-Assisted Dump internal code.
+ *
+ * Copyright 2011, IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.ibm.com>
+ *
+ * Copyright 2019, IBM Corp.
+ * Author: Hari Bathini <hbathini@linux.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __PPC64_FA_DUMP_INTERNAL_H__
+#define __PPC64_FA_DUMP_INTERNAL_H__
+
+/*
+ * The RMA region will be saved for later dumping when kernel crashes.
+ * RMA is Real Mode Area, the first block of logical memory address owned
+ * by logical partition, containing the storage that may be accessed with
+ * translate off.
+ */
+#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
+
+#define memblock_num_regions(memblock_type) (memblock.memblock_type.cnt)
+
+/* Alignment per CMA requirement. */
+#define FADUMP_CMA_ALIGNMENT (PAGE_SIZE << \
+ max_t(unsigned long, MAX_ORDER - 1, \
+ pageblock_order))
+
+/* FAD commands */
+#define FADUMP_REGISTER 1
+#define FADUMP_UNREGISTER 2
+#define FADUMP_INVALIDATE 3
+
+#define FADUMP_CRASH_INFO_MAGIC str_to_u64("FADMPINF")
+
+/* fadump crash info structure */
+struct fadump_crash_info_header {
+ u64 magic_number;
+ u64 elfcorehdr_addr;
+ u32 crashing_cpu;
+ struct pt_regs regs;
+ struct cpumask online_mask;
+};
+
+struct fad_crash_memory_ranges {
+ unsigned long long base;
+ unsigned long long size;
+};
+
+/* Firmware-assisted dump configuration details. */
+struct fw_dump {
+ unsigned long reserve_dump_area_start;
+ unsigned long reserve_dump_area_size;
+ /* cmd line option during boot */
+ unsigned long reserve_bootvar;
+
+ unsigned long cpu_state_data_size;
+ unsigned long hpte_region_size;
+ unsigned long boot_memory_size;
+
+ unsigned long fadumphdr_addr;
+ unsigned long cpu_notes_buf;
+ unsigned long cpu_notes_buf_size;
+
+ int ibm_configure_kernel_dump;
+
+ unsigned long fadump_enabled:1;
+ unsigned long fadump_supported:1;
+ unsigned long dump_active:1;
+ unsigned long dump_registered:1;
+ unsigned long nocma:1;
+};
+
+#endif /* __PPC64_FA_DUMP_INTERNAL_H__ */
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index a784695..4c3b874 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -32,6 +32,8 @@
#include <asm/fadump.h>
#include <asm/setup.h>
+#include "fadump-common.h"
+
static struct fw_dump fw_dump;
static struct fadump_mem_struct fdm;
static const struct fadump_mem_struct *fdm_active;
^ permalink raw reply related
* [PATCH v4 00/25] Add FADump support on PowerNV platform
From: Hari Bathini @ 2019-07-16 11:31 UTC (permalink / raw)
To: linuxppc-dev
Cc: Ananth N Mavinakayanahalli, Mahesh J Salgaonkar, Vasant Hegde,
Oliver, Nicholas Piggin, Stewart Smith, Daniel Axtens
Firmware-Assisted Dump (FADump) is currently supported only on pSeries
platform. This patch series adds support for PowerNV platform too.
The first few patches refactor the FADump code to make use of common
code across multiple platforms. Then basic FADump support is added for
PowerNV platform. Followed by patches to honour reserved-ranges DT node
while reserving/releasing memory used by FADump. The subsequent patch
processes CPU state data provided by firmware to create and append core
notes to the ELF core file and the next patch adds support to preserve
crash data for subsequent boots (useful in cases like petitboot). The
subsequent patches add support to export opalcore. opalcore makes
debugging of failures in OPAL code easier. Firmware-Assisted Dump
documentation is also updated appropriately.
The patch series is tested with the latest firmware plus the below skiboot
changes for MPIPL support:
https://patchwork.ozlabs.org/project/skiboot/list/?series=119169
("MPIPL support")
Changes in v4:
* Split the patches.
* Rebased to latest upstream kernel version.
* Updated according to latest OPAL changes.
---
Hari Bathini (25):
powerpc/fadump: move internal macros/definitions to a new header
powerpc/fadump: move internal code to a new file
powerpc/fadump: Improve fadump documentation
pseries/fadump: move rtas specific definitions to platform code
pseries/fadump: introduce callbacks for platform specific operations
pseries/fadump: define register/un-register callback functions
pseries/fadump: move out platform specific support from generic code
powerpc/fadump: use FADump instead of fadump for how it is pronounced
opal: add MPIPL interface definitions
powernv/fadump: add fadump support on powernv
powernv/fadump: register kernel metadata address with opal
powernv/fadump: define register/un-register callback functions
powernv/fadump: support copying multiple kernel memory regions
powernv/fadump: process the crashdump by exporting it as /proc/vmcore
powerpc/fadump: Update documentation about OPAL platform support
powerpc/fadump: consider reserved ranges while reserving memory
powerpc/fadump: consider reserved ranges while releasing memory
powernv/fadump: process architected register state data provided by firmware
powernv/fadump: add support to preserve crash data on FADUMP disabled kernel
powerpc/fadump: update documentation about CONFIG_PRESERVE_FA_DUMP
powernv/opalcore: export /sys/firmware/opal/core for analysing opal crashes
powernv/fadump: Warn before processing partial crashdump
powernv/opalcore: provide an option to invalidate /sys/firmware/opal/core file
powernv/fadump: consider f/w load area
powernv/fadump: update documentation about option to release opalcore
Documentation/powerpc/firmware-assisted-dump.txt | 224 +++-
arch/powerpc/Kconfig | 23
arch/powerpc/include/asm/fadump.h | 190 ----
arch/powerpc/include/asm/opal-api.h | 50 +
arch/powerpc/include/asm/opal.h | 6
arch/powerpc/kernel/Makefile | 6
arch/powerpc/kernel/fadump-common.c | 153 +++
arch/powerpc/kernel/fadump-common.h | 203 ++++
arch/powerpc/kernel/fadump.c | 1181 ++++++++--------------
arch/powerpc/kernel/prom.c | 4
arch/powerpc/platforms/powernv/Makefile | 3
arch/powerpc/platforms/powernv/opal-call.c | 3
arch/powerpc/platforms/powernv/opal-core.c | 637 ++++++++++++
arch/powerpc/platforms/powernv/opal-fadump.c | 671 ++++++++++++
arch/powerpc/platforms/powernv/opal-fadump.h | 154 +++
arch/powerpc/platforms/pseries/Makefile | 1
arch/powerpc/platforms/pseries/rtas-fadump.c | 595 +++++++++++
arch/powerpc/platforms/pseries/rtas-fadump.h | 123 ++
18 files changed, 3231 insertions(+), 996 deletions(-)
create mode 100644 arch/powerpc/kernel/fadump-common.c
create mode 100644 arch/powerpc/kernel/fadump-common.h
create mode 100644 arch/powerpc/platforms/powernv/opal-core.c
create mode 100644 arch/powerpc/platforms/powernv/opal-fadump.c
create mode 100644 arch/powerpc/platforms/powernv/opal-fadump.h
create mode 100644 arch/powerpc/platforms/pseries/rtas-fadump.c
create mode 100644 arch/powerpc/platforms/pseries/rtas-fadump.h
^ permalink raw reply
* Re: [PATCH v3 10/11] mm/memory_hotplug: Make unregister_memory_block_under_nodes() never fail
From: David Hildenbrand @ 2019-07-16 11:09 UTC (permalink / raw)
To: Oscar Salvador
Cc: linux-s390, linux-ia64, linux-sh, Greg Kroah-Hartman, Mark Brown,
Rafael J. Wysocki, linux-kernel, Chris Wilson, Michal Hocko,
linux-mm, David S. Miller, Jonathan Cameron, Alex Deucher,
Igor Mammedov, akpm, Wei Yang, linuxppc-dev, Dan Williams,
linux-arm-kernel
In-Reply-To: <20190716084626.GA12394@linux>
On 16.07.19 10:46, Oscar Salvador wrote:
> On Mon, Jul 15, 2019 at 01:10:33PM +0200, David Hildenbrand wrote:
>> On 01.07.19 12:27, Michal Hocko wrote:
>>> On Mon 01-07-19 11:36:44, Oscar Salvador wrote:
>>>> On Mon, Jul 01, 2019 at 10:51:44AM +0200, Michal Hocko wrote:
>>>>> Yeah, we do not allow to offline multi zone (node) ranges so the current
>>>>> code seems to be over engineered.
>>>>>
>>>>> Anyway, I am wondering why do we have to strictly check for already
>>>>> removed nodes links. Is the sysfs code going to complain we we try to
>>>>> remove again?
>>>>
>>>> No, sysfs will silently "fail" if the symlink has already been removed.
>>>> At least that is what I saw last time I played with it.
>>>>
>>>> I guess the question is what if sysfs handling changes in the future
>>>> and starts dropping warnings when trying to remove a symlink is not there.
>>>> Maybe that is unlikely to happen?
>>>
>>> And maybe we handle it then rather than have a static allocation that
>>> everybody with hotremove configured has to pay for.
>>>
>>
>> So what's the suggestion? Dropping the nodemask_t completely and calling
>> sysfs_remove_link() on already potentially removed links?
>>
>> Of course, we can also just use mem_blk->nid and rest assured that it
>> will never be called for memory blocks belonging to multiple nodes.
>
> Hi David,
>
> While it is easy to construct a scenario where a memblock belongs to multiple
> nodes, I have to confess that I yet have not seen that in a real-world scenario.
>
> Given said that, I think that the less risky way is to just drop the nodemask_t
> and do not care about calling sysfs_remove_link() for already removed links.
> As I said, sysfs_remove_link() will silently fail when it fails to find the
> symlink, so I do not think it is a big deal.
>
>
As far as I can tell we
a) don't allow offlining of memory that belongs to multiple nodes
already (as pointed out by Michal recently)
b) users cannot add memory blocks that belong to multiple nodes via
add_memory()
So I don't see a way how remove_memory() (and even offline_pages())
could ever succeed on such memory blocks.
I think it should be fine to limit it to one node here. (if not, I guess
we would have a different BUG that would actually allow to remove such
memory blocks)
--
Thanks,
David / dhildenb
^ permalink raw reply
* Re: [PATCH v3 10/11] mm/memory_hotplug: Make unregister_memory_block_under_nodes() never fail
From: David Hildenbrand @ 2019-07-16 11:08 UTC (permalink / raw)
To: Oscar Salvador
Cc: linux-s390, linux-ia64, linux-sh, Greg Kroah-Hartman, Mark Brown,
Rafael J. Wysocki, linux-kernel, Chris Wilson, Michal Hocko,
linux-mm, David S. Miller, Jonathan Cameron, Alex Deucher,
Igor Mammedov, akpm, Wei Yang, linuxppc-dev, Dan Williams,
linux-arm-kernel
In-Reply-To: <20190716084626.GA12394@linux>
On 16.07.19 10:46, Oscar Salvador wrote:
> On Mon, Jul 15, 2019 at 01:10:33PM +0200, David Hildenbrand wrote:
>> On 01.07.19 12:27, Michal Hocko wrote:
>>> On Mon 01-07-19 11:36:44, Oscar Salvador wrote:
>>>> On Mon, Jul 01, 2019 at 10:51:44AM +0200, Michal Hocko wrote:
>>>>> Yeah, we do not allow to offline multi zone (node) ranges so the current
>>>>> code seems to be over engineered.
>>>>>
>>>>> Anyway, I am wondering why do we have to strictly check for already
>>>>> removed nodes links. Is the sysfs code going to complain we we try to
>>>>> remove again?
>>>>
>>>> No, sysfs will silently "fail" if the symlink has already been removed.
>>>> At least that is what I saw last time I played with it.
>>>>
>>>> I guess the question is what if sysfs handling changes in the future
>>>> and starts dropping warnings when trying to remove a symlink is not there.
>>>> Maybe that is unlikely to happen?
>>>
>>> And maybe we handle it then rather than have a static allocation that
>>> everybody with hotremove configured has to pay for.
>>>
>>
>> So what's the suggestion? Dropping the nodemask_t completely and calling
>> sysfs_remove_link() on already potentially removed links?
>>
>> Of course, we can also just use mem_blk->nid and rest assured that it
>> will never be called for memory blocks belonging to multiple nodes.
>
> Hi David,
>
> While it is easy to construct a scenario where a memblock belongs to multiple
> nodes, I have to confess that I yet have not seen that in a real-world scenario.
>
> Given said that, I think that the less risky way is to just drop the nodemask_t
> and do not care about calling sysfs_remove_link() for already removed links.
> As I said, sysfs_remove_link() will silently fail when it fails to find the
> symlink, so I do not think it is a big deal.
>
>
As far as I can tell we
a) don't allow offlining of memory that belongs to multiple nodes
already (as pointed out by Michael recently)
b) users cannot add memory blocks that belong to multiple nodes via
add_memory()
So I don't see a way how remove_memory() (and even offline_pages())
could ever succeed on such memory blocks.
I think it should be fine to limit it to one node here. (if not, I guess
we would have a different BUG that would actually allow to remove such
memory blocks)
--
Thanks,
David / dhildenb
^ permalink raw reply
* Re: [PATCH 00/10] cpufreq: Migrate users of policy notifiers to QoS requests
From: Rafael J. Wysocki @ 2019-07-16 10:27 UTC (permalink / raw)
To: Viresh Kumar
Cc: open list:ACPI COMPONENT ARCHITECTURE (ACPICA), linuxppc-dev,
Vincent Guittot, open list:DOCUMENTATION, Rafael J. Wysocki,
Amit Daniel Kachhap, Daniel Lezcano, Rafael Wysocki, Robert Moore,
dri-devel, Linux Kernel Mailing List, Eduardo Valentin,
ACPI Devel Maling List, open list:FRAMEBUFFER LAYER,
Greg Kroah-Hartman, Linux PM, Zhang Rui, Javi Merino,
Erik Schmauss, Len Brown
In-Reply-To: <20190716101416.ntk353cfnrcykoek@vireshk-i7>
On Tue, Jul 16, 2019 at 12:14 PM Viresh Kumar <viresh.kumar@linaro.org> wrote:
>
> On 16-07-19, 12:06, Rafael J. Wysocki wrote:
> > On Tue, Jul 16, 2019 at 11:49 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > >
> > > Hello,
> > >
> > > Now that cpufreq core supports taking QoS requests for min/max cpu
> > > frequencies, lets migrate rest of the users to using them instead of the
> > > policy notifiers.
> >
> > Technically, this still is linux-next only. :-)
>
> True :)
>
> > > The CPUFREQ_NOTIFY and CPUFREQ_ADJUST events of the policy notifiers are
> > > removed as a result, but we have to add CPUFREQ_CREATE_POLICY and
> > > CPUFREQ_REMOVE_POLICY events to it for the acpi stuff specifically. So
> > > the policy notifiers aren't completely removed.
> >
> > That's not entirely accurate, because arch_topology is going to use
> > CPUFREQ_CREATE_POLICY now too.
>
> Yeah, I thought about that while writing this patchset and
> coverletter. But had it not been required for ACPI, I would have done
> it differently for the arch-topology code. Maybe direct calling of
> arch-topology routine from cpufreq core. I wanted to get rid of the
> policy notifiers completely but I couldn't find a better way of doing
> it for ACPI stuff.
>
> > > Boot tested on my x86 PC and ARM hikey board. Nothing looked broken :)
> > >
> > > This has already gone through build bot for a few days now.
> >
> > So I'd prefer patches [5-8] to go right after the first one and then
> > do the cleanups on top of that, as somebody may want to backport the
> > essential changes without the cleanups.
>
> In the exceptional case where nobody finds anything wrong with the
> patches (highly unlikely), do you want me to resend with reordering or
> you can reorder them while applying? There are no dependencies between
> those patches anyway.
Please resend the reordered set when the merge window closes.
^ permalink raw reply
* Re: [PATCH 00/10] cpufreq: Migrate users of policy notifiers to QoS requests
From: Viresh Kumar @ 2019-07-16 10:14 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: open list:ACPI COMPONENT ARCHITECTURE (ACPICA), linuxppc-dev,
Vincent Guittot, open list:DOCUMENTATION, Linux PM,
Amit Daniel Kachhap, Daniel Lezcano, Rafael Wysocki, Robert Moore,
dri-devel, Linux Kernel Mailing List, Eduardo Valentin,
ACPI Devel Maling List, open list:FRAMEBUFFER LAYER,
Greg Kroah-Hartman, Zhang Rui, Javi Merino, Erik Schmauss,
Len Brown
In-Reply-To: <CAJZ5v0iqYHNt6NQy3Fi1B=XtjNOm2x0mX3+7eWBREgFZRpUS+w@mail.gmail.com>
On 16-07-19, 12:06, Rafael J. Wysocki wrote:
> On Tue, Jul 16, 2019 at 11:49 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> >
> > Hello,
> >
> > Now that cpufreq core supports taking QoS requests for min/max cpu
> > frequencies, lets migrate rest of the users to using them instead of the
> > policy notifiers.
>
> Technically, this still is linux-next only. :-)
True :)
> > The CPUFREQ_NOTIFY and CPUFREQ_ADJUST events of the policy notifiers are
> > removed as a result, but we have to add CPUFREQ_CREATE_POLICY and
> > CPUFREQ_REMOVE_POLICY events to it for the acpi stuff specifically. So
> > the policy notifiers aren't completely removed.
>
> That's not entirely accurate, because arch_topology is going to use
> CPUFREQ_CREATE_POLICY now too.
Yeah, I thought about that while writing this patchset and
coverletter. But had it not been required for ACPI, I would have done
it differently for the arch-topology code. Maybe direct calling of
arch-topology routine from cpufreq core. I wanted to get rid of the
policy notifiers completely but I couldn't find a better way of doing
it for ACPI stuff.
> > Boot tested on my x86 PC and ARM hikey board. Nothing looked broken :)
> >
> > This has already gone through build bot for a few days now.
>
> So I'd prefer patches [5-8] to go right after the first one and then
> do the cleanups on top of that, as somebody may want to backport the
> essential changes without the cleanups.
In the exceptional case where nobody finds anything wrong with the
patches (highly unlikely), do you want me to resend with reordering or
you can reorder them while applying? There are no dependencies between
those patches anyway.
--
viresh
^ permalink raw reply
* Re: [PATCH 00/10] cpufreq: Migrate users of policy notifiers to QoS requests
From: Rafael J. Wysocki @ 2019-07-16 10:06 UTC (permalink / raw)
To: Viresh Kumar
Cc: open list:ACPI COMPONENT ARCHITECTURE (ACPICA), linuxppc-dev,
Vincent Guittot, open list:DOCUMENTATION, Rafael J. Wysocki,
Amit Daniel Kachhap, Daniel Lezcano, Rafael Wysocki, Robert Moore,
dri-devel, Linux Kernel Mailing List, Eduardo Valentin,
ACPI Devel Maling List, open list:FRAMEBUFFER LAYER,
Greg Kroah-Hartman, Linux PM, Zhang Rui, Javi Merino,
Erik Schmauss, Len Brown
In-Reply-To: <cover.1563269894.git.viresh.kumar@linaro.org>
On Tue, Jul 16, 2019 at 11:49 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
>
> Hello,
>
> Now that cpufreq core supports taking QoS requests for min/max cpu
> frequencies, lets migrate rest of the users to using them instead of the
> policy notifiers.
Technically, this still is linux-next only. :-)
> The CPUFREQ_NOTIFY and CPUFREQ_ADJUST events of the policy notifiers are
> removed as a result, but we have to add CPUFREQ_CREATE_POLICY and
> CPUFREQ_REMOVE_POLICY events to it for the acpi stuff specifically. So
> the policy notifiers aren't completely removed.
That's not entirely accurate, because arch_topology is going to use
CPUFREQ_CREATE_POLICY now too.
> Boot tested on my x86 PC and ARM hikey board. Nothing looked broken :)
>
> This has already gone through build bot for a few days now.
So I'd prefer patches [5-8] to go right after the first one and then
do the cleanups on top of that, as somebody may want to backport the
essential changes without the cleanups.
^ permalink raw reply
* [PATCH 06/10] powerpc: macintosh: Switch to QoS requests instead of cpufreq notifier
From: Viresh Kumar @ 2019-07-16 9:54 UTC (permalink / raw)
To: Rafael Wysocki, Benjamin Herrenschmidt
Cc: Viresh Kumar, Vincent Guittot, linuxppc-dev, linux-kernel,
linux-pm
In-Reply-To: <cover.1563270828.git.viresh.kumar@linaro.org>
The cpufreq core now takes the min/max frequency constraints via QoS
requests and the CPUFREQ_ADJUST notifier shall get removed later on.
Switch over to using the QoS request for maximum frequency constraint
for windfarm_cpufreq_clamp driver.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/macintosh/windfarm_cpufreq_clamp.c | 77 ++++++++++++++--------
1 file changed, 50 insertions(+), 27 deletions(-)
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
index 52fd5fca89a0..705c6200814b 100644
--- a/drivers/macintosh/windfarm_cpufreq_clamp.c
+++ b/drivers/macintosh/windfarm_cpufreq_clamp.c
@@ -3,9 +3,11 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/wait.h>
+#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <asm/prom.h>
@@ -16,36 +18,24 @@
static int clamped;
static struct wf_control *clamp_control;
-
-static int clamp_notifier_call(struct notifier_block *self,
- unsigned long event, void *data)
-{
- struct cpufreq_policy *p = data;
- unsigned long max_freq;
-
- if (event != CPUFREQ_ADJUST)
- return 0;
-
- max_freq = clamped ? (p->cpuinfo.min_freq) : (p->cpuinfo.max_freq);
- cpufreq_verify_within_limits(p, 0, max_freq);
-
- return 0;
-}
-
-static struct notifier_block clamp_notifier = {
- .notifier_call = clamp_notifier_call,
-};
+static struct dev_pm_qos_request qos_req;
+static unsigned int min_freq, max_freq;
static int clamp_set(struct wf_control *ct, s32 value)
{
- if (value)
+ unsigned int freq;
+
+ if (value) {
+ freq = min_freq;
printk(KERN_INFO "windfarm: Clamping CPU frequency to "
"minimum !\n");
- else
+ } else {
+ freq = max_freq;
printk(KERN_INFO "windfarm: CPU frequency unclamped !\n");
+ }
clamped = value;
- cpufreq_update_policy(0);
- return 0;
+
+ return dev_pm_qos_update_request(&qos_req, freq);
}
static int clamp_get(struct wf_control *ct, s32 *value)
@@ -74,27 +64,60 @@ static const struct wf_control_ops clamp_ops = {
static int __init wf_cpufreq_clamp_init(void)
{
+ struct cpufreq_policy *policy;
struct wf_control *clamp;
+ struct device *dev;
+ int ret;
+
+ policy = cpufreq_cpu_get(0);
+ if (!policy) {
+ pr_warn("%s: cpufreq policy not found cpu0\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
+ min_freq = policy->cpuinfo.min_freq;
+ max_freq = policy->cpuinfo.max_freq;
+ cpufreq_cpu_put(policy);
+
+ dev = get_cpu_device(0);
+ if (unlikely(!dev)) {
+ pr_warn("%s: No cpu device for cpu0\n", __func__);
+ return -ENODEV;
+ }
clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
if (clamp == NULL)
return -ENOMEM;
- cpufreq_register_notifier(&clamp_notifier, CPUFREQ_POLICY_NOTIFIER);
+
+ ret = dev_pm_qos_add_request(dev, &qos_req, DEV_PM_QOS_MAX_FREQUENCY,
+ max_freq);
+ if (ret < 0) {
+ pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
+ ret);
+ goto free;
+ }
+
clamp->ops = &clamp_ops;
clamp->name = "cpufreq-clamp";
- if (wf_register_control(clamp))
+ ret = wf_register_control(clamp);
+ if (ret)
goto fail;
clamp_control = clamp;
return 0;
fail:
+ dev_pm_qos_remove_request(&qos_req);
+
+ free:
kfree(clamp);
- return -ENODEV;
+ return ret;
}
static void __exit wf_cpufreq_clamp_exit(void)
{
- if (clamp_control)
+ if (clamp_control) {
wf_unregister_control(clamp_control);
+ dev_pm_qos_remove_request(&qos_req);
+ }
}
--
2.21.0.rc0.269.g1a574e7a288b
^ permalink raw reply related
* [PATCH 00/10] cpufreq: Migrate users of policy notifiers to QoS requests
From: Viresh Kumar @ 2019-07-16 9:48 UTC (permalink / raw)
To: Rafael Wysocki, Amit Daniel Kachhap, Benjamin Herrenschmidt,
Daniel Lezcano, Eduardo Valentin, Erik Schmauss,
Greg Kroah-Hartman, Javi Merino, Len Brown, Rafael J. Wysocki,
Robert Moore, Zhang Rui
Cc: linux-fbdev, Vincent Guittot, linux-pm, Viresh Kumar, linux-doc,
linux-kernel, dri-devel, linux-acpi, linuxppc-dev, devel
Hello,
Now that cpufreq core supports taking QoS requests for min/max cpu
frequencies, lets migrate rest of the users to using them instead of the
policy notifiers.
The CPUFREQ_NOTIFY and CPUFREQ_ADJUST events of the policy notifiers are
removed as a result, but we have to add CPUFREQ_CREATE_POLICY and
CPUFREQ_REMOVE_POLICY events to it for the acpi stuff specifically. So
the policy notifiers aren't completely removed.
Boot tested on my x86 PC and ARM hikey board. Nothing looked broken :)
This has already gone through build bot for a few days now.
--
viresh
Viresh Kumar (10):
cpufreq: Add policy create/remove notifiers
video: sa1100fb: Remove cpufreq policy notifier
video: pxafb: Remove cpufreq policy notifier
arch_topology: Use CPUFREQ_CREATE_POLICY instead of CPUFREQ_NOTIFY
thermal: cpu_cooling: Switch to QoS requests instead of cpufreq
notifier
powerpc: macintosh: Switch to QoS requests instead of cpufreq notifier
cpufreq: powerpc_cbe: Switch to QoS requests instead of cpufreq
notifier
ACPI: cpufreq: Switch to QoS requests instead of cpufreq notifier
cpufreq: Remove CPUFREQ_ADJUST and CPUFREQ_NOTIFY policy notifier
events
Documentation: cpufreq: Update policy notifier documentation
Documentation/cpu-freq/core.txt | 16 +--
drivers/acpi/processor_driver.c | 44 ++++++++-
drivers/acpi/processor_perflib.c | 106 +++++++++-----------
drivers/acpi/processor_thermal.c | 81 ++++++++-------
drivers/base/arch_topology.c | 2 +-
drivers/cpufreq/cpufreq.c | 51 ++++------
drivers/cpufreq/ppc_cbe_cpufreq.c | 19 +++-
drivers/cpufreq/ppc_cbe_cpufreq.h | 8 ++
drivers/cpufreq/ppc_cbe_cpufreq_pmi.c | 96 +++++++++++-------
drivers/macintosh/windfarm_cpufreq_clamp.c | 77 ++++++++++-----
drivers/thermal/cpu_cooling.c | 110 +++++----------------
drivers/video/fbdev/pxafb.c | 21 ----
drivers/video/fbdev/pxafb.h | 1 -
drivers/video/fbdev/sa1100fb.c | 27 -----
drivers/video/fbdev/sa1100fb.h | 1 -
include/acpi/processor.h | 22 +++--
include/linux/cpufreq.h | 4 +-
17 files changed, 327 insertions(+), 359 deletions(-)
--
2.21.0.rc0.269.g1a574e7a288b
^ permalink raw reply
* Re: [PATCH kernel v2] powerpc/xive: Drop deregistered irqs
From: Cédric Le Goater @ 2019-07-16 8:59 UTC (permalink / raw)
To: Alexey Kardashevskiy, linuxppc-dev
Cc: Alistair Popple, Daniel Henrique Barboza, Greg Kurz,
Nicholas Piggin, Paul Mackerras, David Gibson
In-Reply-To: <20190715071131.86173-1-aik@ozlabs.ru>
On 15/07/2019 09:11, Alexey Kardashevskiy wrote:
> There is a race between releasing an irq on one cpu and fetching it
> from XIVE on another cpu as there does not seem to be any locking between
> these, probably because xive_irq_chip::irq_shutdown() is supposed to
> remove the irq from all queues in the system which it does not do.
>
> As a result, when such released irq appears in a queue, we take it
> from the queue but we do not change the current priority on that cpu and
> since there is no handler for the irq, EOI is never called and the cpu
> current priority remains elevated (7 vs. 0xff==unmasked). If another irq
> is assigned to the same cpu, then that device stops working until irq
> is moved to another cpu or the device is reset.
>
> This adds a new ppc_md.orphan_irq callback which is called if no irq
> descriptor is found. The XIVE implementation drops the current priority
> to 0xff which effectively unmasks interrupts in a current CPU.
The test on generic_handle_irq() catches interrupt events that
were served on a target CPU while the source interrupt was being
shutdown on another CPU.
The orphan_irq() handler restores the CPPR in such cases.
This looks OK to me. I would have added some more comments in the
code.
Reviewed-by: Cédric Le Goater <clg@kaod.org>
And adding to the list of future cleanups : a 'set_cppr' helper.
Thanks,
C.
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> Changes:
> v2:
> * added ppc_md.orphan_irq
>
> ---
>
> Found it on P9 system with:
> - a host with 8 cpus online
> - a boot disk on ahci with its msix on cpu#0
> - a guest with 2xGPUs + 6xNVLink + 4 cpus
> - GPU#0 from the guest is bound to the same cpu#0.
>
> Killing a guest killed ahci and therefore the host because of the race.
> Note that VFIO masks interrupts first and only then resets the device.
> ---
> arch/powerpc/include/asm/machdep.h | 3 +++
> arch/powerpc/kernel/irq.c | 9 ++++++---
> arch/powerpc/sysdev/xive/common.c | 10 ++++++++++
> 3 files changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
> index c43d6eca9edd..6cc14e28e89a 100644
> --- a/arch/powerpc/include/asm/machdep.h
> +++ b/arch/powerpc/include/asm/machdep.h
> @@ -59,6 +59,9 @@ struct machdep_calls {
> /* Return an irq, or 0 to indicate there are none pending. */
> unsigned int (*get_irq)(void);
>
> + /* Drops irq if it does not have a valid descriptor */
> + void (*orphan_irq)(unsigned int irq);
> +
> /* PCI stuff */
> /* Called after allocating resources */
> void (*pcibios_fixup)(void);
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index bc68c53af67c..b4e06d05bdba 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -632,10 +632,13 @@ void __do_irq(struct pt_regs *regs)
> may_hard_irq_enable();
>
> /* And finally process it */
> - if (unlikely(!irq))
> + if (unlikely(!irq)) {
> __this_cpu_inc(irq_stat.spurious_irqs);
> - else
> - generic_handle_irq(irq);
> + } else if (generic_handle_irq(irq)) {
> + if (ppc_md.orphan_irq)
> + ppc_md.orphan_irq(irq);
> + __this_cpu_inc(irq_stat.spurious_irqs);
> + }
>
> trace_irq_exit(regs);
>
> diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c
> index 082c7e1c20f0..b4054091999a 100644
> --- a/arch/powerpc/sysdev/xive/common.c
> +++ b/arch/powerpc/sysdev/xive/common.c
> @@ -283,6 +283,15 @@ static unsigned int xive_get_irq(void)
> return irq;
> }
>
> +static void xive_orphan_irq(unsigned int irq)
> +{
> + struct xive_cpu *xc = __this_cpu_read(xive_cpu);
> +
> + xc->cppr = 0xff;
> + out_8(xive_tima + xive_tima_offset + TM_CPPR, 0xff);
> + DBG_VERBOSE("orphan_irq: irq %d, adjusting CPPR to 0xff\n", irq);
> +}
> +
> /*
> * After EOI'ing an interrupt, we need to re-check the queue
> * to see if another interrupt is pending since multiple
> @@ -1419,6 +1428,7 @@ bool __init xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 o
> xive_irq_priority = max_prio;
>
> ppc_md.get_irq = xive_get_irq;
> + ppc_md.orphan_irq = xive_orphan_irq;
> __xive_enabled = true;
>
> pr_devel("Initializing host..\n");
>
^ permalink raw reply
* Re: [PATCH kernel v2] powerpc/xive: Drop deregistered irqs
From: Cédric Le Goater @ 2019-07-16 9:14 UTC (permalink / raw)
To: Alexey Kardashevskiy, linuxppc-dev
Cc: Alistair Popple, Daniel Henrique Barboza, Greg Kurz,
Nicholas Piggin, Paul Mackerras, David Gibson
In-Reply-To: <b8722c86-317d-ba60-1b16-d848c86d0e71@ozlabs.ru>
On 16/07/2019 11:10, Alexey Kardashevskiy wrote:
>
>
> On 16/07/2019 18:59, Cédric Le Goater wrote:
>> On 15/07/2019 09:11, Alexey Kardashevskiy wrote:
>>> There is a race between releasing an irq on one cpu and fetching it
>>> from XIVE on another cpu as there does not seem to be any locking between
>>> these, probably because xive_irq_chip::irq_shutdown() is supposed to
>>> remove the irq from all queues in the system which it does not do.
>>>
>>> As a result, when such released irq appears in a queue, we take it
>>> from the queue but we do not change the current priority on that cpu and
>>> since there is no handler for the irq, EOI is never called and the cpu
>>> current priority remains elevated (7 vs. 0xff==unmasked). If another irq
>>> is assigned to the same cpu, then that device stops working until irq
>>> is moved to another cpu or the device is reset.
>>>
>>> This adds a new ppc_md.orphan_irq callback which is called if no irq
>>> descriptor is found. The XIVE implementation drops the current priority
>>> to 0xff which effectively unmasks interrupts in a current CPU.
>>
>>
>> The test on generic_handle_irq() catches interrupt events that
>> were served on a target CPU while the source interrupt was being
>> shutdown on another CPU.
>>
>> The orphan_irq() handler restores the CPPR in such cases.
>>
>> This looks OK to me. I would have added some more comments in the
>> code.
>
>
> Which and where? Thanks,
Above xive_orphan_irq() explaining the complete problem that we are
addressing. XIVE is not super obvious when looking at the code ...
C.
>
>> Reviewed-by: Cédric Le Goater <clg@kaod.org>
>>
>>
>> And adding to the list of future cleanups : a 'set_cppr' helper.
>>
>> Thanks,
>>
>> C.
>>
>>
>>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>>> ---
>>> Changes:
>>> v2:
>>> * added ppc_md.orphan_irq
>>>
>>> ---
>>>
>>> Found it on P9 system with:
>>> - a host with 8 cpus online
>>> - a boot disk on ahci with its msix on cpu#0
>>> - a guest with 2xGPUs + 6xNVLink + 4 cpus
>>> - GPU#0 from the guest is bound to the same cpu#0.
>>>
>>> Killing a guest killed ahci and therefore the host because of the race.
>>> Note that VFIO masks interrupts first and only then resets the device.
>>> ---
>>> arch/powerpc/include/asm/machdep.h | 3 +++
>>> arch/powerpc/kernel/irq.c | 9 ++++++---
>>> arch/powerpc/sysdev/xive/common.c | 10 ++++++++++
>>> 3 files changed, 19 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
>>> index c43d6eca9edd..6cc14e28e89a 100644
>>> --- a/arch/powerpc/include/asm/machdep.h
>>> +++ b/arch/powerpc/include/asm/machdep.h
>>> @@ -59,6 +59,9 @@ struct machdep_calls {
>>> /* Return an irq, or 0 to indicate there are none pending. */
>>> unsigned int (*get_irq)(void);
>>> + /* Drops irq if it does not have a valid descriptor */
>>> + void (*orphan_irq)(unsigned int irq);
>>> +
>>> /* PCI stuff */
>>> /* Called after allocating resources */
>>> void (*pcibios_fixup)(void);
>>> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
>>> index bc68c53af67c..b4e06d05bdba 100644
>>> --- a/arch/powerpc/kernel/irq.c
>>> +++ b/arch/powerpc/kernel/irq.c
>>> @@ -632,10 +632,13 @@ void __do_irq(struct pt_regs *regs)
>>> may_hard_irq_enable();
>>> /* And finally process it */
>>> - if (unlikely(!irq))
>>> + if (unlikely(!irq)) {
>>> __this_cpu_inc(irq_stat.spurious_irqs);
>>> - else
>>> - generic_handle_irq(irq);
>>> + } else if (generic_handle_irq(irq)) {
>>> + if (ppc_md.orphan_irq)
>>> + ppc_md.orphan_irq(irq);
>>> + __this_cpu_inc(irq_stat.spurious_irqs);
>>> + }
>>> trace_irq_exit(regs);
>>> diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c
>>> index 082c7e1c20f0..b4054091999a 100644
>>> --- a/arch/powerpc/sysdev/xive/common.c
>>> +++ b/arch/powerpc/sysdev/xive/common.c
>>> @@ -283,6 +283,15 @@ static unsigned int xive_get_irq(void)
>>> return irq;
>>> }
>>> +static void xive_orphan_irq(unsigned int irq)
>>> +{
>>> + struct xive_cpu *xc = __this_cpu_read(xive_cpu);
>>> +
>>> + xc->cppr = 0xff;
>>> + out_8(xive_tima + xive_tima_offset + TM_CPPR, 0xff);
>>> + DBG_VERBOSE("orphan_irq: irq %d, adjusting CPPR to 0xff\n", irq);
>>> +}
>>> +
>>> /*
>>> * After EOI'ing an interrupt, we need to re-check the queue
>>> * to see if another interrupt is pending since multiple
>>> @@ -1419,6 +1428,7 @@ bool __init xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 o
>>> xive_irq_priority = max_prio;
>>> ppc_md.get_irq = xive_get_irq;
>>> + ppc_md.orphan_irq = xive_orphan_irq;
>>> __xive_enabled = true;
>>> pr_devel("Initializing host..\n");
>>>
>>
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox