clear-pkgs-linux-iot-lts2018/0349-ASoC-Intel-Skylake-Sup...

270 lines
8.3 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 9d2be10e484c..c08d87821c9f 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 14802ab7ea20..cfdf2ce3733b 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 d6866bc15469..ad437be40334 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 7288893ce61a..8f4e3074de17 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 8dbe73ee3d59..b3a15ed76122 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
--
https://clearlinux.org