224 lines
7.8 KiB
Diff
224 lines
7.8 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 13917d5..e36160b 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 4b3c7e2..36e699a 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 8f4056e..a420d70 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
|
|
|