235 lines
8.2 KiB
Diff
235 lines
8.2 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: "Lulko, KamilX" <kamilx.lulko@intel.com>
|
|
Date: Fri, 22 Mar 2019 12:33:02 +0100
|
|
Subject: [PATCH] ASoC: Intel: read DSP stack dump from specific core only
|
|
|
|
DSP exception notification states explicitly which core
|
|
the exception is from. Only this core will print the stack
|
|
into the memory window so there is no point in trying to read
|
|
it from all cores. Additionally add simple boundary check for
|
|
read and write pointers - these could be overwritten by DSP
|
|
and cause out of bounds offset access.
|
|
|
|
Change-Id: I1bf6caaf16a448ce7cd6c93229ffe19aa99d55cd
|
|
Tracked-On: OAM-79127
|
|
Signed-off-by: Lulko, KamilX <kamilx.lulko@intel.com>
|
|
---
|
|
sound/soc/intel/skylake/skl-sst-ipc.c | 1 +
|
|
sound/soc/intel/skylake/skl-sst-ipc.h | 2 +-
|
|
sound/soc/intel/skylake/skl-sst-utils.c | 121 +++++++++++-------------
|
|
3 files changed, 58 insertions(+), 66 deletions(-)
|
|
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
|
|
index af84aab4689a..891d6ca8325b 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
|
|
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
|
|
@@ -656,6 +656,7 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
|
|
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,
|
|
+ (header.extension & DSP_EXCEP_CORE_MASK),
|
|
(header.extension >> DSP_EXCEP_STACK_SIZE_SHIFT));
|
|
if (ret < 0) {
|
|
dev_err(ipc->dev,
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
index d28913476d3b..abddf44562b3 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
@@ -481,7 +481,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 stack_size);
|
|
+int skl_dsp_crash_dump_read(struct skl_sst *ctx, int idx, 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 344892e70d86..856a6e86be52 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-utils.c
|
|
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
|
|
@@ -35,6 +35,9 @@
|
|
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
|
|
#define MAX_DSP_EXCEPTION_STACK_SIZE (64*1024)
|
|
|
|
+#define EXCEPTION_RECORD_OFFSET(core_count, core_idx) \
|
|
+ (0x1000 - ((core_count - core_idx) * 0x158) + 4)
|
|
+
|
|
/* FW adds headers and trailing patters to extended crash data */
|
|
#define EXTRA_BYTES 256
|
|
|
|
@@ -313,42 +316,20 @@ 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 = readl(ptr);
|
|
- write = readl(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)
|
|
+static int skl_read_ext_exception_data(struct skl_sst *ctx, int idx,
|
|
+ void *ext_core_dump, int ext_core_dump_sz, 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;
|
|
+ int count;
|
|
u32 *ptr;
|
|
|
|
/* move to the current core's tracing window */
|
|
@@ -359,44 +340,49 @@ static void skl_read_ext_exception_data(struct skl_sst *ctx, int idx,
|
|
|
|
/* in case of read = write, just return */
|
|
if (read == write)
|
|
- return;
|
|
+ return 0;
|
|
+ /* check r/w pointers sanity */
|
|
+ if ((read + 8) >= size || (write + 8) >= size)
|
|
+ return -EINVAL;
|
|
|
|
- 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 */
|
|
- } 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 */
|
|
- }
|
|
- writel(write, ptr);
|
|
+ if (write > read)
|
|
+ count = write - read;
|
|
+ else
|
|
+ count = size - 8 - read;
|
|
+
|
|
+ if (offset + count > ext_core_dump_sz)
|
|
+ return -EINVAL;
|
|
+
|
|
+ memcpy_fromio((ext_core_dump + offset),
|
|
+ (const void __iomem *) (base + 8 + read), count);
|
|
+
|
|
+ *sz_ext_dump = offset + count;
|
|
+ read += count;
|
|
+ if (read >= size - 8)
|
|
+ read = 0;
|
|
+ writel(read, ptr);
|
|
+ return 0;
|
|
}
|
|
|
|
-int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
|
|
+int skl_dsp_crash_dump_read(struct skl_sst *ctx, int idx, int stack_size)
|
|
{
|
|
- int num_mod = 0, size_core_dump, sz_ext_dump = 0, idx = 0;
|
|
+ int num_mod = 0, size_core_dump, sz_ext_dump = 0;
|
|
struct uuid_module *module, *module1;
|
|
void *coredump, *ext_core_dump;
|
|
+ unsigned long ext_core_dump_sz;
|
|
void *fw_reg_addr, *offset;
|
|
struct pci_dev *pci = to_pci_dev(ctx->dsp->dev);
|
|
+ u32 stackdump_complete = 0;
|
|
u16 length0, length1, length2, length3;
|
|
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;
|
|
struct sst_dsp *sst = ctx->dsp;
|
|
+ unsigned long timeout;
|
|
+
|
|
+ if (idx < 0 || idx >= ctx->cores.count)
|
|
+ return -EINVAL;
|
|
|
|
if (list_empty(&ctx->uuid_list))
|
|
dev_info(ctx->dev, "Module list is empty\n");
|
|
@@ -406,20 +392,27 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
|
|
}
|
|
|
|
if(stack_size)
|
|
- ext_core_dump = vzalloc(stack_size + EXTRA_BYTES);
|
|
+ ext_core_dump_sz = stack_size + EXTRA_BYTES;
|
|
else
|
|
- ext_core_dump = vzalloc(MAX_DSP_EXCEPTION_STACK_SIZE + EXTRA_BYTES);
|
|
- 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++) {
|
|
- if(skl_check_ext_excep_data_avail(ctx, idx) != 0) {
|
|
- while(sz_ext_dump < stack_size) {
|
|
- skl_read_ext_exception_data(ctx, idx,
|
|
- ext_core_dump, &sz_ext_dump);
|
|
- }
|
|
- }
|
|
+ ext_core_dump_sz = MAX_DSP_EXCEPTION_STACK_SIZE + EXTRA_BYTES;
|
|
+ ext_core_dump = vzalloc(ext_core_dump_sz);
|
|
+ if (!ext_core_dump) {
|
|
+ dev_err(ctx->dsp->dev, "failed to allocate memory for FW Stack\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ fw_reg_addr = (void __force *)(ctx->dsp->mailbox.in_base -
|
|
+ ctx->dsp->addr.w0_stat_sz);
|
|
+
|
|
+ timeout = jiffies + msecs_to_jiffies(100);
|
|
+ while (!stackdump_complete) {
|
|
+ stackdump_complete = readl(fw_reg_addr +
|
|
+ EXCEPTION_RECORD_OFFSET(ctx->cores.count, idx));
|
|
+ if (skl_read_ext_exception_data(ctx, idx, ext_core_dump,
|
|
+ ext_core_dump_sz, &sz_ext_dump) < 0)
|
|
+ break;
|
|
+ if (time_after(jiffies, timeout))
|
|
+ break;
|
|
}
|
|
|
|
/* Length representing in DWORD */
|
|
@@ -475,8 +468,6 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
|
|
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));
|
|
offset += sizeof(*type2_data);
|
|
--
|
|
https://clearlinux.org
|
|
|