270 lines
8.2 KiB
Diff
270 lines
8.2 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Mousumi Jana <mousumix.jana@intel.com>
|
|
Date: Tue, 4 Jul 2017 18:39:18 +0530
|
|
Subject: [PATCH] ASoC: Intel: Skylake: Support for DSP exception record dump
|
|
|
|
In the cases where the DSP encounters an exception
|
|
during its execution, the record is stored in the FW
|
|
registers window, aligned towards the end. This data
|
|
is read by the driver and is passed to the user space
|
|
using the linux coredump framework
|
|
The record contains data on a per core basis is dumped to
|
|
the userspace in scenario -
|
|
when DSP sends an EXCEPTION_CAUGHT IPC
|
|
|
|
Change-Id: I1d2ac3bca545db7fe5d13c1a0d6ab850da4d7984
|
|
Signed-off-by: Mousumi Jana <mousumix.jana@intel.com>
|
|
Signed-off-by: Giribabu Gogineni <giribabux.gogineni@intel.com>
|
|
---
|
|
sound/soc/intel/Kconfig | 1 +
|
|
sound/soc/intel/skylake/skl-sst-ipc.c | 17 +++-
|
|
sound/soc/intel/skylake/skl-sst-ipc.h | 13 ---
|
|
sound/soc/intel/skylake/skl-sst-utils.c | 114 +++++++++++++++++++++++-
|
|
sound/soc/intel/skylake/skl-topology.h | 1 +
|
|
5 files changed, 131 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
|
|
index 9d2be10..c08d878 100644
|
|
--- a/sound/soc/intel/Kconfig
|
|
+++ b/sound/soc/intel/Kconfig
|
|
@@ -115,6 +115,7 @@ config SND_SOC_INTEL_SKYLAKE
|
|
select SND_SOC_ACPI_INTEL_MATCH
|
|
select SDW
|
|
select SDW_CNL
|
|
+ select WANT_DEV_COREDUMP
|
|
help
|
|
If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
|
|
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
|
|
index 14802ab..cfdf2ce 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
|
|
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
|
|
@@ -21,6 +21,7 @@
|
|
#include "skl-sst-ipc.h"
|
|
#include "skl-fwlog.h"
|
|
#include "sound/hdaudio_ext.h"
|
|
+#include "skl-topology.h"
|
|
|
|
#define IPC_IXC_STATUS_BITS 24
|
|
|
|
@@ -271,7 +272,9 @@ enum skl_ipc_notification_type {
|
|
IPC_GLB_NOTIFY_RESOURCE_EVENT = 5,
|
|
IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6,
|
|
IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7,
|
|
- IPC_GLB_NOTIFY_FW_READY = 8
|
|
+ IPC_GLB_NOTIFY_FW_READY = 8,
|
|
+ IPC_GLB_NOTIFY_FW_AUD_CLASS_RESULT = 9,
|
|
+ IPC_GLB_NOTIFY_EXCEPTION_CAUGHT = 10
|
|
};
|
|
|
|
/* Module Message Types */
|
|
@@ -406,6 +409,7 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
|
|
struct skl_ipc_header header)
|
|
{
|
|
struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
|
|
+ int ret;
|
|
|
|
if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
|
|
switch (IPC_GLB_NOTIFY_TYPE(header.primary)) {
|
|
@@ -440,6 +444,17 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
|
|
skl->enable_miscbdcge(ipc->dev, false);
|
|
skl->miscbdcg_disabled = true;
|
|
break;
|
|
+ case IPC_GLB_NOTIFY_EXCEPTION_CAUGHT:
|
|
+ dev_err(ipc->dev, "*****Exception Detected **********\n");
|
|
+ /* hexdump of the fw core exception record reg */
|
|
+ ret = skl_dsp_crash_dump_read(skl);
|
|
+ if (ret < 0) {
|
|
+ dev_err(ipc->dev,
|
|
+ "dsp crash dump read fail:%d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ break;
|
|
+
|
|
|
|
default:
|
|
dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n",
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
index d6866bc..ad437be 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
@@ -375,19 +375,6 @@ struct sw_version {
|
|
u16 build;
|
|
} __packed;
|
|
|
|
-struct skl_dsp_core_dump {
|
|
- u16 type0;
|
|
- u16 length0;
|
|
- u32 crash_dump_ver;
|
|
- u16 bus_dev_id;
|
|
- u16 cavs_hw_version;
|
|
- struct fw_version fw_ver;
|
|
- struct sw_version sw_ver;
|
|
- u16 type2;
|
|
- u16 length2;
|
|
- u32 fwreg[FW_REG_SZ];
|
|
-} __packed;
|
|
-
|
|
struct skl_module_notify {
|
|
u32 unique_id;
|
|
u32 event_id;
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
|
|
index 7288893..8f4e307 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-utils.c
|
|
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
|
|
@@ -16,6 +16,8 @@
|
|
#include <linux/device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/uuid.h>
|
|
+#include <linux/devcoredump.h>
|
|
+#include <linux/pci.h>
|
|
#include "skl-sst-dsp.h"
|
|
#include "../common/sst-dsp.h"
|
|
#include "../common/sst-dsp-priv.h"
|
|
@@ -23,7 +25,11 @@
|
|
|
|
|
|
#define UUID_STR_SIZE 37
|
|
-
|
|
+#define TYPE0_EXCEPTION 0
|
|
+#define TYPE1_EXCEPTION 1
|
|
+#define TYPE2_EXCEPTION 2
|
|
+#define MAX_CRASH_DATA_TYPES 3
|
|
+#define CRASH_DUMP_VERSION 0x1
|
|
/* FW Extended Manifest Header id = $AE1 */
|
|
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
|
|
|
|
@@ -126,6 +132,31 @@ struct skl_ext_manifest_hdr {
|
|
u32 entries;
|
|
};
|
|
|
|
+struct adsp_crash_hdr {
|
|
+ u16 type;
|
|
+ u16 length;
|
|
+ char data[0];
|
|
+} __packed;
|
|
+
|
|
+struct adsp_type0_crash_data {
|
|
+ u32 crash_dump_ver;
|
|
+ u16 bus_dev_id;
|
|
+ u16 cavs_hw_version;
|
|
+ struct fw_version fw_ver;
|
|
+ struct sw_version sw_ver;
|
|
+} __packed;
|
|
+
|
|
+struct adsp_type1_crash_data {
|
|
+ u32 mod_uuid[4];
|
|
+ u32 hash[2];
|
|
+ u16 mod_id;
|
|
+ u16 rsvd;
|
|
+} __packed;
|
|
+
|
|
+struct adsp_type2_crash_data {
|
|
+ u32 fwreg[FW_REG_SZ];
|
|
+} __packed;
|
|
+
|
|
static int skl_get_pvtid_map(struct uuid_module *module, int instance_id)
|
|
{
|
|
int pvt_id;
|
|
@@ -261,6 +292,87 @@ int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id)
|
|
}
|
|
EXPORT_SYMBOL_GPL(skl_put_pvt_id);
|
|
|
|
+
|
|
+
|
|
+int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
|
|
+{
|
|
+ int num_mod = 0, size_core_dump, sz_ext_dump = 0, idx = 0;
|
|
+ struct uuid_module *module, *module1;
|
|
+ void *coredump, *ext_core_dump;
|
|
+ void *fw_reg_addr, *offset;
|
|
+ struct pci_dev *pci = to_pci_dev(ctx->dsp->dev);
|
|
+ u16 length0, length1, length2;
|
|
+ struct adsp_crash_hdr *crash_data_hdr;
|
|
+ struct adsp_type0_crash_data *type0_data;
|
|
+ struct adsp_type1_crash_data *type1_data;
|
|
+ struct adsp_type2_crash_data *type2_data;
|
|
+
|
|
+ if (list_empty(&ctx->uuid_list))
|
|
+ dev_info(ctx->dev, "Module list is empty\n");
|
|
+
|
|
+ list_for_each_entry(module1, &ctx->uuid_list, list) {
|
|
+ num_mod++;
|
|
+ }
|
|
+
|
|
+ /* Length representing in DWORD */
|
|
+ length0 = sizeof(*type0_data) / sizeof(u32);
|
|
+ length1 = (num_mod * sizeof(*type1_data)) / sizeof(u32);
|
|
+ length2 = sizeof(*type2_data) / sizeof(u32);
|
|
+
|
|
+ /* type1 data size is calculated based on number of modules */
|
|
+ size_core_dump = (MAX_CRASH_DATA_TYPES * sizeof(*crash_data_hdr)) +
|
|
+ sizeof(*type0_data) + (num_mod * sizeof(*type1_data)) +
|
|
+ sizeof(*type2_data);
|
|
+
|
|
+ coredump = vzalloc(size_core_dump);
|
|
+ if (!coredump)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ offset = coredump;
|
|
+
|
|
+ /* Fill type0 header and data */
|
|
+ crash_data_hdr = (struct adsp_crash_hdr *) offset;
|
|
+ crash_data_hdr->type = TYPE0_EXCEPTION;
|
|
+ crash_data_hdr->length = length0;
|
|
+ offset += sizeof(*crash_data_hdr);
|
|
+ type0_data = (struct adsp_type0_crash_data *) offset;
|
|
+ type0_data->crash_dump_ver = CRASH_DUMP_VERSION;
|
|
+ type0_data->bus_dev_id = pci->device;
|
|
+ offset += sizeof(*type0_data);
|
|
+
|
|
+ /* Fill type1 header and data */
|
|
+ crash_data_hdr = (struct adsp_crash_hdr *) offset;
|
|
+ crash_data_hdr->type = TYPE1_EXCEPTION;
|
|
+ crash_data_hdr->length = length1;
|
|
+ offset += sizeof(*crash_data_hdr);
|
|
+ type1_data = (struct adsp_type1_crash_data *) offset;
|
|
+ list_for_each_entry(module, &ctx->uuid_list, list) {
|
|
+ memcpy(type1_data->mod_uuid, &(module->uuid),
|
|
+ (sizeof(type1_data->mod_uuid)));
|
|
+ memcpy(type1_data->hash, &(module->hash),
|
|
+ (sizeof(type1_data->hash)));
|
|
+ memcpy(&type1_data->mod_id, &(module->id),
|
|
+ (sizeof(type1_data->mod_id)));
|
|
+ type1_data++;
|
|
+ }
|
|
+ offset += (num_mod * sizeof(*type1_data));
|
|
+
|
|
+ /* Fill type2 header and data */
|
|
+ crash_data_hdr = (struct adsp_crash_hdr *) offset;
|
|
+ crash_data_hdr->type = TYPE2_EXCEPTION;
|
|
+ crash_data_hdr->length = length2;
|
|
+ offset += sizeof(*crash_data_hdr);
|
|
+ type2_data = (struct adsp_type2_crash_data *) offset;
|
|
+ fw_reg_addr = (void __force*)(ctx->dsp->mailbox.in_base -
|
|
+ ctx->dsp->addr.w0_stat_sz);
|
|
+ memcpy_fromio(type2_data->fwreg, (const void __iomem *)fw_reg_addr,
|
|
+ sizeof(*type2_data));
|
|
+
|
|
+ dev_coredumpv(ctx->dsp->dev, coredump,
|
|
+ size_core_dump, GFP_KERNEL);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
* Parse the firmware binary to get the UUID, module id
|
|
* and loadable flags
|
|
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
|
|
index 8dbe73e..b3a15ed 100644
|
|
--- a/sound/soc/intel/skylake/skl-topology.h
|
|
+++ b/sound/soc/intel/skylake/skl-topology.h
|
|
@@ -613,4 +613,5 @@ int skl_tplg_dsp_log_set(struct snd_kcontrol *kcontrol,
|
|
|
|
int skl_dai_load(struct snd_soc_component *cmp,
|
|
struct snd_soc_dai_driver *pcm_dai);
|
|
+int skl_dsp_crash_dump_read(struct skl_sst *ctx);
|
|
#endif
|
|
--
|
|
2.21.0
|
|
|