xref: /openbmc/linux/sound/soc/sof/sof-client-ipc-flood-test.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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