From df132fa9daf4828598dbba553e1b2bb5cf36a715 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:30:58 -0600 Subject: ASoC: SOF: use inclusive language for bclk and fsync Mirror alsa-lib definitions w/ codec_provider (CP) and codec_consumer (CC). Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201112163100.5081-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'include/sound/sof') diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 34f135adf8ec..6bb403e8c5ee 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -34,15 +34,21 @@ #define SOF_DAI_FMT_IB_NF (3 << 8) /**< invert BCLK + nor FRM */ #define SOF_DAI_FMT_IB_IF (4 << 8) /**< invert BCLK + FRM */ -#define SOF_DAI_FMT_CBM_CFM (0 << 12) /**< codec clk & FRM master */ -#define SOF_DAI_FMT_CBS_CFM (2 << 12) /**< codec clk slave & FRM master */ -#define SOF_DAI_FMT_CBM_CFS (3 << 12) /**< codec clk master & frame slave */ -#define SOF_DAI_FMT_CBS_CFS (4 << 12) /**< codec clk & FRM slave */ +#define SOF_DAI_FMT_CBP_CFP (0 << 12) /**< codec bclk provider & frame provider */ +#define SOF_DAI_FMT_CBC_CFP (2 << 12) /**< codec bclk consumer & frame provider */ +#define SOF_DAI_FMT_CBP_CFC (3 << 12) /**< codec bclk provider & frame consumer */ +#define SOF_DAI_FMT_CBC_CFC (4 << 12) /**< codec bclk consumer & frame consumer */ + +/* keep old definitions for backwards compatibility */ +#define SOF_DAI_FMT_CBM_CFM SOF_DAI_FMT_CBP_CFP +#define SOF_DAI_FMT_CBS_CFM SOF_DAI_FMT_CBC_CFP +#define SOF_DAI_FMT_CBM_CFS SOF_DAI_FMT_CBP_CFC +#define SOF_DAI_FMT_CBS_CFS SOF_DAI_FMT_CBC_CFC #define SOF_DAI_FMT_FORMAT_MASK 0x000f #define SOF_DAI_FMT_CLOCK_MASK 0x00f0 #define SOF_DAI_FMT_INV_MASK 0x0f00 -#define SOF_DAI_FMT_MASTER_MASK 0xf000 +#define SOF_DAI_FMT_CLOCK_PROVIDER_MASK 0xf000 /** \brief Types of DAI */ enum sof_ipc_dai_type { -- cgit v1.3-14-g43fede From 7c1d0e554a359cca77bfabd2a29b06f5322d172d Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Fri, 20 Nov 2020 16:40:25 +0200 Subject: ASoC: SOF: IPC: fix implicit type overflow Implicit values may have a length of 15bits (s16) so we need to declare the proper size so we don't get undefined behaviour. This appears to be arch and compiler dependent. This commit is to keep the headers aligned between the firmware and kernel. UBSan discovered this bug in the firmware. Signed-off-by: Curtis Malainey Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201120144025.2166023-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/sound/sof') diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 2d35997ace40..571e1dd54b89 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -31,12 +31,12 @@ /* Global Message - Generic */ #define SOF_GLB_TYPE_SHIFT 28 -#define SOF_GLB_TYPE_MASK (0xf << SOF_GLB_TYPE_SHIFT) +#define SOF_GLB_TYPE_MASK (0xfL << SOF_GLB_TYPE_SHIFT) #define SOF_GLB_TYPE(x) ((x) << SOF_GLB_TYPE_SHIFT) /* Command Message - Generic */ #define SOF_CMD_TYPE_SHIFT 16 -#define SOF_CMD_TYPE_MASK (0xfff << SOF_CMD_TYPE_SHIFT) +#define SOF_CMD_TYPE_MASK (0xfffL << SOF_CMD_TYPE_SHIFT) #define SOF_CMD_TYPE(x) ((x) << SOF_CMD_TYPE_SHIFT) /* Global Message Types */ -- cgit v1.3-14-g43fede From 7f09f79d5cb13186b0f422cf2e1c711c88c92195 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 24 Nov 2020 20:00:14 +0200 Subject: ASoC: SOF: ext_manifest: Parse firmware config dictionary Values given in this dictionary describes used firmware configuration, like feature availability, buffer size limits and similar properties. Signed-off-by: Karol Trzcinski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201124180017.2232128-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ext_manifest.h | 19 +++++++++++++++++++ sound/soc/sof/loader.c | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) (limited to 'include/sound/sof') diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index 342e86e54db5..31da6e611c6e 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -61,6 +61,7 @@ enum sof_ext_man_elem_type { SOF_EXT_MAN_ELEM_WINDOW = SOF_IPC_EXT_WINDOW, SOF_EXT_MAN_ELEM_CC_VERSION = SOF_IPC_EXT_CC_INFO, SOF_EXT_MAN_ELEM_DBG_ABI = SOF_IPC_EXT_USER_ABI_INFO, + SOF_EXT_MAN_ELEM_CONFIG_DATA = 5, /**< ABI3.17 */ }; /* extended manifest element header */ @@ -99,4 +100,22 @@ struct ext_man_dbg_abi { struct sof_ipc_user_abi_version dbg_abi; } __packed; +/* EXT_MAN_ELEM_CONFIG_DATA elements identificators, ABI3.17 */ +enum config_elem_type { + SOF_EXT_MAN_CONFIG_EMPTY = 0, + SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE = 1, +}; + +struct sof_config_elem { + uint32_t token; + uint32_t value; +} __packed; + +/* firmware configuration information */ +struct sof_ext_man_config_data { + struct sof_ext_man_elem_header hdr; + + struct sof_config_elem elems[]; +} __packed; + #endif /* __SOF_FIRMWARE_EXT_MANIFEST_H__ */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index ce68d708fc6f..33d3be774380 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -197,6 +197,44 @@ static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev, return 0; } +static int ext_man_get_config_data(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + const struct sof_ext_man_config_data *config = + container_of(hdr, struct sof_ext_man_config_data, hdr); + const struct sof_config_elem *elem; + int elems_counter; + int elems_size; + int i; + + /* calculate elements counter */ + elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header); + elems_counter = elems_size / sizeof(struct sof_config_elem); + + dev_dbg(sdev->dev, "%s can hold up to %d config elements\n", + __func__, elems_counter); + + for (i = 0; i < elems_counter; ++i) { + elem = &config->elems[i]; + dev_dbg(sdev->dev, "%s get index %d token %d val %d\n", + __func__, i, elem->token, elem->value); + switch (elem->token) { + case SOF_EXT_MAN_CONFIG_EMPTY: + /* unused memory space is zero filled - mapped to EMPTY elements */ + break; + case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE: + /* TODO: use ipc msg size from config data */ + break; + default: + dev_info(sdev->dev, "Unknown firmware configuration token %d value %d", + elem->token, elem->value); + break; + } + } + + return 0; +} + static ssize_t snd_sof_ext_man_size(const struct firmware *fw) { const struct sof_ext_man_header *head; @@ -279,6 +317,9 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, case SOF_EXT_MAN_ELEM_DBG_ABI: ret = ext_man_get_dbg_abi_info(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_CONFIG_DATA: + ret = ext_man_get_config_data(sdev, elem_hdr); + break; default: dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n", elem_hdr->type, elem_hdr->size); -- cgit v1.3-14-g43fede From 2e4f3f9141cc626147eaf6fbb8a92f17fd069553 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 24 Nov 2020 20:00:15 +0200 Subject: ASoC: SOF: Improve code alignment in header.h Each define value in series should be aligned and tabs should be used instead of spaces to follow code-style. Signed-off-by: Karol Trzcinski Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201124180017.2232128-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/sound/sof') diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 571e1dd54b89..ece6d48dd007 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -49,7 +49,7 @@ #define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U) #define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U) #define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U) -#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU) +#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU) #define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU) #define SOF_IPC_GLB_PROBE SOF_GLB_TYPE(0xCU) @@ -109,7 +109,7 @@ #define SOF_IPC_PROBE_DMA_ADD SOF_CMD_TYPE(0x003) #define SOF_IPC_PROBE_DMA_INFO SOF_CMD_TYPE(0x004) #define SOF_IPC_PROBE_DMA_REMOVE SOF_CMD_TYPE(0x005) -#define SOF_IPC_PROBE_POINT_ADD SOF_CMD_TYPE(0x006) +#define SOF_IPC_PROBE_POINT_ADD SOF_CMD_TYPE(0x006) #define SOF_IPC_PROBE_POINT_INFO SOF_CMD_TYPE(0x007) #define SOF_IPC_PROBE_POINT_REMOVE SOF_CMD_TYPE(0x008) @@ -119,7 +119,7 @@ #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) /* debug */ -#define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001) +#define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001) /* Get message component id */ #define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) -- cgit v1.3-14-g43fede From 6dd958955d3053a9c50353e39671622af4b8fba2 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 24 Nov 2020 20:00:16 +0200 Subject: ASoC: SOF: Change section comment for SOF_IPC_TEST_ Section comment should be coherent with IPC prefix from define names. Signed-off-by: Karol Trzcinski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201124180017.2232128-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/sound/sof') diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index ece6d48dd007..13256d4fb0dd 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -118,7 +118,7 @@ #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) -/* debug */ +/* test */ #define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001) /* Get message component id */ -- cgit v1.3-14-g43fede From 5b10b62989219aa527ee4fa555d1995a3b70981b Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 24 Nov 2020 20:00:17 +0200 Subject: ASoC: SOF: Add `memory_info` file to debugfs This file content describes memory allocation status at run-time, typically to detect memory leaks. Signed-off-by: Karol Trzcinski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201124180017.2232128-5-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/debug.h | 41 ++++++++++++++ include/sound/sof/ext_manifest.h | 1 + include/sound/sof/header.h | 4 ++ include/uapi/sound/sof/abi.h | 2 +- sound/soc/sof/debug.c | 117 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc.c | 9 +++ sound/soc/sof/loader.c | 10 ++++ sound/soc/sof/sof-priv.h | 2 + 8 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 include/sound/sof/debug.h (limited to 'include/sound/sof') diff --git a/include/sound/sof/debug.h b/include/sound/sof/debug.h new file mode 100644 index 000000000000..3ecb5793789d --- /dev/null +++ b/include/sound/sof/debug.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +#ifndef __INCLUDE_SOUND_SOF_DEBUG_H__ +#define __INCLUDE_SOUND_SOF_DEBUG_H__ + +#include + +/** ABI3.18 */ +enum sof_ipc_dbg_mem_zone { + SOF_IPC_MEM_ZONE_SYS = 0, /**< System zone */ + SOF_IPC_MEM_ZONE_SYS_RUNTIME = 1, /**< System-runtime zone */ + SOF_IPC_MEM_ZONE_RUNTIME = 2, /**< Runtime zone */ + SOF_IPC_MEM_ZONE_BUFFER = 3, /**< Buffer zone */ +}; + +/** ABI3.18 */ +struct sof_ipc_dbg_mem_usage_elem { + uint32_t zone; /**< see sof_ipc_dbg_mem_zone */ + uint32_t id; /**< heap index within zone */ + uint32_t used; /**< number of bytes used in zone */ + uint32_t free; /**< number of bytes free to use within zone */ + uint32_t reserved; /**< for future use */ +} __packed; + +/** ABI3.18 */ +struct sof_ipc_dbg_mem_usage { + struct sof_ipc_reply rhdr; /**< generic IPC reply header */ + uint32_t reserved[4]; /**< reserved for future use */ + uint32_t num_elems; /**< elems[] counter */ + struct sof_ipc_dbg_mem_usage_elem elems[]; /**< memory usage information */ +} __packed; + +#endif diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index 31da6e611c6e..e05cb21023e5 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -104,6 +104,7 @@ struct ext_man_dbg_abi { enum config_elem_type { SOF_EXT_MAN_CONFIG_EMPTY = 0, SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE = 1, + SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN = 2, /**< ABI 3.18 */ }; struct sof_config_elem { diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 13256d4fb0dd..c93f08334bbe 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -52,6 +52,7 @@ #define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU) #define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU) #define SOF_IPC_GLB_PROBE SOF_GLB_TYPE(0xCU) +#define SOF_IPC_GLB_DEBUG SOF_GLB_TYPE(0xDU) /* * DSP Command Message Types @@ -118,6 +119,9 @@ #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) +/* debug */ +#define SOF_IPC_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001) + /* test */ #define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001) diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 6af32f82fb99..fe2cfae94b45 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 17 +#define SOF_ABI_MINOR 18 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 9419a99bab53..143117334ae5 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "sof-priv.h" #include "ops.h" @@ -626,6 +628,121 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, } EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item); +static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size) +{ + struct sof_ipc_cmd_hdr msg = { + .size = sizeof(struct sof_ipc_cmd_hdr), + .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE, + }; + struct sof_ipc_dbg_mem_usage *reply; + int len; + int ret; + int i; + + reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + if (!reply) + return -ENOMEM; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(sdev->dev); + dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); + goto error; + } + + ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_put_autosuspend(sdev->dev); + if (ret < 0 || reply->rhdr.error < 0) { + ret = min(ret, reply->rhdr.error); + dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret); + goto error; + } + + if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) { + dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n", + reply->rhdr.hdr.size); + ret = -EINVAL; + goto error; + } + + for (i = 0, len = 0; i < reply->num_elems; i++) { + ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n", + reply->elems[i].zone, reply->elems[i].id, + reply->elems[i].used, reply->elems[i].free); + if (ret < 0) + goto error; + len += ret; + } + + ret = len; +error: + kfree(reply); + return ret; +} + +static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + int data_length; + + /* read memory info from FW only once for each file read */ + if (!*ppos) { + dfse->buf_data_size = 0; + data_length = memory_info_update(sdev, dfse->buf, dfse->size); + if (data_length < 0) + return data_length; + dfse->buf_data_size = data_length; + } + + return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size); +} + +static int memory_info_open(struct inode *inode, struct file *file) +{ + struct snd_sof_dfsentry *dfse = inode->i_private; + struct snd_sof_dev *sdev = dfse->sdev; + + file->private_data = dfse; + + /* allocate buffer memory only in first open run, to save memory when unused */ + if (!dfse->buf) { + dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!dfse->buf) + return -ENOMEM; + dfse->size = PAGE_SIZE; + } + + return 0; +} + +static const struct file_operations memory_info_fops = { + .open = memory_info_open, + .read = memory_info_read, + .llseek = default_llseek, +}; + +int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry *dfse; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + /* don't allocate buffer before first usage, to save memory when unused */ + dfse->type = SOF_DFSENTRY_TYPE_BUF; + dfse->sdev = sdev; + + debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops); + + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + return 0; +} +EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init); + int snd_sof_dbg_init(struct snd_sof_dev *sdev) { const struct snd_sof_dsp_ops *ops = sof_ops(sdev); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index fd2b96ae4943..fc13bb06dbf3 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -181,6 +181,15 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) str2 = "unknown type"; break; } break; + case SOF_IPC_GLB_DEBUG: + str = "GLB_DEBUG"; + switch (type) { + case SOF_IPC_DEBUG_MEM_USAGE: + str2 = "MEM_USAGE"; break; + default: + str2 = "unknown type"; break; + } + break; default: str = "unknown GLB command"; break; } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 33d3be774380..2a8c9bff9963 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -205,6 +205,7 @@ static int ext_man_get_config_data(struct snd_sof_dev *sdev, const struct sof_config_elem *elem; int elems_counter; int elems_size; + int ret = 0; int i; /* calculate elements counter */ @@ -225,11 +226,20 @@ static int ext_man_get_config_data(struct snd_sof_dev *sdev, case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE: /* TODO: use ipc msg size from config data */ break; + case SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN: + if (sdev->first_boot && elem->value) + ret = snd_sof_dbg_memory_info_init(sdev); + break; default: dev_info(sdev->dev, "Unknown firmware configuration token %d value %d", elem->token, elem->value); break; } + if (ret < 0) { + dev_err(sdev->dev, "error: processing sof_ext_man_config_data failed for token %d value 0x%x, %d\n", + elem->token, elem->value, ret); + return ret; + } } return 0; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0aed2a7ab858..d8bc0178dc89 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -290,6 +290,7 @@ enum sof_debugfs_access_type { /* FS entry for debug files that can expose DSP memories, registers */ struct snd_sof_dfsentry { size_t size; + size_t buf_data_size; /* length of buffered data for file read operation */ enum sof_dfsentry_type type; /* * access_type specifies if the @@ -523,6 +524,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, void *stack, size_t stack_words); int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); +int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev); /* * Platform specific ops. -- cgit v1.3-14-g43fede From e984f3ef3d2ac4a1896f7a3845b7c89c27841cbe Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 27 Nov 2020 18:40:18 +0200 Subject: ASoC: SOF: ops: add parse_platform_ext_manifest() op Add parse_platform_ext_manifest() op to parse platform-specific config data in the extended manifest. Signed-off-by: Fred Oh Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201127164022.2498406-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ext_manifest.h | 1 + sound/soc/sof/loader.c | 3 +++ sound/soc/sof/ops.h | 10 ++++++++++ sound/soc/sof/sof-priv.h | 5 +++++ 4 files changed, 19 insertions(+) (limited to 'include/sound/sof') diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index e05cb21023e5..7abc4f0bd3ad 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -62,6 +62,7 @@ enum sof_ext_man_elem_type { SOF_EXT_MAN_ELEM_CC_VERSION = SOF_IPC_EXT_CC_INFO, SOF_EXT_MAN_ELEM_DBG_ABI = SOF_IPC_EXT_USER_ABI_INFO, SOF_EXT_MAN_ELEM_CONFIG_DATA = 5, /**< ABI3.17 */ + SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA = 6, }; /* extended manifest element header */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 2a8c9bff9963..cbce484b6469 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -330,6 +330,9 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, case SOF_EXT_MAN_ELEM_CONFIG_DATA: ret = ext_man_get_config_data(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA: + ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr); + break; default: dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n", elem_hdr->type, elem_hdr->size); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b21632f5511a..77a6ac157d37 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -100,6 +100,16 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } +/* parse platform specific extended manifest */ +static inline int snd_sof_dsp_parse_platform_ext_manifest(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + if (sof_ops(sdev)->parse_platform_ext_manifest) + return sof_ops(sdev)->parse_platform_ext_manifest(sdev, hdr); + + return 0; +} + /* misc */ /** diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d8bc0178dc89..32d6ceb41fdd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -18,6 +18,7 @@ #include #include #include +#include /* debug flags */ #define SOF_DBG_ENABLE_TRACE BIT(0) @@ -208,6 +209,10 @@ struct snd_sof_dsp_ops { int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ + /* parse platform specific extended manifest, optional */ + int (*parse_platform_ext_manifest)(struct snd_sof_dev *sof_dev, + const struct sof_ext_man_elem_header *hdr); + /* DSP PM */ int (*suspend)(struct snd_sof_dev *sof_dev, u32 target_state); /* optional */ -- cgit v1.3-14-g43fede From 8f6cfbb6d4272635311b4604194e39172e7719ad Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Fri, 4 Dec 2020 18:50:14 +0200 Subject: ASoC: SOF: trace: Add runtime trace filtering mechanism The "filter" debugfs file defines the log levels used by the firmware and reported by sof-logger. The file contains the formatted entry list, where each entry follows the following syntax in plain text: log_level uuid_id pipe_id comp_id; This file may be updated by userspace applications such sof-logger, or directly by the user during debugging process. An unused (wildcard) pipe_id or comp_id value should be set to -1, uuid_id is hexadecimal value, so when unused then should be set to 0. When the file is modified, an IPC command is sent to FW with new trace levels for selected components in filter elements list. Signed-off-by: Karol Trzcinski Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201204165014.2697903-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 1 + include/sound/sof/trace.h | 28 ++++++ sound/soc/sof/trace.c | 224 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+) (limited to 'include/sound/sof') diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index c93f08334bbe..4c747c52e01b 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -118,6 +118,7 @@ #define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) +#define SOF_IPC_TRACE_FILTER_UPDATE SOF_CMD_TYPE(0x004) /**< ABI3.17 */ /* debug */ #define SOF_IPC_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001) diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h index c31a94a13ce0..25ea99f62d37 100644 --- a/include/sound/sof/trace.h +++ b/include/sound/sof/trace.h @@ -43,6 +43,34 @@ struct sof_ipc_dma_trace_posn { uint32_t messages; /* total trace messages */ } __packed; +/* Values used in sof_ipc_trace_filter_elem: */ + +/* bits 6..0 */ +#define SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL 0x01 /**< trace level for selected components */ +#define SOF_IPC_TRACE_FILTER_ELEM_BY_UUID 0x02 /**< filter by uuid key */ +#define SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE 0x03 /**< filter by pipeline */ +#define SOF_IPC_TRACE_FILTER_ELEM_BY_COMP 0x04 /**< filter by component id */ + +/* bit 7 */ +#define SOF_IPC_TRACE_FILTER_ELEM_FIN 0x80 /**< mark last filter in set */ + +/* bits 31..8: Unused */ + +/** part of sof_ipc_trace_filter, ABI3.17 */ +struct sof_ipc_trace_filter_elem { + uint32_t key; /**< SOF_IPC_TRACE_FILTER_ELEM_ {LEVEL, UUID, COMP, PIPE} */ + uint32_t value; /**< element value */ +} __packed; + +/** Runtime tracing filtration data - SOF_IPC_TRACE_FILTER_UPDATE, ABI3.17 */ +struct sof_ipc_trace_filter { + struct sof_ipc_cmd_hdr hdr; /**< IPC command header */ + uint32_t elem_cnt; /**< number of entries in elems[] array */ + uint32_t reserved[8]; /**< reserved for future usage */ + /** variable size array with new filtering settings */ + struct sof_ipc_trace_filter_elem elems[]; +} __packed; + /* * Commom debug */ diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 69889241a092..f72a6e83e6af 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -13,6 +13,225 @@ #include "sof-priv.h" #include "ops.h" +#define TRACE_FILTER_ELEMENTS_PER_ENTRY 4 +#define TRACE_FILTER_MAX_CONFIG_STRING_LENGTH 1024 + +static int trace_filter_append_elem(struct snd_sof_dev *sdev, uint32_t key, uint32_t value, + struct sof_ipc_trace_filter_elem *elem_list, + int capacity, int *counter) +{ + if (*counter >= capacity) + return -ENOMEM; + + elem_list[*counter].key = key; + elem_list[*counter].value = value; + ++*counter; + + return 0; +} + +static int trace_filter_parse_entry(struct snd_sof_dev *sdev, const char *line, + struct sof_ipc_trace_filter_elem *elem, + int capacity, int *counter) +{ + int len = strlen(line); + int cnt = *counter; + uint32_t uuid_id; + int log_level; + int pipe_id; + int comp_id; + int read; + int ret; + + /* ignore empty content */ + ret = sscanf(line, " %n", &read); + if (!ret && read == len) + return len; + + ret = sscanf(line, " %d %x %d %d %n", &log_level, &uuid_id, &pipe_id, &comp_id, &read); + if (ret != TRACE_FILTER_ELEMENTS_PER_ENTRY || read != len) { + dev_err(sdev->dev, "error: invalid trace filter entry '%s'\n", line); + return -EINVAL; + } + + if (uuid_id > 0) { + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_UUID, + uuid_id, elem, capacity, &cnt); + if (ret) + return ret; + } + if (pipe_id >= 0) { + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE, + pipe_id, elem, capacity, &cnt); + if (ret) + return ret; + } + if (comp_id >= 0) { + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_COMP, + comp_id, elem, capacity, &cnt); + if (ret) + return ret; + } + + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL | + SOF_IPC_TRACE_FILTER_ELEM_FIN, + log_level, elem, capacity, &cnt); + if (ret) + return ret; + + /* update counter only when parsing whole entry passed */ + *counter = cnt; + + return len; +} + +static int trace_filter_parse(struct snd_sof_dev *sdev, char *string, + int *out_elem_cnt, + struct sof_ipc_trace_filter_elem **out) +{ + static const char entry_delimiter[] = ";"; + char *entry = string; + int capacity = 0; + int entry_len; + int cnt = 0; + + /* + * Each entry contains at least 1, up to TRACE_FILTER_ELEMENTS_PER_ENTRY + * IPC elements, depending on content. Calculate IPC elements capacity + * for the input string where each element is set. + */ + while (entry) { + capacity += TRACE_FILTER_ELEMENTS_PER_ENTRY; + entry = strchr(entry + 1, entry_delimiter[0]); + } + *out = kmalloc(capacity * sizeof(**out), GFP_KERNEL); + if (!*out) + return -ENOMEM; + + /* split input string by ';', and parse each entry separately in trace_filter_parse_entry */ + while ((entry = strsep(&string, entry_delimiter))) { + entry_len = trace_filter_parse_entry(sdev, entry, *out, capacity, &cnt); + if (entry_len < 0) { + dev_err(sdev->dev, "error: %s failed for '%s', %d\n", __func__, entry, + entry_len); + return -EINVAL; + } + } + + *out_elem_cnt = cnt; + + return 0; +} + +static int sof_ipc_trace_update_filter(struct snd_sof_dev *sdev, int num_elems, + struct sof_ipc_trace_filter_elem *elems) +{ + struct sof_ipc_trace_filter *msg; + struct sof_ipc_reply reply; + size_t size; + int ret; + + size = struct_size(msg, elems, num_elems); + if (size > SOF_IPC_MSG_MAX_SIZE) + return -EINVAL; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->hdr.size = size; + msg->hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_FILTER_UPDATE; + msg->elem_cnt = num_elems; + memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems)); + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(sdev->dev); + dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); + goto error; + } + ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size, + &reply, sizeof(reply)); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_put_autosuspend(sdev->dev); + +error: + kfree(msg); + return ret ? ret : reply.error; +} + +static ssize_t sof_dfsentry_trace_filter_write(struct file *file, const char __user *from, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct sof_ipc_trace_filter_elem *elems = NULL; + struct snd_sof_dev *sdev = dfse->sdev; + loff_t pos = 0; + int num_elems; + char *string; + int ret; + + if (count > TRACE_FILTER_MAX_CONFIG_STRING_LENGTH) { + dev_err(sdev->dev, "%s too long input, %zu > %d\n", __func__, count, + TRACE_FILTER_MAX_CONFIG_STRING_LENGTH); + return -EINVAL; + } + + string = kmalloc(count + 1, GFP_KERNEL); + if (!string) + return -ENOMEM; + + /* assert null termination */ + string[count] = 0; + ret = simple_write_to_buffer(string, count, &pos, from, count); + if (ret < 0) + goto error; + + ret = trace_filter_parse(sdev, string, &num_elems, &elems); + if (ret < 0) { + dev_err(sdev->dev, "error: fail in trace_filter_parse, %d\n", ret); + goto error; + } + + if (num_elems) { + ret = sof_ipc_trace_update_filter(sdev, num_elems, elems); + if (ret < 0) { + dev_err(sdev->dev, "error: fail in sof_ipc_trace_update_filter %d\n", ret); + goto error; + } + } + ret = count; +error: + kfree(string); + kfree(elems); + return ret; +} + +static const struct file_operations sof_dfs_trace_filter_fops = { + .open = simple_open, + .write = sof_dfsentry_trace_filter_write, + .llseek = default_llseek, +}; + +static int trace_debugfs_filter_create(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry *dfse; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->sdev = sdev; + dfse->type = SOF_DFSENTRY_TYPE_BUF; + + debugfs_create_file("filter", 0200, sdev->debugfs_root, dfse, + &sof_dfs_trace_filter_fops); + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + + return 0; +} + static size_t sof_trace_avail(struct snd_sof_dev *sdev, loff_t pos, size_t buffer_size) { @@ -135,10 +354,15 @@ static const struct file_operations sof_dfs_trace_fops = { static int trace_debugfs_create(struct snd_sof_dev *sdev) { struct snd_sof_dfsentry *dfse; + int ret; if (!sdev) return -EINVAL; + ret = trace_debugfs_filter_create(sdev); + if (ret < 0) + dev_err(sdev->dev, "error: fail in %s, %d", __func__, ret); + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); if (!dfse) return -ENOMEM; -- cgit v1.3-14-g43fede