// 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 #include #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); }