Skip to content

Commit

Permalink
powerpc/fadump: Fix fadump to work with a different endian capture ke…
Browse files Browse the repository at this point in the history
…rnel

Dump capture would fail if capture kernel is not of the endianess as the
production kernel, because the in-memory data structure (struct
opal_fadump_mem_struct) shared across production kernel and capture
kernel assumes the same endianess for both the kernels, which doesn't
have to be true always. Fix it by having a well-defined endianess for
struct opal_fadump_mem_struct.

Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/161902744901.86147.14719228311655123526.stgit@hbathini
  • Loading branch information
hbathini authored and mpe committed Apr 26, 2022
1 parent a84ca70 commit b74196a
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 47 deletions.
94 changes: 52 additions & 42 deletions arch/powerpc/platforms/powernv/opal-fadump.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
addr = be64_to_cpu(addr);
pr_debug("Kernel metadata addr: %llx\n", addr);
opal_fdm_active = (void *)addr;
if (opal_fdm_active->registered_regions == 0)
if (be16_to_cpu(opal_fdm_active->registered_regions) == 0)
return;

ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_BOOT_MEM, &addr);
Expand Down Expand Up @@ -95,17 +95,17 @@ static int opal_fadump_unregister(struct fw_dump *fadump_conf);
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);
pr_debug("Boot memory regions count: %d\n", be16_to_cpu(fdm->region_cnt));

/*
* 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;
fadump_conf->boot_mem_dest_addr = be64_to_cpu(fdm->rgn[0].dest);
pr_debug("Destination address of boot memory regions: %#016llx\n",
fadump_conf->boot_mem_dest_addr);

fadump_conf->fadumphdr_addr = fdm->fadumphdr_addr;
fadump_conf->fadumphdr_addr = be64_to_cpu(fdm->fadumphdr_addr);
}

/*
Expand All @@ -126,9 +126,9 @@ static void __init opal_fadump_get_config(struct fw_dump *fadump_conf,
fadump_conf->boot_memory_size = 0;

pr_debug("Boot memory regions:\n");
for (i = 0; i < fdm->region_cnt; i++) {
base = fdm->rgn[i].src;
size = fdm->rgn[i].size;
for (i = 0; i < be16_to_cpu(fdm->region_cnt); i++) {
base = be64_to_cpu(fdm->rgn[i].src);
size = be64_to_cpu(fdm->rgn[i].size);
pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);

fadump_conf->boot_mem_addr[i] = base;
Expand All @@ -143,7 +143,7 @@ static void __init opal_fadump_get_config(struct fw_dump *fadump_conf,
* Start address of reserve dump area (permanent reservation) for
* re-registering FADump after dump capture.
*/
fadump_conf->reserve_dump_area_start = fdm->rgn[0].dest;
fadump_conf->reserve_dump_area_start = be64_to_cpu(fdm->rgn[0].dest);

/*
* Rarely, but it can so happen that system crashes before all
Expand All @@ -155,13 +155,14 @@ static void __init opal_fadump_get_config(struct fw_dump *fadump_conf,
* Hope the memory that could not be preserved only has pages
* that are usually filtered out while saving the vmcore.
*/
if (fdm->region_cnt > fdm->registered_regions) {
if (be16_to_cpu(fdm->region_cnt) > be16_to_cpu(fdm->registered_regions)) {
pr_warn("Not all memory regions were saved!!!\n");
pr_warn(" Unsaved memory regions:\n");
i = fdm->registered_regions;
while (i < fdm->region_cnt) {
i = be16_to_cpu(fdm->registered_regions);
while (i < be16_to_cpu(fdm->region_cnt)) {
pr_warn("\t[%03d] base: 0x%llx, size: 0x%llx\n",
i, fdm->rgn[i].src, fdm->rgn[i].size);
i, be64_to_cpu(fdm->rgn[i].src),
be64_to_cpu(fdm->rgn[i].size));
i++;
}

Expand All @@ -170,43 +171,46 @@ static void __init opal_fadump_get_config(struct fw_dump *fadump_conf,
}

fadump_conf->boot_mem_top = (fadump_conf->boot_memory_size + hole_size);
fadump_conf->boot_mem_regs_cnt = fdm->region_cnt;
fadump_conf->boot_mem_regs_cnt = be16_to_cpu(fdm->region_cnt);
opal_fadump_update_config(fadump_conf, fdm);
}

/* Initialize kernel metadata */
static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm)
{
fdm->version = OPAL_FADUMP_VERSION;
fdm->region_cnt = 0;
fdm->registered_regions = 0;
fdm->fadumphdr_addr = 0;
fdm->region_cnt = cpu_to_be16(0);
fdm->registered_regions = cpu_to_be16(0);
fdm->fadumphdr_addr = cpu_to_be64(0);
}

static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
{
u64 addr = fadump_conf->reserve_dump_area_start;
u16 reg_cnt;
int i;

opal_fdm = __va(fadump_conf->kernel_metadata);
opal_fadump_init_metadata(opal_fdm);

/* Boot memory regions */
reg_cnt = be16_to_cpu(opal_fdm->region_cnt);
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_sz[i];
opal_fdm->rgn[i].src = cpu_to_be64(fadump_conf->boot_mem_addr[i]);
opal_fdm->rgn[i].dest = cpu_to_be64(addr);
opal_fdm->rgn[i].size = cpu_to_be64(fadump_conf->boot_mem_sz[i]);

opal_fdm->region_cnt++;
reg_cnt++;
addr += fadump_conf->boot_mem_sz[i];
}
opal_fdm->region_cnt = cpu_to_be16(reg_cnt);

