Skip to content

Commit d8f8baf

Browse files
committed
ASoC: SOF: Add memory_info file to debugfs
This file content describes firmware memory allocation retrieved at run-time, typically to detect memory leaks. Signed-off-by: Karol Trzcinski <karolx.trzcinski@linux.intel.com>
1 parent 49aaa86 commit d8f8baf

5 files changed

Lines changed: 161 additions & 1 deletion

File tree

include/sound/sof/debug.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
2+
/*
3+
* This file is provided under a dual BSD/GPLv2 license. When using or
4+
* redistributing this file, you may do so under either license.
5+
*
6+
* Copyright(c) 2020 Intel Corporation. All rights reserved.
7+
*/
8+
9+
#ifndef __INCLUDE_SOUND_SOF_DEBUG_H__
10+
#define __INCLUDE_SOUND_SOF_DEBUG_H__
11+
12+
#include <sound/sof/header.h>
13+
14+
enum sof_ipc_dbg_mem_zone {
15+
SOF_IPC_MEM_ZONE_SYS = 0, /**< System zone */
16+
SOF_IPC_MEM_ZONE_SYS_RUNTIME = 1, /**< System-runtime zone */
17+
SOF_IPC_MEM_ZONE_RUNTIME = 2, /**< Runtime zone */
18+
SOF_IPC_MEM_ZONE_BUFFER = 3, /**< Buffer zone */
19+
};
20+
21+
struct sof_ipc_dbg_mem_usage_elem {
22+
uint32_t zone; /**< see sof_ipc_dbg_mem_zone */
23+
uint32_t id; /**< heap index within zone */
24+
uint32_t used; /**< number of bytes used in zone */
25+
uint32_t free; /**< number of bytes free to use within zone */
26+
uint32_t reserved; /**< for future use */
27+
} __attribute__((packed));
28+
29+
struct sof_ipc_dbg_mem_usage {
30+
struct sof_ipc_reply rhdr; /**< generic IPC reply header */
31+
uint32_t reserved[8]; /**< reserved for future use */
32+
uint32_t num_elems; /**< elems[] counter */
33+
struct sof_ipc_dbg_mem_usage_elem elems[]; /**< memory usage information */
34+
} __attribute__((packed));
35+
36+
#endif

include/sound/sof/header.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU)
5353
#define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU)
5454
#define SOF_IPC_GLB_PROBE SOF_GLB_TYPE(0xCU)
55+
#define SOF_IPC_GLB_DEBUG SOF_GLB_TYPE(0xDU)
5556

5657
/*
5758
* DSP Command Message Types
@@ -118,6 +119,9 @@
118119
#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002)
119120
#define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003)
120121

122+
/* debug */
123+
#define SOF_IPC_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001)
124+
121125
/* test */
122126
#define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001)
123127

include/uapi/sound/sof/abi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
/* SOF ABI version major, minor and patch numbers */
2828
#define SOF_ABI_MAJOR 3
29-
#define SOF_ABI_MINOR 17
29+
#define SOF_ABI_MINOR 18
3030
#define SOF_ABI_PATCH 0
3131

3232
/* SOF ABI version number. Format within 32bit word is MMmmmppp */

sound/soc/sof/debug.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/debugfs.h>
1515
#include <linux/io.h>
1616
#include <linux/pm_runtime.h>
17+
#include <sound/sof/debug.h>
1718
#include "sof-priv.h"
1819
#include "ops.h"
1920

@@ -626,6 +627,118 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
626627
}
627628
EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item);
628629

