summaryrefslogtreecommitdiff
path: root/sound/soc/sof/debug.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@linux.intel.com>2021-11-16 18:21:37 +0300
committerMark Brown <broonie@kernel.org>2021-11-17 16:04:51 +0300
commit2f0b1b013bbc5d6f4c7c386e12f423d6b4ef3245 (patch)
tree95e68ad04288394942978b263f9939d843e62f85 /sound/soc/sof/debug.c
parent0bd2891bda4550774946abbfac88443a16c15d5a (diff)
downloadlinux-2f0b1b013bbc5d6f4c7c386e12f423d6b4ef3245.tar.xz
ASoC: SOF: debug: Add support for IPC message injection
In order to stress test the firmware's ability to handle (mis)crafted IPC messages this patch adds a debugfs interface where a binary file (message) can be written and the message is sent to the firmware as it is. Read on the same file will return the reply from the firmware if it is available as a binary. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com> Link: https://lore.kernel.org/r/20211116152137.52129-5-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/debug.c')
-rw-r--r--sound/soc/sof/debug.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index dc1df5fb7b4c..2f8b5ac9b78a 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -336,6 +336,104 @@ static int sof_debug_ipc_flood_test(struct snd_sof_dev *sdev,
}
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR)
+static ssize_t msg_inject_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct snd_sof_dfsentry *dfse = file->private_data;
+ struct sof_ipc_reply *rhdr = dfse->msg_inject_rx;
+
+ if (!rhdr->hdr.size || !count || *ppos)
+ return 0;
+
+ if (count > rhdr->hdr.size)
+ count = rhdr->hdr.size;
+
+ if (copy_to_user(buffer, dfse->msg_inject_rx, count))
+ return -EFAULT;
+
+ *ppos += count;
+ return count;
+}
+
+static ssize_t msg_inject_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct snd_sof_dfsentry *dfse = file->private_data;
+ struct snd_sof_dev *sdev = dfse->sdev;
+ struct sof_ipc_cmd_hdr *hdr = dfse->msg_inject_tx;
+ size_t size;
+ int ret, err;
+
+ if (*ppos)
+ return 0;
+
+ size = simple_write_to_buffer(dfse->msg_inject_tx, SOF_IPC_MSG_MAX_SIZE,
+ ppos, buffer, count);
+ if (size != count)
+ return size > 0 ? -EFAULT : size;
+
+ ret = pm_runtime_get_sync(sdev->dev);
+ if (ret < 0 && ret != -EACCES) {
+ dev_err_ratelimited(sdev->dev, "%s: DSP resume failed: %d\n",
+ __func__, ret);
+ pm_runtime_put_noidle(sdev->dev);
+ goto out;
+ }
+
+ /* send the message */
+ memset(dfse->msg_inject_rx, 0, SOF_IPC_MSG_MAX_SIZE);
+ ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, dfse->msg_inject_tx, count,
+ dfse->msg_inject_rx, SOF_IPC_MSG_MAX_SIZE);
+
+ pm_runtime_mark_last_busy(sdev->dev);
+ err = pm_runtime_put_autosuspend(sdev->dev);
+ if (err < 0)
+ dev_err_ratelimited(sdev->dev, "%s: DSP idle failed: %d\n",
+ __func__, err);
+
+ /* return size if test is successful */
+ if (ret >= 0)
+ ret = size;
+
+out:
+ return ret;
+}
+
+static const struct file_operations msg_inject_fops = {
+ .open = simple_open,
+ .read = msg_inject_read,
+ .write = msg_inject_write,
+ .llseek = default_llseek,
+};
+
+static int snd_sof_debugfs_msg_inject_item(struct snd_sof_dev *sdev,
+ const char *name, mode_t mode,
+ const struct file_operations *fops)
+{
+ struct snd_sof_dfsentry *dfse;
+
+ dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+ if (!dfse)
+ return -ENOMEM;
+
+ /* pre allocate the tx and rx buffers */
+ dfse->msg_inject_tx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
+ dfse->msg_inject_rx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
+ if (!dfse->msg_inject_tx || !dfse->msg_inject_rx)
+ return -ENOMEM;
+
+ dfse->type = SOF_DFSENTRY_TYPE_BUF;
+ dfse->sdev = sdev;
+
+ debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops);
+ /* add to dfsentry list */
+ list_add(&dfse->list, &sdev->dfsentry_list);
+
+ return 0;
+}
+#endif
+
static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
@@ -812,6 +910,15 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
return err;
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR)
+ err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644,
+ &msg_inject_fops);
+
+ /* errors are only due to memory allocation, not debugfs */
+ if (err < 0)
+ return err;
+#endif
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_sof_dbg_init);