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:
Родитель
de8f0b173d
Коммит
a0f7180a2c
|
@ -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),
|
||||
|
|
Загрузка…
Ссылка в новой задаче