16e9548cdSRanjani Sridharan // SPDX-License-Identifier: GPL-2.0-only
26e9548cdSRanjani Sridharan //
36e9548cdSRanjani Sridharan // Copyright(c) 2022 Intel Corporation. All rights reserved.
46e9548cdSRanjani Sridharan //
56e9548cdSRanjani Sridharan // Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
66e9548cdSRanjani Sridharan // Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
76e9548cdSRanjani Sridharan //
86e9548cdSRanjani Sridharan
96e9548cdSRanjani Sridharan #include <linux/auxiliary_bus.h>
106e9548cdSRanjani Sridharan #include <linux/completion.h>
116e9548cdSRanjani Sridharan #include <linux/debugfs.h>
126e9548cdSRanjani Sridharan #include <linux/ktime.h>
136e9548cdSRanjani Sridharan #include <linux/mod_devicetable.h>
146e9548cdSRanjani Sridharan #include <linux/module.h>
156e9548cdSRanjani Sridharan #include <linux/pm_runtime.h>
166e9548cdSRanjani Sridharan #include <linux/slab.h>
176e9548cdSRanjani Sridharan #include <linux/uaccess.h>
186e9548cdSRanjani Sridharan #include <sound/sof/header.h>
196e9548cdSRanjani Sridharan
206e9548cdSRanjani Sridharan #include "sof-client.h"
216e9548cdSRanjani Sridharan
226e9548cdSRanjani Sridharan #define MAX_IPC_FLOOD_DURATION_MS 1000
236e9548cdSRanjani Sridharan #define MAX_IPC_FLOOD_COUNT 10000
246e9548cdSRanjani Sridharan #define IPC_FLOOD_TEST_RESULT_LEN 512
256e9548cdSRanjani Sridharan #define SOF_IPC_CLIENT_SUSPEND_DELAY_MS 3000
266e9548cdSRanjani Sridharan
276e9548cdSRanjani Sridharan #define DEBUGFS_IPC_FLOOD_COUNT "ipc_flood_count"
286e9548cdSRanjani Sridharan #define DEBUGFS_IPC_FLOOD_DURATION "ipc_flood_duration_ms"
296e9548cdSRanjani Sridharan
306e9548cdSRanjani Sridharan struct sof_ipc_flood_priv {
316e9548cdSRanjani Sridharan struct dentry *dfs_root;
326e9548cdSRanjani Sridharan struct dentry *dfs_link[2];
336e9548cdSRanjani Sridharan char *buf;
346e9548cdSRanjani Sridharan };
356e9548cdSRanjani Sridharan
sof_ipc_flood_dfs_open(struct inode * inode,struct file * file)366e9548cdSRanjani Sridharan static int sof_ipc_flood_dfs_open(struct inode *inode, struct file *file)
376e9548cdSRanjani Sridharan {
386e9548cdSRanjani Sridharan struct sof_client_dev *cdev = inode->i_private;
396e9548cdSRanjani Sridharan int ret;
406e9548cdSRanjani Sridharan
416e9548cdSRanjani Sridharan if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED)
426e9548cdSRanjani Sridharan return -ENODEV;
436e9548cdSRanjani Sridharan
446e9548cdSRanjani Sridharan ret = debugfs_file_get(file->f_path.dentry);
456e9548cdSRanjani Sridharan if (unlikely(ret))
466e9548cdSRanjani Sridharan return ret;
476e9548cdSRanjani Sridharan
486e9548cdSRanjani Sridharan ret = simple_open(inode, file);
496e9548cdSRanjani Sridharan if (ret)
506e9548cdSRanjani Sridharan debugfs_file_put(file->f_path.dentry);
516e9548cdSRanjani Sridharan
526e9548cdSRanjani Sridharan return ret;
536e9548cdSRanjani Sridharan }
546e9548cdSRanjani Sridharan
556e9548cdSRanjani Sridharan /*
566e9548cdSRanjani Sridharan * helper function to perform the flood test. Only one of the two params, ipc_duration_ms
576e9548cdSRanjani Sridharan * or ipc_count, will be non-zero and will determine the type of test
586e9548cdSRanjani Sridharan */
sof_debug_ipc_flood_test(struct sof_client_dev * cdev,bool flood_duration_test,unsigned long ipc_duration_ms,unsigned long ipc_count)596e9548cdSRanjani Sridharan static int sof_debug_ipc_flood_test(struct sof_client_dev *cdev,
606e9548cdSRanjani Sridharan bool flood_duration_test,
616e9548cdSRanjani Sridharan unsigned long ipc_duration_ms,
626e9548cdSRanjani Sridharan unsigned long ipc_count)
636e9548cdSRanjani Sridharan {
646e9548cdSRanjani Sridharan struct sof_ipc_flood_priv *priv = cdev->data;
656e9548cdSRanjani Sridharan struct device *dev = &cdev->auxdev.dev;
666e9548cdSRanjani Sridharan struct sof_ipc_cmd_hdr hdr;
676e9548cdSRanjani Sridharan u64 min_response_time = U64_MAX;
686e9548cdSRanjani Sridharan ktime_t start, end, test_end;
696e9548cdSRanjani Sridharan u64 avg_response_time = 0;
706e9548cdSRanjani Sridharan u64 max_response_time = 0;
716e9548cdSRanjani Sridharan u64 ipc_response_time;
726e9548cdSRanjani Sridharan int i = 0;
736e9548cdSRanjani Sridharan int ret;
746e9548cdSRanjani Sridharan
756e9548cdSRanjani Sridharan /* configure test IPC */
766e9548cdSRanjani Sridharan hdr.cmd = SOF_IPC_GLB_TEST_MSG | SOF_IPC_TEST_IPC_FLOOD;
776e9548cdSRanjani Sridharan hdr.size = sizeof(hdr);
786e9548cdSRanjani Sridharan
796e9548cdSRanjani Sridharan /* set test end time for duration flood test */
806e9548cdSRanjani Sridharan if (flood_duration_test)
816e9548cdSRanjani Sridharan test_end = ktime_get_ns() + ipc_duration_ms * NSEC_PER_MSEC;
826e9548cdSRanjani Sridharan
836e9548cdSRanjani Sridharan /* send test IPC's */
846e9548cdSRanjani Sridharan while (1) {
856e9548cdSRanjani Sridharan start = ktime_get();
86*367fd6ffSCurtis Malainey ret = sof_client_ipc_tx_message_no_reply(cdev, &hdr);
876e9548cdSRanjani Sridharan end = ktime_get();
886e9548cdSRanjani Sridharan
896e9548cdSRanjani Sridharan if (ret < 0)
906e9548cdSRanjani Sridharan break;
916e9548cdSRanjani Sridharan
926e9548cdSRanjani Sridharan /* compute min and max response times */
936e9548cdSRanjani Sridharan ipc_response_time = ktime_to_ns(ktime_sub(end, start));
946e9548cdSRanjani Sridharan min_response_time = min(min_response_time, ipc_response_time);
956e9548cdSRanjani Sridharan max_response_time = max(max_response_time, ipc_response_time);
966e9548cdSRanjani Sridharan
976e9548cdSRanjani Sridharan /* sum up response times */
986e9548cdSRanjani Sridharan avg_response_time += ipc_response_time;
996e9548cdSRanjani Sridharan i++;
1006e9548cdSRanjani Sridharan
1016e9548cdSRanjani Sridharan /* test complete? */
1026e9548cdSRanjani Sridharan if (flood_duration_test) {
1036e9548cdSRanjani Sridharan if (ktime_to_ns(end) >= test_end)
1046e9548cdSRanjani Sridharan break;
1056e9548cdSRanjani Sridharan } else {
1066e9548cdSRanjani Sridharan if (i == ipc_count)
1076e9548cdSRanjani Sridharan break;
1086e9548cdSRanjani Sridharan }
1096e9548cdSRanjani Sridharan }
1106e9548cdSRanjani Sridharan
1116e9548cdSRanjani Sridharan if (ret < 0)
1126e9548cdSRanjani Sridharan dev_err(dev, "ipc flood test failed at %d iterations\n", i);
1136e9548cdSRanjani Sridharan
1146e9548cdSRanjani Sridharan /* return if the first IPC fails */
1156e9548cdSRanjani Sridharan if (!i)
1166e9548cdSRanjani Sridharan return ret;
1176e9548cdSRanjani Sridharan
1186e9548cdSRanjani Sridharan /* compute average response time */
1196e9548cdSRanjani Sridharan do_div(avg_response_time, i);
1206e9548cdSRanjani Sridharan
1216e9548cdSRanjani Sridharan /* clear previous test output */
1226e9548cdSRanjani Sridharan memset(priv->buf, 0, IPC_FLOOD_TEST_RESULT_LEN);
1236e9548cdSRanjani Sridharan
1246e9548cdSRanjani Sridharan if (!ipc_count) {
1256e9548cdSRanjani Sridharan dev_dbg(dev, "IPC Flood test duration: %lums\n", ipc_duration_ms);
1266e9548cdSRanjani Sridharan snprintf(priv->buf, IPC_FLOOD_TEST_RESULT_LEN,
1276e9548cdSRanjani Sridharan "IPC Flood test duration: %lums\n", ipc_duration_ms);
1286e9548cdSRanjani Sridharan }
1296e9548cdSRanjani Sridharan
1306e9548cdSRanjani Sridharan dev_dbg(dev, "IPC Flood count: %d, Avg response time: %lluns\n",
1316e9548cdSRanjani Sridharan i, avg_response_time);
1326e9548cdSRanjani Sridharan dev_dbg(dev, "Max response time: %lluns\n", max_response_time);
1336e9548cdSRanjani Sridharan dev_dbg(dev, "Min response time: %lluns\n", min_response_time);
1346e9548cdSRanjani Sridharan
1356e9548cdSRanjani Sridharan /* format output string and save test results */
1366e9548cdSRanjani Sridharan snprintf(priv->buf + strlen(priv->buf),
1376e9548cdSRanjani Sridharan IPC_FLOOD_TEST_RESULT_LEN - strlen(priv->buf),
1386e9548cdSRanjani Sridharan "IPC Flood count: %d\nAvg response time: %lluns\n",
1396e9548cdSRanjani Sridharan i, avg_response_time);
1406e9548cdSRanjani Sridharan
1416e9548cdSRanjani Sridharan snprintf(priv->buf + strlen(priv->buf),
1426e9548cdSRanjani Sridharan IPC_FLOOD_TEST_RESULT_LEN - strlen(priv->buf),
1436e9548cdSRanjani Sridharan "Max response time: %lluns\nMin response time: %lluns\n",
1446e9548cdSRanjani Sridharan max_response_time, min_response_time);
1456e9548cdSRanjani Sridharan
1466e9548cdSRanjani Sridharan return ret;
1476e9548cdSRanjani Sridharan }
1486e9548cdSRanjani Sridharan
1496e9548cdSRanjani Sridharan /*
1506e9548cdSRanjani Sridharan * Writing to the debugfs entry initiates the IPC flood test based on
1516e9548cdSRanjani Sridharan * the IPC count or the duration specified by the user.
1526e9548cdSRanjani Sridharan */
sof_ipc_flood_dfs_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)1536e9548cdSRanjani Sridharan static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buffer,
1546e9548cdSRanjani Sridharan size_t count, loff_t *ppos)
1556e9548cdSRanjani Sridharan {
1566e9548cdSRanjani Sridharan struct sof_client_dev *cdev = file->private_data;
1576e9548cdSRanjani Sridharan struct device *dev = &cdev->auxdev.dev;
1586e9548cdSRanjani Sridharan unsigned long ipc_duration_ms = 0;
1596e9548cdSRanjani Sridharan bool flood_duration_test = false;
1606e9548cdSRanjani Sridharan unsigned long ipc_count = 0;
1616e9548cdSRanjani Sridharan struct dentry *dentry;
1626e9548cdSRanjani Sridharan int err;
1636e9548cdSRanjani Sridharan size_t size;
1646e9548cdSRanjani Sridharan char *string;
1656e9548cdSRanjani Sridharan int ret;
1666e9548cdSRanjani Sridharan
1676e9548cdSRanjani Sridharan string = kzalloc(count + 1, GFP_KERNEL);
1686e9548cdSRanjani Sridharan if (!string)
1696e9548cdSRanjani Sridharan return -ENOMEM;
1706e9548cdSRanjani Sridharan
1716e9548cdSRanjani Sridharan size = simple_write_to_buffer(string, count, ppos, buffer, count);
1726e9548cdSRanjani Sridharan
1736e9548cdSRanjani Sridharan /*
1746e9548cdSRanjani Sridharan * write op is only supported for ipc_flood_count or
1756e9548cdSRanjani Sridharan * ipc_flood_duration_ms debugfs entries atm.
1766e9548cdSRanjani Sridharan * ipc_flood_count floods the DSP with the number of IPC's specified.
1776e9548cdSRanjani Sridharan * ipc_duration_ms test floods the DSP for the time specified
1786e9548cdSRanjani Sridharan * in the debugfs entry.
1796e9548cdSRanjani Sridharan */
1806e9548cdSRanjani Sridharan dentry = file->f_path.dentry;
1816e9548cdSRanjani Sridharan if (strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) &&
1826e9548cdSRanjani Sridharan strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) {
1836e9548cdSRanjani Sridharan ret = -EINVAL;
1846e9548cdSRanjani Sridharan goto out;
1856e9548cdSRanjani Sridharan }
1866e9548cdSRanjani Sridharan
1876e9548cdSRanjani Sridharan if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION))
1886e9548cdSRanjani Sridharan flood_duration_test = true;
1896e9548cdSRanjani Sridharan
1906e9548cdSRanjani Sridharan /* test completion criterion */
1916e9548cdSRanjani Sridharan if (flood_duration_test)
1926e9548cdSRanjani Sridharan ret = kstrtoul(string, 0, &ipc_duration_ms);
1936e9548cdSRanjani Sridharan else
1946e9548cdSRanjani Sridharan ret = kstrtoul(string, 0, &ipc_count);
1956e9548cdSRanjani Sridharan if (ret < 0)
1966e9548cdSRanjani Sridharan goto out;
1976e9548cdSRanjani Sridharan
1986e9548cdSRanjani Sridharan /* limit max duration/ipc count for flood test */
1996e9548cdSRanjani Sridharan if (flood_duration_test) {
2006e9548cdSRanjani Sridharan if (!ipc_duration_ms) {
2016e9548cdSRanjani Sridharan ret = size;
2026e9548cdSRanjani Sridharan goto out;
2036e9548cdSRanjani Sridharan }
2046e9548cdSRanjani Sridharan
2056e9548cdSRanjani Sridharan /* find the minimum. min() is not used to avoid warnings */
2066e9548cdSRanjani Sridharan if (ipc_duration_ms > MAX_IPC_FLOOD_DURATION_MS)
2076e9548cdSRanjani Sridharan ipc_duration_ms = MAX_IPC_FLOOD_DURATION_MS;
2086e9548cdSRanjani Sridharan } else {
2096e9548cdSRanjani Sridharan if (!ipc_count) {
2106e9548cdSRanjani Sridharan ret = size;
2116e9548cdSRanjani Sridharan goto out;
2126e9548cdSRanjani Sridharan }
2136e9548cdSRanjani Sridharan
2146e9548cdSRanjani Sridharan /* find the minimum. min() is not used to avoid warnings */
2156e9548cdSRanjani Sridharan if (ipc_count > MAX_IPC_FLOOD_COUNT)
2166e9548cdSRanjani Sridharan ipc_count = MAX_IPC_FLOOD_COUNT;
2176e9548cdSRanjani Sridharan }
2186e9548cdSRanjani Sridharan
219b1378b25SPierre-Louis Bossart ret = pm_runtime_resume_and_get(dev);
2206e9548cdSRanjani Sridharan if (ret < 0 && ret != -EACCES) {
2216e9548cdSRanjani Sridharan dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret);
2226e9548cdSRanjani Sridharan goto out;
2236e9548cdSRanjani Sridharan }
2246e9548cdSRanjani Sridharan
2256e9548cdSRanjani Sridharan /* flood test */
2266e9548cdSRanjani Sridharan ret = sof_debug_ipc_flood_test(cdev, flood_duration_test,
2276e9548cdSRanjani Sridharan ipc_duration_ms, ipc_count);
2286e9548cdSRanjani Sridharan
2296e9548cdSRanjani Sridharan pm_runtime_mark_last_busy(dev);
2306e9548cdSRanjani Sridharan err = pm_runtime_put_autosuspend(dev);
2316e9548cdSRanjani Sridharan if (err < 0)
2326e9548cdSRanjani Sridharan dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
2336e9548cdSRanjani Sridharan
2346e9548cdSRanjani Sridharan /* return size if test is successful */
2356e9548cdSRanjani Sridharan if (ret >= 0)
2366e9548cdSRanjani Sridharan ret = size;
2376e9548cdSRanjani Sridharan out:
2386e9548cdSRanjani Sridharan kfree(string);
2396e9548cdSRanjani Sridharan return ret;
2406e9548cdSRanjani Sridharan }
2416e9548cdSRanjani Sridharan
2426e9548cdSRanjani Sridharan /* return the result of the last IPC flood test */
sof_ipc_flood_dfs_read(struct file * file,char __user * buffer,size_t count,loff_t * ppos)2436e9548cdSRanjani Sridharan static ssize_t sof_ipc_flood_dfs_read(struct file *file, char __user *buffer,
2446e9548cdSRanjani Sridharan size_t count, loff_t *ppos)
2456e9548cdSRanjani Sridharan {
2466e9548cdSRanjani Sridharan struct sof_client_dev *cdev = file->private_data;
2476e9548cdSRanjani Sridharan struct sof_ipc_flood_priv *priv = cdev->data;
2486e9548cdSRanjani Sridharan size_t size_ret;
2496e9548cdSRanjani Sridharan
2506e9548cdSRanjani Sridharan struct dentry *dentry;
2516e9548cdSRanjani Sridharan
2526e9548cdSRanjani Sridharan dentry = file->f_path.dentry;
2536e9548cdSRanjani Sridharan if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) ||
2546e9548cdSRanjani Sridharan !strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) {
2556e9548cdSRanjani Sridharan if (*ppos)
2566e9548cdSRanjani Sridharan return 0;
2576e9548cdSRanjani Sridharan
2586e9548cdSRanjani Sridharan count = min_t(size_t, count, strlen(priv->buf));
2596e9548cdSRanjani Sridharan size_ret = copy_to_user(buffer, priv->buf, count);
2606e9548cdSRanjani Sridharan if (size_ret)
2616e9548cdSRanjani Sridharan return -EFAULT;
2626e9548cdSRanjani Sridharan
2636e9548cdSRanjani Sridharan *ppos += count;
2646e9548cdSRanjani Sridharan return count;
2656e9548cdSRanjani Sridharan }
2666e9548cdSRanjani Sridharan return count;
2676e9548cdSRanjani Sridharan }
2686e9548cdSRanjani Sridharan
sof_ipc_flood_dfs_release(struct inode * inode,struct file * file)2696e9548cdSRanjani Sridharan static int sof_ipc_flood_dfs_release(struct inode *inode, struct file *file)
2706e9548cdSRanjani Sridharan {
2716e9548cdSRanjani Sridharan debugfs_file_put(file->f_path.dentry);
2726e9548cdSRanjani Sridharan
2736e9548cdSRanjani Sridharan return 0;
2746e9548cdSRanjani Sridharan }
2756e9548cdSRanjani Sridharan
2766e9548cdSRanjani Sridharan static const struct file_operations sof_ipc_flood_fops = {
2776e9548cdSRanjani Sridharan .open = sof_ipc_flood_dfs_open,
2786e9548cdSRanjani Sridharan .read = sof_ipc_flood_dfs_read,
2796e9548cdSRanjani Sridharan .llseek = default_llseek,
2806e9548cdSRanjani Sridharan .write = sof_ipc_flood_dfs_write,
2816e9548cdSRanjani Sridharan .release = sof_ipc_flood_dfs_release,
2826e9548cdSRanjani Sridharan
2836e9548cdSRanjani Sridharan .owner = THIS_MODULE,
2846e9548cdSRanjani Sridharan };
2856e9548cdSRanjani Sridharan
2866e9548cdSRanjani Sridharan /*
2876e9548cdSRanjani Sridharan * The IPC test client creates a couple of debugfs entries that will be used
2886e9548cdSRanjani Sridharan * flood tests. Users can write to these entries to execute the IPC flood test
2896e9548cdSRanjani Sridharan * by specifying either the number of IPCs to flood the DSP with or the duration
2906e9548cdSRanjani Sridharan * (in ms) for which the DSP should be flooded with test IPCs. At the
2916e9548cdSRanjani Sridharan * end of each test, the average, min and max response times are reported back.
2926e9548cdSRanjani Sridharan * The results of the last flood test can be accessed by reading the debugfs
2936e9548cdSRanjani Sridharan * entries.
2946e9548cdSRanjani Sridharan */
sof_ipc_flood_probe(struct auxiliary_device * auxdev,const struct auxiliary_device_id * id)2956e9548cdSRanjani Sridharan static int sof_ipc_flood_probe(struct auxiliary_device *auxdev,
2966e9548cdSRanjani Sridharan const struct auxiliary_device_id *id)
2976e9548cdSRanjani Sridharan {
2986e9548cdSRanjani Sridharan struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
2996e9548cdSRanjani Sridharan struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev);
3006e9548cdSRanjani Sridharan struct device *dev = &auxdev->dev;
3016e9548cdSRanjani Sridharan struct sof_ipc_flood_priv *priv;
3026e9548cdSRanjani Sridharan
3036e9548cdSRanjani Sridharan /* allocate memory for client data */
3046e9548cdSRanjani Sridharan priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3056e9548cdSRanjani Sridharan if (!priv)
3066e9548cdSRanjani Sridharan return -ENOMEM;
3076e9548cdSRanjani Sridharan
3086e9548cdSRanjani Sridharan priv->buf = devm_kmalloc(dev, IPC_FLOOD_TEST_RESULT_LEN, GFP_KERNEL);
3096e9548cdSRanjani Sridharan if (!priv->buf)
3106e9548cdSRanjani Sridharan return -ENOMEM;
3116e9548cdSRanjani Sridharan
3126e9548cdSRanjani Sridharan cdev->data = priv;
3136e9548cdSRanjani Sridharan
3146e9548cdSRanjani Sridharan /* create debugfs root folder with device name under parent SOF dir */
3156e9548cdSRanjani Sridharan priv->dfs_root = debugfs_create_dir(dev_name(dev), debugfs_root);
3166e9548cdSRanjani Sridharan if (!IS_ERR_OR_NULL(priv->dfs_root)) {
3176e9548cdSRanjani Sridharan /* create read-write ipc_flood_count debugfs entry */
3186e9548cdSRanjani Sridharan debugfs_create_file(DEBUGFS_IPC_FLOOD_COUNT, 0644, priv->dfs_root,
3196e9548cdSRanjani Sridharan cdev, &sof_ipc_flood_fops);
3206e9548cdSRanjani Sridharan
3216e9548cdSRanjani Sridharan /* create read-write ipc_flood_duration_ms debugfs entry */
3226e9548cdSRanjani Sridharan debugfs_create_file(DEBUGFS_IPC_FLOOD_DURATION, 0644,
3236e9548cdSRanjani Sridharan priv->dfs_root, cdev, &sof_ipc_flood_fops);
3246e9548cdSRanjani Sridharan
3256e9548cdSRanjani Sridharan if (auxdev->id == 0) {
3266e9548cdSRanjani Sridharan /*
3276e9548cdSRanjani Sridharan * Create symlinks for backwards compatibility to the
3286e9548cdSRanjani Sridharan * first IPC flood test instance
3296e9548cdSRanjani Sridharan */
3306e9548cdSRanjani Sridharan char target[100];
3316e9548cdSRanjani Sridharan
3326e9548cdSRanjani Sridharan snprintf(target, 100, "%s/" DEBUGFS_IPC_FLOOD_COUNT,
3336e9548cdSRanjani Sridharan dev_name(dev));
3346e9548cdSRanjani Sridharan priv->dfs_link[0] =
3356e9548cdSRanjani Sridharan debugfs_create_symlink(DEBUGFS_IPC_FLOOD_COUNT,
3366e9548cdSRanjani Sridharan debugfs_root, target);
3376e9548cdSRanjani Sridharan
3386e9548cdSRanjani Sridharan snprintf(target, 100, "%s/" DEBUGFS_IPC_FLOOD_DURATION,
3396e9548cdSRanjani Sridharan dev_name(dev));
3406e9548cdSRanjani Sridharan priv->dfs_link[1] =
3416e9548cdSRanjani Sridharan debugfs_create_symlink(DEBUGFS_IPC_FLOOD_DURATION,
3426e9548cdSRanjani Sridharan debugfs_root, target);
3436e9548cdSRanjani Sridharan }
3446e9548cdSRanjani Sridharan }
3456e9548cdSRanjani Sridharan
3466e9548cdSRanjani Sridharan /* enable runtime PM */
3476e9548cdSRanjani Sridharan pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS);
3486e9548cdSRanjani Sridharan pm_runtime_use_autosuspend(dev);
3496e9548cdSRanjani Sridharan pm_runtime_enable(dev);
3506e9548cdSRanjani Sridharan pm_runtime_mark_last_busy(dev);
3516e9548cdSRanjani Sridharan pm_runtime_idle(dev);
3526e9548cdSRanjani Sridharan
3536e9548cdSRanjani Sridharan return 0;
3546e9548cdSRanjani Sridharan }
3556e9548cdSRanjani Sridharan
sof_ipc_flood_remove(struct auxiliary_device * auxdev)3566e9548cdSRanjani Sridharan static void sof_ipc_flood_remove(struct auxiliary_device *auxdev)
3576e9548cdSRanjani Sridharan {
3586e9548cdSRanjani Sridharan struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
3596e9548cdSRanjani Sridharan struct sof_ipc_flood_priv *priv = cdev->data;
3606e9548cdSRanjani Sridharan
3616e9548cdSRanjani Sridharan pm_runtime_disable(&auxdev->dev);
3626e9548cdSRanjani Sridharan
3636e9548cdSRanjani Sridharan if (auxdev->id == 0) {
3646e9548cdSRanjani Sridharan debugfs_remove(priv->dfs_link[0]);
3656e9548cdSRanjani Sridharan debugfs_remove(priv->dfs_link[1]);
3666e9548cdSRanjani Sridharan }
3676e9548cdSRanjani Sridharan
3686e9548cdSRanjani Sridharan debugfs_remove_recursive(priv->dfs_root);
3696e9548cdSRanjani Sridharan }
3706e9548cdSRanjani Sridharan
3716e9548cdSRanjani Sridharan static const struct auxiliary_device_id sof_ipc_flood_client_id_table[] = {
3726e9548cdSRanjani Sridharan { .name = "snd_sof.ipc_flood" },
3736e9548cdSRanjani Sridharan {},
3746e9548cdSRanjani Sridharan };
3756e9548cdSRanjani Sridharan MODULE_DEVICE_TABLE(auxiliary, sof_ipc_flood_client_id_table);
3766e9548cdSRanjani Sridharan
3776e9548cdSRanjani Sridharan /*
3786e9548cdSRanjani Sridharan * No need for driver pm_ops as the generic pm callbacks in the auxiliary bus
3796e9548cdSRanjani Sridharan * type are enough to ensure that the parent SOF device resumes to bring the DSP
3806e9548cdSRanjani Sridharan * back to D0.
3816e9548cdSRanjani Sridharan * Driver name will be set based on KBUILD_MODNAME.
3826e9548cdSRanjani Sridharan */
3836e9548cdSRanjani Sridharan static struct auxiliary_driver sof_ipc_flood_client_drv = {
3846e9548cdSRanjani Sridharan .probe = sof_ipc_flood_probe,
3856e9548cdSRanjani Sridharan .remove = sof_ipc_flood_remove,
3866e9548cdSRanjani Sridharan
3876e9548cdSRanjani Sridharan .id_table = sof_ipc_flood_client_id_table,
3886e9548cdSRanjani Sridharan };
3896e9548cdSRanjani Sridharan
3906e9548cdSRanjani Sridharan module_auxiliary_driver(sof_ipc_flood_client_drv);
3916e9548cdSRanjani Sridharan
3926e9548cdSRanjani Sridharan MODULE_DESCRIPTION("SOF IPC Flood Test Client Driver");
3936e9548cdSRanjani Sridharan MODULE_LICENSE("GPL");
3946e9548cdSRanjani Sridharan MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
395