xref: /linux/sound/soc/sof/intel/telemetry.c (revision 33e02dc69afbd8f1b85a51d74d72f139ba4ca623)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2023 Intel Corporation
7 
8 /* telemetry data queried from debug window */
9 
10 #include <sound/sof/ipc4/header.h>
11 #include <sound/sof/xtensa.h>
12 #include "../ipc4-priv.h"
13 #include "../sof-priv.h"
14 #include "hda.h"
15 #include "telemetry.h"
16 
sof_ipc4_intel_dump_telemetry_state(struct snd_sof_dev * sdev,u32 flags)17 void sof_ipc4_intel_dump_telemetry_state(struct snd_sof_dev *sdev, u32 flags)
18 {
19 	static const char invalid_slot_msg[] = "Core dump is not available due to";
20 	struct sof_ipc4_telemetry_slot_data *telemetry_data;
21 	struct sof_ipc_dsp_oops_xtensa *xoops;
22 	struct xtensa_arch_block *block;
23 	u32 slot_offset;
24 	char *level;
25 
26 	level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
27 
28 	slot_offset = sof_ipc4_find_debug_slot_offset_by_type(sdev, SOF_IPC4_DEBUG_SLOT_TELEMETRY);
29 	if (!slot_offset)
30 		return;
31 
32 	telemetry_data = kmalloc(sizeof(*telemetry_data), GFP_KERNEL);
33 	if (!telemetry_data)
34 		return;
35 	sof_mailbox_read(sdev, slot_offset, telemetry_data, sizeof(*telemetry_data));
36 	if (telemetry_data->separator != XTENSA_CORE_DUMP_SEPARATOR) {
37 		dev_err(sdev->dev, "%s invalid separator %#x\n", invalid_slot_msg,
38 			telemetry_data->separator);
39 		goto free_telemetry_data;
40 	}
41 
42 	block = kmalloc(sizeof(*block), GFP_KERNEL);
43 	if (!block)
44 		goto free_telemetry_data;
45 
46 	sof_mailbox_read(sdev, slot_offset + sizeof(*telemetry_data), block, sizeof(*block));
47 	if (block->soc != XTENSA_SOC_INTEL_ADSP) {
48 		dev_err(sdev->dev, "%s invalid SOC %d\n", invalid_slot_msg, block->soc);
49 		goto free_block;
50 	}
51 
52 	if (telemetry_data->hdr.id[0] != COREDUMP_HDR_ID0 ||
53 	    telemetry_data->hdr.id[1] != COREDUMP_HDR_ID1 ||
54 	    telemetry_data->arch_hdr.id != COREDUMP_ARCH_HDR_ID) {
55 		dev_err(sdev->dev, "%s invalid coredump header %c%c, arch hdr %c\n",
56 			invalid_slot_msg, telemetry_data->hdr.id[0],
57 			telemetry_data->hdr.id[1],
58 			telemetry_data->arch_hdr.id);
59 		goto free_block;
60 	}
61 
62 	switch (block->toolchain) {
63 	case XTENSA_TOOL_CHAIN_ZEPHYR:
64 		dev_printk(level, sdev->dev, "FW is built with Zephyr toolchain\n");
65 		break;
66 	case XTENSA_TOOL_CHAIN_XCC:
67 		dev_printk(level, sdev->dev, "FW is built with XCC toolchain\n");
68 		break;
69 	default:
70 		dev_printk(level, sdev->dev, "Unknown toolchain is used\n");
71 		break;
72 	}
73 
74 	xoops = kzalloc(struct_size(xoops, ar, XTENSA_CORE_AR_REGS_COUNT), GFP_KERNEL);
75 	if (!xoops)
76 		goto free_block;
77 
78 	xoops->exccause = block->exccause;
79 	xoops->excvaddr = block->excvaddr;
80 	xoops->epc1 = block->pc;
81 	xoops->ps = block->ps;
82 	xoops->sar = block->sar;
83 
84 	xoops->plat_hdr.numaregs = XTENSA_CORE_AR_REGS_COUNT;
85 	memcpy((void *)xoops->ar, block->ar, XTENSA_CORE_AR_REGS_COUNT * sizeof(u32));
86 
87 	sof_oops(sdev, level, xoops);
88 	sof_stack(sdev, level, xoops, NULL, 0);
89 
90 	kfree(xoops);
91 free_block:
92 	kfree(block);
93 free_telemetry_data:
94 	kfree(telemetry_data);
95 }
96 EXPORT_SYMBOL_NS(sof_ipc4_intel_dump_telemetry_state, SND_SOC_SOF_INTEL_HDA_COMMON);
97