From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: "Panwar, Ashish" 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 Reviewed-on: Reviewed-by: Babu, Ramesh Tested-by: Babu, Ramesh Signed-off-by: Guneshwor Singh --- 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 #include #include - +#include +#include +#include #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 +#include +#include +#include +#include +#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