Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 150
Add memory usage scan possibility#2459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
08c030e49aaa862fccbb4d82096aFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ | ||
| /* | ||
ktrzcinx marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| * 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 <karolx.trzcinski@linux.intel.com> | ||
| */ | ||
| #ifndef __INCLUDE_SOUND_SOF_DEBUG_H__ | ||
| #define __INCLUDE_SOUND_SOF_DEBUG_H__ | ||
| #include <sound/sof/header.h> | ||
| /** 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 */ | ||
Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this has been discussed and I know the reasons and I don't have a good universal solution, but having different (compatible) struct definitions in the kernel and the firmware still feels uncomfortable to me... Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lyakh I think that's a fair point. One one hand, we could have a more strict approach of defining the ABI with a separate formal description (we've started to documents some bits with doxygen notation in FW headers), but in practise the current model has been fairly effective. So for now, any exception needs to be agreed separately, but e.g. in this case, after a lot of back and forth, this seems to be best candidate. | ||
| } __packed; | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -61,6 +61,7 @@ enum sof_ext_man_elem_type { | ||
| SOF_EXT_MAN_ELEM_WINDOW = SOF_IPC_EXT_WINDOW, | ||
ktrzcinx marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 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,23 @@ 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, | ||
| SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN = 2, /**< ABI 3.18 */ | ||
| }; | ||
| 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__ */ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -49,9 +49,10 @@ | ||
| #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_DEBUGSOF_GLB_TYPE(0xAU) | ||
| #define SOF_IPC_GLB_GDB_DEBUGSOF_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) | ||
ktrzcinx marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /* | ||
| * DSP Command Message Types | ||
| @@ -109,7 +110,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 +120,10 @@ | ||
| #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_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001) | ||
| /* test */ | ||
| #define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001) | ||
| /* Get message component id */ | ||
| #define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -14,6 +14,8 @@ | ||
| #include <linux/debugfs.h> | ||
| #include <linux/io.h> | ||
| #include <linux/pm_runtime.h> | ||
| #include <sound/sof/ext_manifest.h> | ||
| #include <sound/sof/debug.h> | ||
| #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); | ||
ktrzcinx marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 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; | ||
ktrzcinx marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| 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); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -192,6 +192,54 @@ 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; | ||
ktrzcinx marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| int elems_size; | ||
| int ret = 0; | ||
| 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; | ||
| 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; | ||
| } | ||
| static ssize_t snd_sof_ext_man_size(const struct firmware *fw) | ||
| { | ||
| const struct sof_ext_man_header *head; | ||
| @@ -274,6 +322,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_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n", | ||
| elem_hdr->type, elem_hdr->size); | ||
Uh oh!
There was an error while loading. Please reload this page.