clear-pkgs-linux-iot-lts2018/0404-ASoC-Intel-Skylake-Rea...

224 lines
7.9 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pardha Saradhi K <pardha.saradhi.kesapragada@intel.com>
Date: Thu, 8 Mar 2018 00:35:50 +0530
Subject: [PATCH] ASoC: Intel: Skylake: Read extended crash dump info from DSP
When DSP encounters an exception, besides providing basic info
about the crash in the FW REGS section, an extended info is
written in the log buffer, on a per core basis. This information
is usually related to the module's stack that helps in
identifying the reason for the Exception to occur.
Audio driver needs to read this info from the log buffers and
append it to the crash dump file.
Change-Id: I0ae67e510f7627317b10445cdf3c2c927beaca4f
Signed-off-by: Pardha Saradhi K <pardha.saradhi.kesapragada@intel.com>
Reviewed-on:
Reviewed-by: Shaik, ShahinaX <shahinax.shaik@intel.com>
Reviewed-by: Shaik, Kareem M <kareem.m.shaik@intel.com>
Reviewed-by: Sinha, Mohit <mohit.sinha@intel.com>
Reviewed-by: Kp, Jeeja <jeeja.kp@intel.com>
Tested-by: Madiwalar, MadiwalappaX <madiwalappax.madiwalar@intel.com>
---
sound/soc/intel/skylake/skl-sst-ipc.c | 9 ++-
sound/soc/intel/skylake/skl-sst-ipc.h | 2 +-
sound/soc/intel/skylake/skl-sst-utils.c | 102 +++++++++++++++++++++++-
3 files changed, 106 insertions(+), 7 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 13917d54d..e36160b11 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -202,6 +202,9 @@
#define MOD_DATA_OFFSET 12
#define SET_LARGE_CFG_FW_CONFIG 7
+#define DSP_EXCEP_CORE_MASK 0x3
+#define DSP_EXCEP_STACK_SIZE_SHIFT 2
+
enum skl_ipc_msg_target {
IPC_FW_GEN_MSG = 0,
IPC_MOD_MSG = 1
@@ -494,9 +497,11 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
skl->miscbdcg_disabled = true;
break;
case IPC_GLB_NOTIFY_EXCEPTION_CAUGHT:
- dev_err(ipc->dev, "*****Exception Detected **********\n");
+ dev_err(ipc->dev, "*****Exception Detected on core id: %d \n",(header.extension & DSP_EXCEP_CORE_MASK));
+ dev_err(ipc->dev, "Exception Stack size is %d\n", (header.extension >> DSP_EXCEP_STACK_SIZE_SHIFT));
/* hexdump of the fw core exception record reg */
- ret = skl_dsp_crash_dump_read(skl);
+ ret = skl_dsp_crash_dump_read(skl,
+ (header.extension >> DSP_EXCEP_STACK_SIZE_SHIFT));
if (ret < 0) {
dev_err(ipc->dev,
"dsp crash dump read fail:%d\n", ret);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index 4b3c7e283..36e699a17 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -470,7 +470,7 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size);
int skl_notify_tplg_change(struct skl_sst *ctx, int type);
-int skl_dsp_crash_dump_read(struct skl_sst *ctx);
+int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size);
void skl_ipc_set_fw_cfg(struct sst_generic_ipc *ipc, u8 instance_id,
u16 module_id, u32 *data);
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 8f4056ebf..a420d702f 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -32,6 +32,7 @@
#define CRASH_DUMP_VERSION 0x1
/* FW Extended Manifest Header id = $AE1 */
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
+#define MAX_DSP_EXCEPTION_STACK_SIZE (64*1024)
#define UUID_ATTR_RO(_name) \
struct uuid_attribute uuid_attr_##_name = __ATTR_RO(_name)
@@ -308,6 +309,73 @@ void skl_reset_instance_id(struct skl_sst *ctx)
}
EXPORT_SYMBOL_GPL(skl_reset_instance_id);
+/* This function checks tha available data on the core id
+ * passed as an argument and returns the bytes available
+ */
+static int skl_check_ext_excep_data_avail(struct skl_sst *ctx, int idx)
+{
+ u32 size = ctx->dsp->trace_wind.size/ctx->dsp->trace_wind.nr_dsp;
+ u8 *base = (u8 __force*)ctx->dsp->trace_wind.addr;
+ u32 read, write;
+ u32 *ptr;
+
+ /* move to the source dsp tracing window */
+ base += (idx * size);
+ ptr = (u32 *) base;
+ read = ptr[0];
+ write = ptr[1];
+
+ if (write == read)
+ return 0;
+ else if (write > read)
+ return (write - read);
+ else
+ return (size - 8 - read + write);
+}
+
+/* Function to read the extended DSP crash information from the
+ * log buffer memory window, on per core basis.
+ * Data is read into the buffer passed as *ext_core_dump.
+ * number of bytes read is updated in the sz_ext_dump
+ */
+static void skl_read_ext_exception_data(struct skl_sst *ctx, int idx,
+ void *ext_core_dump, int *sz_ext_dump)
+{
+ u32 size = ctx->dsp->trace_wind.size/ctx->dsp->trace_wind.nr_dsp;
+ u8 *base = (u8 __force*)ctx->dsp->trace_wind.addr;
+ u32 read, write;
+ int offset = *sz_ext_dump;
+ u32 *ptr;
+
+ /* move to the current core's tracing window */
+ base += (idx * size);
+ ptr = (u32 *) base;
+ read = ptr[0];
+ write = ptr[1];
+ if (write > read) {
+ memcpy_fromio((ext_core_dump + offset),
+ (const void __iomem *)(base + 8 + read),
+ (write - read));
+ *sz_ext_dump = offset + write - read;
+ /* advance read pointer */
+ ptr[0] += write - read;
+ } else {
+ /* wrap around condition - copy till the end */
+ memcpy_fromio((ext_core_dump + offset),
+ (const void __iomem *)(base + 8 + read),
+ (size - 8 - read));
+ *sz_ext_dump = offset + size - 8 - read;
+ offset = *sz_ext_dump;
+
+ /* copy from the beginnning */
+ memcpy_fromio((ext_core_dump + offset),
+ (const void __iomem *) (base + 8), write);
+ *sz_ext_dump = offset + write;
+ /* update the read pointer */
+ ptr[0] = write;
+ }
+}
+
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;
@@ -320,6 +388,7 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
struct adsp_type0_crash_data *type0_data;
struct adsp_type1_crash_data *type1_data;
struct adsp_type2_crash_data *type2_data;
+ struct sst_dsp *sst = ctx->dsp;
if (list_empty(&ctx->uuid_list))
dev_info(ctx->dev, "Module list is empty\n");
@@ -328,6 +397,21 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
num_mod++;
}
+ if(stack_size)
+ ext_core_dump = vzalloc(stack_size);
+ else
+ ext_core_dump = vzalloc(MAX_DSP_EXCEPTION_STACK_SIZE);
+ if (!ext_core_dump) {
+ dev_err(ctx->dsp->dev, "failed to allocate memory for FW Stack\n");
+ return -ENOMEM;
+ }
+ for (idx = 0; idx < sst->trace_wind.nr_dsp; idx++) {
+ while(skl_check_ext_excep_data_avail(ctx, idx)) {
+ skl_read_ext_exception_data(ctx, idx,
+ ext_core_dump, &sz_ext_dump);
+ }
+ }
+
/* Length representing in DWORD */
length0 = sizeof(*type0_data) / sizeof(u32);
length1 = (num_mod * sizeof(*type1_data)) / sizeof(u32);
@@ -336,11 +420,14 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
/* 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);
+ sizeof(*type2_data) + sz_ext_dump;
- coredump = vzalloc(size_core_dump);
- if (!coredump)
+ coredump = vzalloc(size_core_dump + sz_ext_dump);
+ if (!coredump){
+ dev_err(ctx->dsp->dev, "failed to allocate memory \n");
+ vfree(ext_core_dump);
return -ENOMEM;
+ }
offset = coredump;
@@ -382,8 +469,15 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
memcpy_fromio(type2_data->fwreg, (const void __iomem *)fw_reg_addr,
sizeof(*type2_data));
+ if (sz_ext_dump) {
+ offset = coredump + size_core_dump;
+ memcpy(offset, ext_core_dump, sz_ext_dump);
+ }
+
+ vfree(ext_core_dump);
+
dev_coredumpv(ctx->dsp->dev, coredump,
- size_core_dump, GFP_KERNEL);
+ size_core_dump + sz_ext_dump, GFP_KERNEL);
return 0;
}
--
https://clearlinux.org