/*
* 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);
opal_fdm->fadumphdr_addr = cpu_to_be64(be64_to_cpu(opal_fdm->rgn[0].dest) +
fadump_conf->boot_memory_size);

opal_fadump_update_config(fadump_conf, opal_fdm);

Expand Down Expand Up @@ -269,18 +273,21 @@ static u64 opal_fadump_get_bootmem_min(void)
static int opal_fadump_register(struct fw_dump *fadump_conf)
{
s64 rc = OPAL_PARAMETER;
u16 registered_regs;
int i, err = -EIO;

for (i = 0; i < opal_fdm->region_cnt; i++) {
registered_regs = be16_to_cpu(opal_fdm->registered_regions);
for (i = 0; i < be16_to_cpu(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);
be64_to_cpu(opal_fdm->rgn[i].src),
be64_to_cpu(opal_fdm->rgn[i].dest),
be64_to_cpu(opal_fdm->rgn[i].size));
if (rc != OPAL_SUCCESS)
break;

opal_fdm->registered_regions++;
registered_regs++;
}
opal_fdm->registered_regions = cpu_to_be16(registered_regs);

switch (rc) {
case OPAL_SUCCESS:
Expand All @@ -291,7 +298,8 @@ static int opal_fadump_register(struct fw_dump *fadump_conf)
case OPAL_RESOURCE:
/* If MAX regions limit in f/w is hit, warn and proceed. */
pr_warn("%d regions could not be registered for MPIPL as MAX limit is reached!\n",
(opal_fdm->region_cnt - opal_fdm->registered_regions));
(be16_to_cpu(opal_fdm->region_cnt) -
be16_to_cpu(opal_fdm->registered_regions)));
fadump_conf->dump_registered = 1;
err = 0;
break;
Expand All @@ -312,7 +320,7 @@ static int opal_fadump_register(struct fw_dump *fadump_conf)
* If some regions were registered before OPAL_MPIPL_ADD_RANGE
* OPAL call failed, unregister all regions.
*/
if ((err < 0) && (opal_fdm->registered_regions > 0))
if ((err < 0) && (be16_to_cpu(opal_fdm->registered_regions) > 0))
opal_fadump_unregister(fadump_conf);

return err;
Expand All @@ -328,7 +336,7 @@ static int opal_fadump_unregister(struct fw_dump *fadump_conf)
return -EIO;
}

opal_fdm->registered_regions = 0;
opal_fdm->registered_regions = cpu_to_be16(0);
fadump_conf->dump_registered = 0;
return 0;
}
Expand Down Expand Up @@ -563,19 +571,20 @@ static void opal_fadump_region_show(struct fw_dump *fadump_conf,
else
fdm_ptr = opal_fdm;

for (i = 0; i < fdm_ptr->region_cnt; i++) {
for (i = 0; i < be16_to_cpu(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;
(i < be16_to_cpu(fdm_ptr->registered_regions)))
dumped_bytes = be64_to_cpu(fdm_ptr->rgn[i].size);

seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest);
be64_to_cpu(fdm_ptr->rgn[i].src),
be64_to_cpu(fdm_ptr->rgn[i].dest));
seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
fdm_ptr->rgn[i].size, dumped_bytes);
be64_to_cpu(fdm_ptr->rgn[i].size), dumped_bytes);
}

/* Dump is active. Show reserved area start address. */
Expand Down Expand Up @@ -624,6 +633,7 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
{
const __be32 *prop;
unsigned long dn;
__be64 be_addr;
u64 addr = 0;
int i, len;
s64 ret;
Expand Down Expand Up @@ -680,13 +690,13 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
if (!prop)
return;

ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr);
if ((ret != OPAL_SUCCESS) || !addr) {
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &be_addr);
if ((ret != OPAL_SUCCESS) || !be_addr) {
pr_err("Failed to get Kernel metadata (%lld)\n", ret);
return;
}

addr = be64_to_cpu(addr);
addr = be64_to_cpu(be_addr);
pr_debug("Kernel metadata addr: %llx\n", addr);

opal_fdm_active = __va(addr);
Expand All @@ -697,14 +707,14 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
}

/* Kernel regions not registered with f/w for MPIPL */
if (opal_fdm_active->registered_regions == 0) {
if (be16_to_cpu(opal_fdm_active->registered_regions) == 0) {
opal_fdm_active = NULL;
return;
}

ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &addr);
if (addr) {
addr = be64_to_cpu(addr);
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &be_addr);
if (be_addr) {
addr = be64_to_cpu(be_addr);
pr_debug("CPU metadata addr: %llx\n", addr);
opal_cpu_metadata = __va(addr);
}
Expand Down
10 changes: 5 additions & 5 deletions arch/powerpc/platforms/powernv/opal-fadump.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@
* OPAL FADump kernel metadata
*
* The address of this structure will be registered with f/w for retrieving
* and processing during crash dump.
* in the capture kernel to process the 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;
__be16 region_cnt; /* number of regions */
__be16 registered_regions; /* Regions registered for MPIPL */
__be64 fadumphdr_addr;
struct opal_mpipl_region rgn[FADUMP_MAX_MEM_REGS];
} __packed;

Expand Down Expand Up @@ -135,7 +135,7 @@ static inline void opal_fadump_read_regs(char *bufp, unsigned int regs_cnt,
for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) {
reg_entry = (struct hdat_fadump_reg_entry *)bufp;
val = (cpu_endian ? be64_to_cpu(reg_entry->reg_val) :
reg_entry->reg_val);
(u64)(reg_entry->reg_val));
opal_fadump_set_regval_regnum(regs,
be32_to_cpu(reg_entry->reg_type),
be32_to_cpu(reg_entry->reg_num),
Expand Down

0 comments on commit b74196a

Please sign in to comment.