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);
|
addr = be64_to_cpu(addr);
|
||||||
pr_debug("Kernel metadata addr: %llx\n", addr);
|
pr_debug("Kernel metadata addr: %llx\n", addr);
|
||||||
opal_fdm_active = (void *)addr;
|
opal_fdm_active = (void *)addr;
|
||||||
if (opal_fdm_active->registered_regions == 0)
|
if (be16_to_cpu(opal_fdm_active->registered_regions) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_BOOT_MEM, &addr);
|
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,
|
static void opal_fadump_update_config(struct fw_dump *fadump_conf,
|
||||||
const struct opal_fadump_mem_struct *fdm)
|
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
|
* The destination address of the first boot memory region is the
|
||||||
* destination address of boot memory regions.
|
* 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",
|
pr_debug("Destination address of boot memory regions: %#016llx\n",
|
||||||
fadump_conf->boot_mem_dest_addr);
|
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;
|
fadump_conf->boot_memory_size = 0;
|
||||||
|
|
||||||
pr_debug("Boot memory regions:\n");
|
pr_debug("Boot memory regions:\n");
|
||||||
for (i = 0; i < fdm->region_cnt; i++) {
|
for (i = 0; i < be16_to_cpu(fdm->region_cnt); i++) {
|
||||||
base = fdm->rgn[i].src;
|
base = be64_to_cpu(fdm->rgn[i].src);
|
||||||
size = fdm->rgn[i].size;
|
size = be64_to_cpu(fdm->rgn[i].size);
|
||||||
pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);
|
pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);
|
||||||
|
|
||||||
fadump_conf->boot_mem_addr[i] = base;
|
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
|
* Start address of reserve dump area (permanent reservation) for
|
||||||
* re-registering FADump after dump capture.
|
* 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
|
* 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
|
* Hope the memory that could not be preserved only has pages
|
||||||
* that are usually filtered out while saving the vmcore.
|
* 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("Not all memory regions were saved!!!\n");
|
||||||
pr_warn(" Unsaved memory regions:\n");
|
pr_warn(" Unsaved memory regions:\n");
|
||||||
i = fdm->registered_regions;
|
i = be16_to_cpu(fdm->registered_regions);
|
||||||
while (i < fdm->region_cnt) {
|
while (i < be16_to_cpu(fdm->region_cnt)) {
|
||||||
pr_warn("\t[%03d] base: 0x%llx, size: 0x%llx\n",
|
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++;
|
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_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);
|
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)
|
static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm)
|
||||||
{
|
{
|
||||||
fdm->version = OPAL_FADUMP_VERSION;
|
fdm->version = OPAL_FADUMP_VERSION;
|
||||||
fdm->region_cnt = 0;
|
fdm->region_cnt = cpu_to_be16(0);
|
||||||
fdm->registered_regions = 0;
|
fdm->registered_regions = cpu_to_be16(0);
|
||||||
fdm->fadumphdr_addr = 0;
|
fdm->fadumphdr_addr = cpu_to_be64(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
|
static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
|
||||||
{
|
{
|
||||||
u64 addr = fadump_conf->reserve_dump_area_start;
|
u64 addr = fadump_conf->reserve_dump_area_start;
|
||||||
|
u16 reg_cnt;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
opal_fdm = __va(fadump_conf->kernel_metadata);
|
opal_fdm = __va(fadump_conf->kernel_metadata);
|
||||||
opal_fadump_init_metadata(opal_fdm);
|
opal_fadump_init_metadata(opal_fdm);
|
||||||
|
|
||||||
/* Boot memory regions */
|
/* Boot memory regions */
|
||||||
|
reg_cnt = be16_to_cpu(opal_fdm->region_cnt);
|
||||||
for (i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
|
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].src = cpu_to_be64(fadump_conf->boot_mem_addr[i]);
|
||||||
opal_fdm->rgn[i].dest = addr;
|
opal_fdm->rgn[i].dest = cpu_to_be64(addr);
|
||||||
opal_fdm->rgn[i].size = fadump_conf->boot_mem_sz[i];
|
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];
|
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.
|
* Kernel metadata is passed to f/w and retrieved in capture kerenl.
|
||||||
* So, use it to save fadump header address instead of calculating it.
|
* So, use it to save fadump header address instead of calculating it.
|
||||||
*/
|
*/
|
||||||
opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest +
|
opal_fdm->fadumphdr_addr = cpu_to_be64(be64_to_cpu(opal_fdm->rgn[0].dest) +
|
||||||
fadump_conf->boot_memory_size);
|
fadump_conf->boot_memory_size);
|
||||||
|
|
||||||
opal_fadump_update_config(fadump_conf, opal_fdm);
|
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)
|
static int opal_fadump_register(struct fw_dump *fadump_conf)
|
||||||
{
|
{
|
||||||
s64 rc = OPAL_PARAMETER;
|
s64 rc = OPAL_PARAMETER;
|
||||||
|
u16 registered_regs;
|
||||||
int i, err = -EIO;
|
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,
|
rc = opal_mpipl_update(OPAL_MPIPL_ADD_RANGE,
|
||||||
opal_fdm->rgn[i].src,
|
be64_to_cpu(opal_fdm->rgn[i].src),
|
||||||
opal_fdm->rgn[i].dest,
|
be64_to_cpu(opal_fdm->rgn[i].dest),
|
||||||
opal_fdm->rgn[i].size);
|
be64_to_cpu(opal_fdm->rgn[i].size));
|
||||||
if (rc != OPAL_SUCCESS)
|
if (rc != OPAL_SUCCESS)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
opal_fdm->registered_regions++;
|
registered_regs++;
|
||||||
}
|
}
|
||||||
|
opal_fdm->registered_regions = cpu_to_be16(registered_regs);
|
||||||
|
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case OPAL_SUCCESS:
|
case OPAL_SUCCESS:
|
||||||
|
@ -291,7 +298,8 @@ static int opal_fadump_register(struct fw_dump *fadump_conf)
|
||||||
case OPAL_RESOURCE:
|
case OPAL_RESOURCE:
|
||||||
/* If MAX regions limit in f/w is hit, warn and proceed. */
|
/* 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",
|
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;
|
fadump_conf->dump_registered = 1;
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
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
|
* If some regions were registered before OPAL_MPIPL_ADD_RANGE
|
||||||
* OPAL call failed, unregister all regions.
|
* 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);
|
opal_fadump_unregister(fadump_conf);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -328,7 +336,7 @@ static int opal_fadump_unregister(struct fw_dump *fadump_conf)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
opal_fdm->registered_regions = 0;
|
opal_fdm->registered_regions = cpu_to_be16(0);
|
||||||
fadump_conf->dump_registered = 0;
|
fadump_conf->dump_registered = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -563,19 +571,20 @@ static void opal_fadump_region_show(struct fw_dump *fadump_conf,
|
||||||
else
|
else
|
||||||
fdm_ptr = opal_fdm;
|
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
|
* Only regions that are registered for MPIPL
|
||||||
* would have dump data.
|
* would have dump data.
|
||||||
*/
|
*/
|
||||||
if ((fadump_conf->dump_active) &&
|
if ((fadump_conf->dump_active) &&
|
||||||
(i < fdm_ptr->registered_regions))
|
(i < be16_to_cpu(fdm_ptr->registered_regions)))
|
||||||
dumped_bytes = fdm_ptr->rgn[i].size;
|
dumped_bytes = be64_to_cpu(fdm_ptr->rgn[i].size);
|
||||||
|
|
||||||
seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
|
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",
|
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. */
|
/* 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;
|
const __be32 *prop;
|
||||||
unsigned long dn;
|
unsigned long dn;
|
||||||
|
__be64 be_addr;
|
||||||
u64 addr = 0;
|
u64 addr = 0;
|
||||||
int i, len;
|
int i, len;
|
||||||
s64 ret;
|
s64 ret;
|
||||||
|
@ -680,13 +690,13 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
|
||||||
if (!prop)
|
if (!prop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr);
|
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &be_addr);
|
||||||
if ((ret != OPAL_SUCCESS) || !addr) {
|
if ((ret != OPAL_SUCCESS) || !be_addr) {
|
||||||
pr_err("Failed to get Kernel metadata (%lld)\n", ret);
|
pr_err("Failed to get Kernel metadata (%lld)\n", ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = be64_to_cpu(addr);
|
addr = be64_to_cpu(be_addr);
|
||||||
pr_debug("Kernel metadata addr: %llx\n", addr);
|
pr_debug("Kernel metadata addr: %llx\n", addr);
|
||||||
|
|
||||||
opal_fdm_active = __va(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 */
|
/* 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;
|
opal_fdm_active = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &addr);
|
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &be_addr);
|
||||||
if (addr) {
|
if (be_addr) {
|
||||||
addr = be64_to_cpu(addr);
|
addr = be64_to_cpu(be_addr);
|
||||||
pr_debug("CPU metadata addr: %llx\n", addr);
|
pr_debug("CPU metadata addr: %llx\n", addr);
|
||||||
opal_cpu_metadata = __va(addr);
|
opal_cpu_metadata = __va(addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,14 @@
|
||||||
* OPAL FADump kernel metadata
|
* OPAL FADump kernel metadata
|
||||||
*
|
*
|
||||||
* The address of this structure will be registered with f/w for retrieving
|
* 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 {
|
struct opal_fadump_mem_struct {
|
||||||
u8 version;
|
u8 version;
|
||||||
u8 reserved[3];
|
u8 reserved[3];
|
||||||
u16 region_cnt; /* number of regions */
|
__be16 region_cnt; /* number of regions */
|
||||||
u16 registered_regions; /* Regions registered for MPIPL */
|
__be16 registered_regions; /* Regions registered for MPIPL */
|
||||||
u64 fadumphdr_addr;
|
__be64 fadumphdr_addr;
|
||||||
struct opal_mpipl_region rgn[FADUMP_MAX_MEM_REGS];
|
struct opal_mpipl_region rgn[FADUMP_MAX_MEM_REGS];
|
||||||
} __packed;
|
} __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) {
|
for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) {
|
||||||
reg_entry = (struct hdat_fadump_reg_entry *)bufp;
|
reg_entry = (struct hdat_fadump_reg_entry *)bufp;
|
||||||
val = (cpu_endian ? be64_to_cpu(reg_entry->reg_val) :
|
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,
|
opal_fadump_set_regval_regnum(regs,
|
||||||
be32_to_cpu(reg_entry->reg_type),
|
be32_to_cpu(reg_entry->reg_type),
|
||||||
be32_to_cpu(reg_entry->reg_num),
|
be32_to_cpu(reg_entry->reg_num),
|
||||||
|
|
Загрузка…
Ссылка в новой задаче