630+
static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size)
631+
{
632+
struct sof_ipc_cmd_hdr msg = {
633+
.size = sizeof(struct sof_ipc_cmd_hdr),
634+
.cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE,
635+
};
636+
struct sof_ipc_dbg_mem_usage *reply;
637+
int len = 0;
638+
int ret;
639+
int i;
640+
641+
reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
642+
if (!reply)
643+
return -ENOMEM;
644+
645+
ret = pm_runtime_get_sync(sdev->dev);
646+
if (ret < 0 && ret != -EACCES) {
647+
pm_runtime_put_noidle(sdev->dev);
648+
dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
649+
goto error;
650+
}
651+
652+
ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
653+
pm_runtime_mark_last_busy(sdev->dev);
654+
pm_runtime_put_autosuspend(sdev->dev);
655+
if (ret < 0 || reply->rhdr.error < 0) {
656+
ret = min(ret, reply->rhdr.error);
657+
dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret);
658+
goto error;
659+
}
660+
661+
if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) {
662+
dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n",
663+
reply->rhdr.hdr.size);
664+
ret = -EINVAL;
665+
goto error;
666+
}
667+
668+
for (i = 0; i < reply->num_elems; i++) {
669+
ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
670+
reply->elems[i].zone, reply->elems[i].id,
671+
reply->elems[i].used, reply->elems[i].free);
672+
if (ret < 0)
673+
goto error;
674+
len += ret;
675+
}
676+
677+
return len;
678+
error:
679+
kfree(reply);
680+
return ret;
681+
}
682+
683+
static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
684+
{
685+
struct snd_sof_dfsentry *dfse = file->private_data;
686+
struct snd_sof_dev *sdev = dfse->sdev;
687+
int ret;
688+
689+
/* allocate buffer memory only in first function run */
690+
if (!sdev->memory_info_buf) {
691+
sdev->memory_info_buf = devm_kmalloc(sdev->dev, dfse->size, GFP_KERNEL);
692+
if (!sdev->memory_info_buf)
693+
return -ENOMEM;
694+
}
695+
696+
/* read memory info from FW only once for each file read */
697+
if (!*ppos) {
698+
sdev->memory_info_len = memory_info_update(sdev, sdev->memory_info_buf, dfse->size);
699+
if (sdev->memory_info_len < 0)
700+
return sdev->memory_info_len;
701+
}
702+
703+
ret = simple_read_from_buffer(to, count, ppos, sdev->memory_info_buf,
704+
sdev->memory_info_len);
705+
706+
return ret;
707+
}
708+
709+
static const struct file_operations memory_info_fops = {
710+
.open = simple_open,
711+
.read = memory_info_read,
712+
.llseek = default_llseek,
713+
};
714+
715+
int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev)
716+
{
717+
struct snd_sof_dfsentry *dfse;
718+
size_t size = 512;
719+
720+
dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
721+
if (!dfse)
722+
goto error;
723+
724+
dfse->type = SOF_DFSENTRY_TYPE_BUF;
725+
dfse->sdev = sdev;
726+
727+
dfse->size = size;
728+
dfse->buf = devm_kmalloc(sdev->dev, size, GFP_KERNEL);
729+
if (!dfse->buf)
730+
goto error;
731+
732+
debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops);
733+
734+
/* add to dfsentry list */
735+
list_add(&dfse->list, &sdev->dfsentry_list);
736+
return 0;
737+
error:
738+
kfree(dfse);
739+
return -ENOMEM;
740+
}
741+
629742
int snd_sof_dbg_init(struct snd_sof_dev *sdev)
630743
{
631744
const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
@@ -651,6 +764,11 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
651764
return err;
652765
}
653766

767+
/* create read-only memory_info debugfs entry */
768+
err = snd_sof_dbg_memory_info_init(sdev);
769+
if (err < 0)
770+
return err;
771+
654772
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
655773
err = snd_sof_debugfs_probe_item(sdev, "probe_points",
656774
0644, &probe_points_fops);

sound/soc/sof/sof-priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ struct snd_sof_dev {
400400
/* debug */
401401
struct dentry *debugfs_root;
402402
struct list_head dfsentry_list;
403+
char *memory_info_buf;
404+
int memory_info_len;
403405

404406
/* firmware loader */
405407
struct snd_dma_buffer dmab;

0 commit comments

Comments
 (0)