Skip to content

Commit bc6635b

Browse files
ujfalusikv2019i
authored andcommitted
ASoC: SOF: Convert the generic IPC message injector into SOF client
Move the IPC message injection code out from the debug file as separate SOF client driver. Based on the kernel configuration, the device registration for the new IPC message injector is going to happen in the core. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent 9676d84 commit bc6635b

File tree

6 files changed

+229
-115
lines changed

6 files changed

+229
-115
lines changed

sound/soc/sof/Kconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM
212212
Select the number of IPC flood test clients to be created.
213213

214214
config SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR
215-
bool "SOF enable IPC message injector"
215+
tristate "SOF enable IPC message injector"
216+
select SND_SOC_SOF_CLIENT
216217
help
217218
This option enables the IPC message injector which can be used to send
218219
crafted IPC messages to the DSP to test its robustness.

sound/soc/sof/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ snd-sof-acpi-objs := sof-acpi-dev.o
1212
snd-sof-of-objs := sof-of-dev.o
1313

1414
snd-sof-ipc-flood-test-objs := sof-client-ipc-flood-test.o
15+
snd-sof-ipc-msg-injector-objs := sof-client-ipc-msg-injector.o
1516

1617
snd-sof-nocodec-objs := nocodec.o
1718

@@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_SOF_OF_DEV) += snd-sof-of.o
2728
obj-$(CONFIG_SND_SOC_SOF_PCI_DEV) += snd-sof-pci.o
2829

2930
obj-$(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) += snd-sof-ipc-flood-test.o
31+
obj-$(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) += snd-sof-ipc-msg-injector.o
3032

3133
obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/
3234
obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/

sound/soc/sof/debug.c

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -234,105 +234,6 @@ static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev,
234234
}
235235
#endif
236236

