diff options
author | Mark Brown <broonie@kernel.org> | 2023-09-19 18:22:11 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2023-09-19 18:22:11 +0100 |
commit | 03db12ef1cbc3ad86aaaf3a5e9203a936dba52b8 (patch) | |
tree | 3cfbde5f60fc2e9fcf259f59bae838333c3ca71b /sound/soc/sof/intel/telemetry.c | |
parent | 16bb22098f0a44fed8192c4b16fede95876fdc19 (diff) | |
parent | c1c48fd6bbe788458e3685fea74bdb3cb148ff93 (diff) |
ASoC: SOF: ipc4/Intel: Support for firmware exception
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:
When a firmware crashes it creats a panic information into a telemetry
slot. The panic format is defined by Zephyr, includes stack and
additional information to help to identify the reason for the crash.
Part of the firmware exception handling the firmware also sends an
EXCEPTION_CAUGHT notification.
This series implements the kernel side handling of the exception: print
information into the kernel log export the whole telemetry slot to user
space for tools extract additional information from the panic dump.
Diffstat (limited to 'sound/soc/sof/intel/telemetry.c')
-rw-r--r-- | sound/soc/sof/intel/telemetry.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/sound/soc/sof/intel/telemetry.c b/sound/soc/sof/intel/telemetry.c new file mode 100644 index 000000000000..1a3b5c28a6f0 --- /dev/null +++ b/sound/soc/sof/intel/telemetry.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. + +/* telemetry data queried from debug window */ + +#include <sound/sof/ipc4/header.h> +#include <sound/sof/xtensa.h> +#include "../ipc4-priv.h" +#include "../sof-priv.h" +#include "hda.h" +#include "telemetry.h" + +void sof_ipc4_intel_dump_telemetry_state(struct snd_sof_dev *sdev, u32 flags) +{ + static const char invalid_slot_msg[] = "Core dump is not available due to"; + struct sof_ipc4_telemetry_slot_data *telemetry_data; + struct sof_ipc_dsp_oops_xtensa *xoops; + struct xtensa_arch_block *block; + u32 slot_offset; + char *level; + + level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; + + slot_offset = sof_ipc4_find_debug_slot_offset_by_type(sdev, SOF_IPC4_DEBUG_SLOT_TELEMETRY); + if (!slot_offset) + return; + + telemetry_data = kmalloc(sizeof(*telemetry_data), GFP_KERNEL); + if (!telemetry_data) + return; + sof_mailbox_read(sdev, slot_offset, telemetry_data, sizeof(*telemetry_data)); + if (telemetry_data->separator != XTENSA_CORE_DUMP_SEPARATOR) { + dev_err(sdev->dev, "%s invalid separator %#x\n", invalid_slot_msg, + telemetry_data->separator); + goto free_telemetry_data; + } + + block = kmalloc(sizeof(*block), GFP_KERNEL); + if (!block) + goto free_telemetry_data; + + sof_mailbox_read(sdev, slot_offset + sizeof(*telemetry_data), block, sizeof(*block)); + if (block->soc != XTENSA_SOC_INTEL_ADSP) { + dev_err(sdev->dev, "%s invalid SOC %d\n", invalid_slot_msg, block->soc); + goto free_block; + } + + if (telemetry_data->hdr.id[0] != COREDUMP_HDR_ID0 || + telemetry_data->hdr.id[1] != COREDUMP_HDR_ID1 || + telemetry_data->arch_hdr.id != COREDUMP_ARCH_HDR_ID) { + dev_err(sdev->dev, "%s invalid coredump header %c%c, arch hdr %c\n", + invalid_slot_msg, telemetry_data->hdr.id[0], + telemetry_data->hdr.id[1], + telemetry_data->arch_hdr.id); + goto free_block; + } + + switch (block->toolchain) { + case XTENSA_TOOL_CHAIN_ZEPHYR: + dev_printk(level, sdev->dev, "FW is built with Zephyr toolchain\n"); + break; + case XTENSA_TOOL_CHAIN_XCC: + dev_printk(level, sdev->dev, "FW is built with XCC toolchain\n"); + break; + default: + dev_printk(level, sdev->dev, "Unknown toolchain is used\n"); + break; + } + + xoops = kzalloc(struct_size(xoops, ar, XTENSA_CORE_AR_REGS_COUNT), GFP_KERNEL); + if (!xoops) + goto free_block; + + xoops->exccause = block->exccause; + xoops->excvaddr = block->excvaddr; + xoops->epc1 = block->pc; + xoops->ps = block->ps; + xoops->sar = block->sar; + + xoops->plat_hdr.numaregs = XTENSA_CORE_AR_REGS_COUNT; + memcpy((void *)xoops->ar, block->ar, XTENSA_CORE_AR_REGS_COUNT * sizeof(u32)); + + sof_oops(sdev, level, xoops); + sof_stack(sdev, level, xoops, NULL, 0); + + kfree(xoops); +free_block: + kfree(block); +free_telemetry_data: + kfree(telemetry_data); +} |