| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 |
|
| 8 |
|
| 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 |
|
| 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_obj(*telemetry_data);
|
| 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_obj(*block);
|
| 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_flex(*xoops, ar, XTENSA_CORE_AR_REGS_COUNT);
|
| 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");
|