237-
238-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR)
239-
static ssize_t msg_inject_read(struct file *file, char __user *buffer,
240-
size_t count, loff_t *ppos)
241-
{
242-
struct snd_sof_dfsentry *dfse = file->private_data;
243-
struct sof_ipc_reply *rhdr = dfse->msg_inject_rx;
244-
245-
if (!rhdr->hdr.size || !count || *ppos)
246-
return 0;
247-
248-
if (count > rhdr->hdr.size)
249-
count = rhdr->hdr.size;
250-
251-
if (copy_to_user(buffer, dfse->msg_inject_rx, count))
252-
return -EFAULT;
253-
254-
*ppos += count;
255-
return count;
256-
}
257-
258-
static ssize_t msg_inject_write(struct file *file, const char __user *buffer,
259-
size_t count, loff_t *ppos)
260-
{
261-
struct snd_sof_dfsentry *dfse = file->private_data;
262-
struct snd_sof_dev *sdev = dfse->sdev;
263-
struct sof_ipc_cmd_hdr *hdr = dfse->msg_inject_tx;
264-
size_t size;
265-
int ret, err;
266-
267-
if (*ppos)
268-
return 0;
269-
270-
size = simple_write_to_buffer(dfse->msg_inject_tx, SOF_IPC_MSG_MAX_SIZE,
271-
ppos, buffer, count);
272-
if (size != count)
273-
return size > 0 ? -EFAULT : size;
274-
275-
ret = pm_runtime_get_sync(sdev->dev);
276-
if (ret < 0 && ret != -EACCES) {
277-
dev_err_ratelimited(sdev->dev, "%s: DSP resume failed: %d\n",
278-
__func__, ret);
279-
pm_runtime_put_noidle(sdev->dev);
280-
goto out;
281-
}
282-
283-
/* send the message */
284-
memset(dfse->msg_inject_rx, 0, SOF_IPC_MSG_MAX_SIZE);
285-
ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, dfse->msg_inject_tx, count,
286-
dfse->msg_inject_rx, SOF_IPC_MSG_MAX_SIZE);
287-
288-
pm_runtime_mark_last_busy(sdev->dev);
289-
err = pm_runtime_put_autosuspend(sdev->dev);
290-
if (err < 0)
291-
dev_err_ratelimited(sdev->dev, "%s: DSP idle failed: %d\n",
292-
__func__, err);
293-
294-
/* return size if test is successful */
295-
if (ret >= 0)
296-
ret = size;
297-
298-
out:
299-
return ret;
300-
}
301-
302-
static const struct file_operations msg_inject_fops = {
303-
.open = simple_open,
304-
.read = msg_inject_read,
305-
.write = msg_inject_write,
306-
.llseek = default_llseek,
307-
};
308-
309-
static int snd_sof_debugfs_msg_inject_item(struct snd_sof_dev *sdev,
310-
const char *name, mode_t mode,
311-
const struct file_operations *fops)
312-
{
313-
struct snd_sof_dfsentry *dfse;
314-
315-
dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
316-
if (!dfse)
317-
return -ENOMEM;
318-
319-
/* pre allocate the tx and rx buffers */
320-
dfse->msg_inject_tx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
321-
dfse->msg_inject_rx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
322-
if (!dfse->msg_inject_tx || !dfse->msg_inject_rx)
323-
return -ENOMEM;
324-
325-
dfse->type = SOF_DFSENTRY_TYPE_BUF;
326-
dfse->sdev = sdev;
327-
328-
debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops);
329-
/* add to dfsentry list */
330-
list_add(&dfse->list, &sdev->dfsentry_list);
331-
332-
return 0;
333-
}
334-
#endif
335-
336237
static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
337238
size_t count, loff_t *ppos)
338239
{
@@ -679,15 +580,6 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
679580
return err;
680581
#endif
681582

682-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR)
683-
err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644,
684-
&msg_inject_fops);
685-
686-
/* errors are only due to memory allocation, not debugfs */
687-
if (err < 0)
688-
return err;
689-
#endif
690-
691583
return 0;
692584
}
693585
EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
//
3+
// Copyright(c) 2021 Intel Corporation. All rights reserved.
4+
//
5+
// Author: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
6+
//
7+
8+
#include <linux/auxiliary_bus.h>
9+
#include <linux/completion.h>
10+
#include <linux/debugfs.h>
11+
#include <linux/ktime.h>
12+
#include <linux/mod_devicetable.h>
13+
#include <linux/module.h>
14+
#include <linux/pm_runtime.h>
15+
#include <linux/slab.h>
16+
#include <linux/uaccess.h>
17+
#include <sound/sof/header.h>
18+
19+
#include "sof-client.h"
20+
21+
#define SOF_IPC_CLIENT_SUSPEND_DELAY_MS 3000
22+
23+
struct sof_msg_inject_priv {
24+
struct dentry *dfs_file;
25+
26+
void *tx_buffer;
27+
void *rx_buffer;
28+
};
29+
30+
static int sof_msg_inject_dfs_open(struct inode *inode, struct file *file)
31+
{
32+
struct sof_client_dev *cdev = inode->i_private;
33+
int ret;
34+
35+
if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED)
36+
return -ENODEV;
37+
38+
ret = debugfs_file_get(file->f_path.dentry);
39+
if (unlikely(ret))
40+
return ret;
41+
42+
ret = simple_open(inode, file);
43+
if (ret)
44+
debugfs_file_put(file->f_path.dentry);
45+
46+
return ret;
47+
}
48+
49+
static ssize_t sof_msg_inject_dfs_read(struct file *file, char __user *buffer,
50+
size_t count, loff_t *ppos)
51+
{
52+
struct sof_client_dev *cdev = file->private_data;
53+
struct sof_msg_inject_priv *priv = cdev->data;
54+
struct sof_ipc_reply *rhdr = priv->rx_buffer;
55+
56+
if (!rhdr->hdr.size || !count || *ppos)
57+
return 0;
58+
59+
if (count > rhdr->hdr.size)
60+
count = rhdr->hdr.size;
61+
62+
if (copy_to_user(buffer, priv->rx_buffer, count))
63+
return -EFAULT;
64+
65+
*ppos += count;
66+
return count;
67+
}
68+
69+
static ssize_t sof_msg_inject_dfs_write(struct file *file, const char __user *buffer,
70+
size_t count, loff_t *ppos)
71+
{
72+
struct sof_client_dev *cdev = file->private_data;
73+
struct sof_msg_inject_priv *priv = cdev->data;
74+
struct device *dev = &cdev->auxdev.dev;
75+
int ret, err;
76+
size_t size;
77+
78+
if (*ppos)
79+
return 0;
80+
81+
size = simple_write_to_buffer(priv->tx_buffer, SOF_IPC_MSG_MAX_SIZE,
82+
ppos, buffer, count);
83+
if (size != count)
84+
return size > 0 ? -EFAULT : size;
85+
86+
ret = pm_runtime_get_sync(dev);
87+
if (ret < 0 && ret != -EACCES) {
88+
dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret);
89+
pm_runtime_put_noidle(dev);
90+
return ret;
91+
}
92+
93+
/* send the message */
94+
memset(priv->rx_buffer, 0, SOF_IPC_MSG_MAX_SIZE);
95+
ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer, priv->rx_buffer,
96+
SOF_IPC_MSG_MAX_SIZE);
97+
pm_runtime_mark_last_busy(dev);
98+
err = pm_runtime_put_autosuspend(dev);
99+
if (err < 0)
100+
dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
101+
102+
/* return size if test is successful */
103+
if (ret >= 0)
104+
ret = size;
105+
106+
return ret;
107+
};
108+
109+
static int sof_msg_inject_dfs_release(struct inode *inode, struct file *file)
110+
{
111+
debugfs_file_put(file->f_path.dentry);
112+
113+
return 0;
114+
}
115+
116+
static const struct file_operations sof_msg_inject_fops = {
117+
.open = sof_msg_inject_dfs_open,
118+
.read = sof_msg_inject_dfs_read,
119+
.write = sof_msg_inject_dfs_write,
120+
.llseek = default_llseek,
121+
.release = sof_msg_inject_dfs_release,
122+
123+
.owner = THIS_MODULE,
124+
};
125+
126+
static int sof_msg_inject_probe(struct auxiliary_device *auxdev,
127+
const struct auxiliary_device_id *id)
128+
{
129+
struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
130+
struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev);
131+
struct device *dev = &auxdev->dev;
132+
struct sof_msg_inject_priv *priv;
133+
134+
/* allocate memory for client data */
135+
priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);
136+
if (!priv)
137+
return -ENOMEM;
138+
139+
priv->tx_buffer = devm_kmalloc(dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
140+
priv->rx_buffer = devm_kmalloc(dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
141+
if (!priv->tx_buffer || !priv->rx_buffer)
142+
return -ENOMEM;
143+
144+
cdev->data = priv;
145+
146+
priv->dfs_file = debugfs_create_file("ipc_msg_inject", 0644, debugfs_root,
147+
cdev, &sof_msg_inject_fops);
148+
149+
/* enable runtime PM */
150+
pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS);
151+
pm_runtime_use_autosuspend(dev);
152+
pm_runtime_enable(dev);
153+
pm_runtime_mark_last_busy(dev);
154+
pm_runtime_idle(dev);
155+
156+
return 0;
157+
}
158+
159+
static void sof_msg_inject_remove(struct auxiliary_device *auxdev)
160+
{
161+
struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
162+
struct sof_msg_inject_priv *priv = cdev->data;
163+
164+
pm_runtime_disable(&auxdev->dev);
165+
166+
debugfs_remove(priv->dfs_file);
167+
}
168+
169+
static const struct auxiliary_device_id sof_msg_inject_client_id_table[] = {
170+
{ .name = "snd_sof.msg_injector" },
171+
{},
172+
};
173+
MODULE_DEVICE_TABLE(auxiliary, sof_msg_inject_client_id_table);
174+
175+
/*
176+
* No need for driver pm_ops as the generic pm callbacks in the auxiliary bus
177+
* type are enough to ensure that the parent SOF device resumes to bring the DSP
178+
* back to D0.
179+
* Driver name will be set based on KBUILD_MODNAME.
180+
*/
181+
static struct auxiliary_driver sof_msg_inject_client_drv = {
182+
.probe = sof_msg_inject_probe,
183+
.remove = sof_msg_inject_remove,
184+
185+
.id_table = sof_msg_inject_client_id_table,
186+
};
187+
188+
module_auxiliary_driver(sof_msg_inject_client_drv);
189+
190+
MODULE_DESCRIPTION("SOF IPC Message Injector Client Driver");
191+
MODULE_LICENSE("GPL");
192+
MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);

0 commit comments

Comments
 (0)