clear-pkgs-linux-iot-lts2018/0219-ASoC-Intel-Skylake-Dri...

313 lines
9.1 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Panwar, Ashish" <ashish.panwar@intel.com>
Date: Wed, 20 Jan 2016 19:09:05 +0530
Subject: [PATCH] ASoC: Intel: Skylake: Driver ring buffer APIs for firmware
logging.
Data from trace window will be copied in this buffer and passed to
user space through compress stream APIs. Assuming a single reader
and single writer usecase, no locking has been implemented on this
buffer and hence we use kernel kfifo API for the ring buffer
implementation.
Change-Id: I4d9eb40abf3d4cc7fdb63ef7626bc49aaa378777
Signed-off-by: Panwar, Ashish <ashish.panwar@intel.com>
Reviewed-on:
Reviewed-by: Babu, Ramesh <ramesh.babu@intel.com>
Tested-by: Babu, Ramesh <ramesh.babu@intel.com>
Signed-off-by: Guneshwor Singh <guneshwor.o.singh@intel.com>
---
sound/soc/intel/common/sst-dsp-priv.h | 39 +++++-
sound/soc/intel/skylake/Makefile | 2 +-
sound/soc/intel/skylake/skl-fwlog.c | 168 ++++++++++++++++++++++++++
sound/soc/intel/skylake/skl-fwlog.h | 20 +++
4 files changed, 227 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/intel/skylake/skl-fwlog.c
create mode 100644 sound/soc/intel/skylake/skl-fwlog.h
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index acf06a4f5144..e7151a7e6bae 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -21,7 +21,9 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
-
+#include <linux/kfifo.h>
+#include <linux/kref.h>
+#include <sound/compress_driver.h>
#include "../skylake/skl-sst-dsp.h"
struct sst_mem_block;
@@ -97,6 +99,37 @@ struct sst_mailbox {
size_t out_size;
};
+/*
+ * Audio DSP Trace Buffer Configuration.
+*/
+struct sst_dbg_rbuffer {
+ DECLARE_KFIFO_PTR(fifo_dsp, u32);
+ struct kref refcount;
+ unsigned long total_avail;
+ /* To set the state of the stream incase of XRUN */
+ struct snd_compr_stream *stream;
+};
+
+/*
+ * DSP Trace Buffer for FW Logging
+ * Assumption: Each core is assigned equal proportion of memory window for fw
+ * logging addressed in the increasing order of core id (i.e., the first trace
+ * buffer belong to core 0 and so on).
+*/
+struct sst_trace_window {
+ /* base address and size of fw logging windows */
+ void __iomem *addr;
+ u32 size;
+ /* driver ringbuffer array for each DSP */
+ struct sst_dbg_rbuffer **dbg_buffers;
+ /* fw write pointer array for each DSP */
+ void __iomem **dsp_wps;
+ /* number of buffers within fw logging window */
+ u32 nr_dsp;
+ /* indicates which DSPs have logging enabled */
+ u32 flags;
+};
+
/*
* Audio DSP memory block types.
*/
@@ -288,6 +321,9 @@ struct sst_dsp {
/* mailbox */
struct sst_mailbox mailbox;
+ /* Trace Buffer */
+ struct sst_trace_window trace_wind;
+
/* HSW/Byt data */
/* list of free and used ADSP memory blocks */
@@ -390,4 +426,5 @@ void sst_mem_block_unregister_all(struct sst_dsp *dsp);
u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
enum sst_mem_type type);
+
#endif
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
index c5ee108bf5d9..831218ee43c8 100644
--- a/sound/soc/intel/skylake/Makefile
+++ b/sound/soc/intel/skylake/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \
skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \
- skl-sst-utils.o
+ skl-sst-utils.o skl-fwlog.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
diff --git a/sound/soc/intel/skylake/skl-fwlog.c b/sound/soc/intel/skylake/skl-fwlog.c
new file mode 100644
index 000000000000..bc25b9e22252
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-fwlog.c
@@ -0,0 +1,168 @@
+/*
+ * Intel SST FW Log Tracing
+ *
+ * Copyright (C) 2015-16, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <sound/compress_driver.h>
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "skl-sst-ipc.h"
+#include "skl.h"
+#include "skl-fwlog.h"
+
+/*
+ * Initialize trace window and firmware write pointers for the platform
+ */
+int skl_dsp_init_trace_window(struct sst_dsp *sst, u32 *wp, u32 offset,
+ u32 size, int cores)
+{
+ int idx, alloc_size;
+ void **dsp_wps;
+ struct sst_dbg_rbuffer **buff;
+
+ alloc_size = sizeof(buff) * cores;
+ buff = devm_kzalloc(sst->dev, alloc_size, GFP_KERNEL);
+ if (!buff)
+ goto failure;
+
+ dsp_wps = devm_kzalloc(sst->dev, sizeof(void *) * cores, GFP_KERNEL);
+
+ if (!dsp_wps)
+ goto failure;
+
+ sst->trace_wind.addr = sst->addr.lpe + offset;
+ sst->trace_wind.size = size;
+ sst->trace_wind.nr_dsp = cores;
+ sst->trace_wind.flags = 0;
+ sst->trace_wind.dbg_buffers = buff;
+ sst->trace_wind.dsp_wps = (void __iomem**)dsp_wps;
+ for (idx = 0; idx < cores; idx++)
+ sst->trace_wind.dsp_wps[idx] = (void __iomem*)(sst->addr.lpe
+ + wp[idx]);
+ return 0;
+
+failure:
+ dev_err(sst->dev, "Trace buffer init failed for the platform\n");
+ return -ENOMEM;
+}
+
+/*
+ * Initialize ring buffer for a dsp fw logging
+ */
+int skl_dsp_init_log_buffer(struct sst_dsp *sst, int size, int core,
+ struct snd_compr_stream *stream)
+{
+ int ret = 0;
+ struct sst_dbg_rbuffer *tmp;
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ ret = kfifo_alloc(&tmp->fifo_dsp, size, GFP_KERNEL);
+ if (!ret) {
+ tmp->stream = stream;
+ tmp->total_avail = 0;
+ kref_init(&tmp->refcount);
+ sst->trace_wind.dbg_buffers[core] = tmp;
+ } else
+ kfree(tmp);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_dsp_init_log_buffer);
+
+unsigned long skl_dsp_log_avail(struct sst_dsp *sst, int core)
+{
+ struct sst_dbg_rbuffer *buff = sst->trace_wind.dbg_buffers[core];
+
+ if (buff->stream->runtime->state == SNDRV_PCM_STATE_XRUN)
+ return 0;
+
+ return buff->total_avail;
+}
+EXPORT_SYMBOL(skl_dsp_log_avail);
+
+void skl_dsp_write_log(struct sst_dsp *sst, void __iomem *src, int core,
+ int count)
+{
+ int i;
+ u32 *data = (u32 *)src;
+ struct sst_dbg_rbuffer *buff = sst->trace_wind.dbg_buffers[core];
+
+ if (buff->stream->runtime->state == SNDRV_PCM_STATE_XRUN)
+ return;
+
+ for (i = 0; i < count; i += 4) {
+ if (!kfifo_put(&buff->fifo_dsp, *data)) {
+ dev_err(sst->dev, "fw log buffer overrun on dsp %d\n",
+ core);
+ buff->stream->runtime->state = SNDRV_PCM_STATE_XRUN;
+ break;
+ }
+ data++;
+ }
+ buff->total_avail += count;
+}
+
+int skl_dsp_copy_log_user(struct sst_dsp *sst, int core,
+ void __user *dest, int count)
+{
+ int copied, ret;
+ struct sst_dbg_rbuffer *buff = sst->trace_wind.dbg_buffers[core];
+
+ ret = kfifo_to_user(&buff->fifo_dsp, dest, count, &copied);
+
+ return ret ? ret : copied;
+}
+EXPORT_SYMBOL_GPL(skl_dsp_copy_log_user);
+
+static void skl_dsp_free_log_buffer(struct kref *ref)
+{
+ struct sst_dbg_rbuffer *buff = container_of(ref, struct sst_dbg_rbuffer,
+ refcount);
+ kfifo_free(&buff->fifo_dsp);
+ kfree(buff);
+}
+
+void skl_dsp_get_log_buff(struct sst_dsp *sst, int core)
+{
+ struct sst_dbg_rbuffer *buff = sst->trace_wind.dbg_buffers[core];
+
+ kref_get(&buff->refcount);
+}
+EXPORT_SYMBOL_GPL(skl_dsp_get_log_buff);
+
+void skl_dsp_put_log_buff(struct sst_dsp *sst, int core)
+{
+ struct sst_dbg_rbuffer *buff = sst->trace_wind.dbg_buffers[core];
+
+ kref_put(&buff->refcount, skl_dsp_free_log_buffer);
+}
+EXPORT_SYMBOL_GPL(skl_dsp_put_log_buff);
+
+void skl_dsp_done_log_buffer(struct sst_dsp *sst, int core)
+{
+ skl_dsp_put_log_buff(sst, core);
+}
+EXPORT_SYMBOL_GPL(skl_dsp_done_log_buffer);
+
+/* Module Information */
+MODULE_AUTHOR("Ashish Panwar <ashish.panwar@intel.com");
+MODULE_DESCRIPTION("Intel SST FW Log Tracing");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/skylake/skl-fwlog.h b/sound/soc/intel/skylake/skl-fwlog.h
new file mode 100644
index 000000000000..06304de3d2ab
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-fwlog.h
@@ -0,0 +1,20 @@
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "skl.h"
+
+#ifndef __SKL_FWLOG_H__
+#define __SKL_FWLOG_H__
+
+int skl_dsp_init_trace_window(struct sst_dsp *sst, u32 *wp, u32 offset,
+ u32 size, int nr_cores);
+int skl_dsp_init_log_buffer(struct sst_dsp *sst, int size,
+ int core, struct snd_compr_stream *stream);
+unsigned long skl_dsp_log_avail(struct sst_dsp *sst, int core);
+void skl_dsp_write_log(struct sst_dsp *sst, void __iomem *src, int core,
+ int count);
+int skl_dsp_copy_log_user(struct sst_dsp *sst, int core, void __user *dest,
+ int count);
+void skl_dsp_get_log_buff(struct sst_dsp *sst, int core);
+void skl_dsp_put_log_buff(struct sst_dsp *sst, int core);
+void skl_dsp_done_log_buffer(struct sst_dsp *sst, int core);
+#endif /* __SKL_FWLOG_H__ */
--
https://clearlinux.org