powerpc/fadump: Fix fadump to work with a different endian capture kernel

[ Upstream commit b74196af37 ]

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
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Hari Bathini 2021-04-21 23:20:52 +05:30 коммит произвёл Greg Kroah-Hartman
Родитель de8f0b173d
Коммит a0f7180a2c
2 изменённых файлов: 57 добавлений и 47 удалений

Просмотреть файл

@ -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);
@ -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);
}
/*
@ -126,9 +126,9 @@ static void 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;
@ -143,7 +143,7 @@ static void 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
@ -155,13 +155,14 @@ static void 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++;
}
@ -170,7 +171,7 @@ static void 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);
}
@ -178,35 +179,38 @@ static void opal_fadump_get_config(struct fw_dump *fadump_conf,
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);
@ -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:
@ -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;
@ -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;
@ -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;
}
@ -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. */
@ -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;
@ -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);
@ -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);
}

Просмотреть файл

@ -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;
@ -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),