1235783Skib// SPDX-License-Identifier: GPL-2.0-only 2235783Skib// 3235783Skib// Copyright(c) 2022 Intel Corporation. All rights reserved. 4235783Skib// 5235783Skib// Author: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> 6235783Skib// 7235783Skib 8235783Skib#include <linux/auxiliary_bus.h> 9235783Skib#include <linux/completion.h> 10235783Skib#include <linux/debugfs.h> 11235783Skib#include <linux/ktime.h> 12235783Skib#include <linux/mod_devicetable.h> 13235783Skib#include <linux/module.h> 14235783Skib#include <linux/pm_runtime.h> 15235783Skib#include <linux/slab.h> 16235783Skib#include <linux/uaccess.h> 17235783Skib#include <sound/sof/header.h> 18235783Skib#include <sound/sof/ipc4/header.h> 19235783Skib 20235783Skib#include "sof-client.h" 21235783Skib 22235783Skib#define SOF_IPC_CLIENT_SUSPEND_DELAY_MS 3000 23235783Skib 24235783Skibstruct sof_msg_inject_priv { 25235783Skib struct dentry *dfs_file; 26235783Skib size_t max_msg_size; 27296548Sdumbbell enum sof_ipc_type ipc_type; 28296548Sdumbbell 29296548Sdumbbell void *tx_buffer; 30296548Sdumbbell void *rx_buffer; 31235783Skib}; 32235783Skib 33235783Skibstatic int sof_msg_inject_dfs_open(struct inode *inode, struct file *file) 34235783Skib{ 35235783Skib struct sof_client_dev *cdev = inode->i_private; 36235783Skib int ret; 37235783Skib 38235783Skib if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED) 39235783Skib return -ENODEV; 40235783Skib 41235783Skib ret = debugfs_file_get(file->f_path.dentry); 42235783Skib if (unlikely(ret)) 43235783Skib return ret; 44235783Skib 45235783Skib ret = simple_open(inode, file); 46235783Skib if (ret) 47235783Skib debugfs_file_put(file->f_path.dentry); 48235783Skib 49235783Skib return ret; 50235783Skib} 51235783Skib 52235783Skibstatic ssize_t sof_msg_inject_dfs_read(struct file *file, char __user *buffer, 53235783Skib size_t count, loff_t *ppos) 54235783Skib{ 55235783Skib struct sof_client_dev *cdev = file->private_data; 56235783Skib struct sof_msg_inject_priv *priv = cdev->data; 57235783Skib struct sof_ipc_reply *rhdr = priv->rx_buffer; 58235783Skib 59235783Skib if (!rhdr->hdr.size || !count || *ppos) 60235783Skib return 0; 61235783Skib 62235783Skib if (count > rhdr->hdr.size) 63235783Skib count = rhdr->hdr.size; 64235783Skib 65235783Skib if (copy_to_user(buffer, priv->rx_buffer, count)) 66235783Skib return -EFAULT; 67235783Skib 68235783Skib *ppos += count; 69235783Skib return count; 70235783Skib} 71235783Skib 72235783Skibstatic ssize_t sof_msg_inject_ipc4_dfs_read(struct file *file, 73235783Skib char __user *buffer, 74235783Skib size_t count, loff_t *ppos) 75235783Skib{ 76235783Skib struct sof_client_dev *cdev = file->private_data; 77235783Skib struct sof_msg_inject_priv *priv = cdev->data; 78235783Skib struct sof_ipc4_msg *ipc4_msg = priv->rx_buffer; 79235783Skib size_t header_size = sizeof(ipc4_msg->header_u64); 80235783Skib size_t remaining; 81235783Skib 82235783Skib if (!ipc4_msg->header_u64 || !count || *ppos) 83235783Skib return 0; 84235783Skib 85235783Skib /* we need space for the header at minimum (u64) */ 86235783Skib if (count < header_size) 87235783Skib return -ENOSPC; 88235783Skib 89235783Skib remaining = header_size; 90235783Skib 91235783Skib /* Only get large config have payload */ 92235783Skib if (SOF_IPC4_MSG_IS_MODULE_MSG(ipc4_msg->primary) && 93235783Skib (SOF_IPC4_MSG_TYPE_GET(ipc4_msg->primary) == SOF_IPC4_MOD_LARGE_CONFIG_GET)) 94235783Skib remaining += ipc4_msg->data_size; 95235783Skib 96235783Skib if (count > remaining) 97235783Skib count = remaining; 98235783Skib else if (count < remaining) 99235783Skib remaining = count; 100235783Skib 101235783Skib /* copy the header first */ 102235783Skib if (copy_to_user(buffer, &ipc4_msg->header_u64, header_size)) 103235783Skib return -EFAULT; 104235783Skib 105235783Skib *ppos += header_size; 106235783Skib remaining -= header_size; 107235783Skib 108235783Skib if (!remaining) 109235783Skib return count; 110235783Skib 111235783Skib if (remaining > ipc4_msg->data_size) 112235783Skib remaining = ipc4_msg->data_size; 113235783Skib 114235783Skib /* Copy the payload */ 115235783Skib if (copy_to_user(buffer + *ppos, ipc4_msg->data_ptr, remaining)) 116235783Skib return -EFAULT; 117235783Skib 118235783Skib *ppos += remaining; 119235783Skib return count; 120235783Skib} 121235783Skib 122235783Skibstatic int sof_msg_inject_send_message(struct sof_client_dev *cdev) 123235783Skib{ 124235783Skib struct sof_msg_inject_priv *priv = cdev->data; 125235783Skib struct device *dev = &cdev->auxdev.dev; 126235783Skib int ret, err; 127235783Skib 128235783Skib ret = pm_runtime_resume_and_get(dev); 129235783Skib if (ret < 0 && ret != -EACCES) { 130235783Skib dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret); 131235783Skib return ret; 132235783Skib } 133235783Skib 134235783Skib /* send the message */ 135235783Skib ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer, priv->rx_buffer, 136235783Skib priv->max_msg_size); 137235783Skib if (ret) 138235783Skib dev_err(dev, "IPC message send failed: %d\n", ret); 139235783Skib 140235783Skib pm_runtime_mark_last_busy(dev); 141235783Skib err = pm_runtime_put_autosuspend(dev); 142235783Skib if (err < 0) 143235783Skib dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); 144235783Skib 145235783Skib return ret; 146235783Skib} 147235783Skib 148235783Skibstatic ssize_t sof_msg_inject_dfs_write(struct file *file, const char __user *buffer, 149235783Skib size_t count, loff_t *ppos) 150235783Skib{ 151235783Skib struct sof_client_dev *cdev = file->private_data; 152235783Skib struct sof_msg_inject_priv *priv = cdev->data; 153235783Skib ssize_t size; 154235783Skib int ret; 155235783Skib 156235783Skib if (*ppos) 157235783Skib return 0; 158235783Skib 159235783Skib size = simple_write_to_buffer(priv->tx_buffer, priv->max_msg_size, 160235783Skib ppos, buffer, count); 161235783Skib if (size < 0) 162235783Skib return size; 163235783Skib if (size != count) 164235783Skib return -EFAULT; 165235783Skib 166235783Skib memset(priv->rx_buffer, 0, priv->max_msg_size); 167235783Skib 168235783Skib ret = sof_msg_inject_send_message(cdev); 169235783Skib 170235783Skib /* return the error code if test failed */ 171235783Skib if (ret < 0) 172235783Skib size = ret; 173235783Skib 174296548Sdumbbell return size; 175235783Skib}; 176235783Skib 177235783Skibstatic ssize_t sof_msg_inject_ipc4_dfs_write(struct file *file, 178235783Skib const char __user *buffer, 179277487Skib size_t count, loff_t *ppos) 180277487Skib{ 181277487Skib struct sof_client_dev *cdev = file->private_data; 182277487Skib struct sof_msg_inject_priv *priv = cdev->data; 183277487Skib struct sof_ipc4_msg *ipc4_msg = priv->tx_buffer; 184277487Skib size_t data_size; 185277487Skib int ret; 186277487Skib 187277487Skib if (*ppos) 188277487Skib return 0; 189277487Skib 190277487Skib if (count < sizeof(ipc4_msg->header_u64)) 191277487Skib return -EINVAL; 192296548Sdumbbell 193277487Skib /* copy the header first */ 194277487Skib if (copy_from_user(&ipc4_msg->header_u64, buffer, 195277487Skib sizeof(ipc4_msg->header_u64))) 196277487Skib return -EFAULT; 197277487Skib 198277487Skib data_size = count - sizeof(ipc4_msg->header_u64); 199277487Skib if (data_size > priv->max_msg_size) 200277487Skib return -EINVAL; 201235783Skib 202235783Skib /* Copy the payload */ 203235783Skib if (copy_from_user(ipc4_msg->data_ptr, 204235783Skib buffer + sizeof(ipc4_msg->header_u64), data_size)) 205235783Skib return -EFAULT; 206235783Skib 207235783Skib ipc4_msg->data_size = data_size; 208235783Skib 209235783Skib /* Initialize the reply storage */ 210277487Skib ipc4_msg = priv->rx_buffer; 211235783Skib ipc4_msg->header_u64 = 0; 212235783Skib ipc4_msg->data_size = priv->max_msg_size; 213235783Skib memset(ipc4_msg->data_ptr, 0, priv->max_msg_size); 214235783Skib 215235783Skib ret = sof_msg_inject_send_message(cdev); 216235783Skib 217235783Skib /* return the error code if test failed */ 218235783Skib if (ret < 0) 219235783Skib return ret; 220235783Skib 221235783Skib return count; 222235783Skib}; 223235783Skib 224235783Skibstatic int sof_msg_inject_dfs_release(struct inode *inode, struct file *file) 225235783Skib{ 226235783Skib debugfs_file_put(file->f_path.dentry); 227235783Skib 228235783Skib return 0; 229235783Skib} 230235783Skib 231235783Skibstatic const struct file_operations sof_msg_inject_fops = { 232235783Skib .open = sof_msg_inject_dfs_open, 233235783Skib .read = sof_msg_inject_dfs_read, 234235783Skib .write = sof_msg_inject_dfs_write, 235235783Skib .llseek = default_llseek, 236235783Skib .release = sof_msg_inject_dfs_release, 237235783Skib 238296548Sdumbbell .owner = THIS_MODULE, 239296548Sdumbbell}; 240296548Sdumbbell 241235783Skibstatic const struct file_operations sof_msg_inject_ipc4_fops = { 242235783Skib .open = sof_msg_inject_dfs_open, 243235783Skib .read = sof_msg_inject_ipc4_dfs_read, 244235783Skib .write = sof_msg_inject_ipc4_dfs_write, 245235783Skib .llseek = default_llseek, 246235783Skib .release = sof_msg_inject_dfs_release, 247235783Skib 248235783Skib .owner = THIS_MODULE, 249235783Skib}; 250235783Skib 251235783Skibstatic int sof_msg_inject_probe(struct auxiliary_device *auxdev, 252235783Skib const struct auxiliary_device_id *id) 253235783Skib{ 254235783Skib struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); 255235783Skib struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev); 256235783Skib static const struct file_operations *fops; 257235783Skib struct device *dev = &auxdev->dev; 258235783Skib struct sof_msg_inject_priv *priv; 259235783Skib size_t alloc_size; 260235783Skib 261235783Skib /* allocate memory for client data */ 262235783Skib priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL); 263235783Skib if (!priv) 264235783Skib return -ENOMEM; 265235783Skib 266235783Skib priv->ipc_type = sof_client_get_ipc_type(cdev); 267235783Skib priv->max_msg_size = sof_client_get_ipc_max_payload_size(cdev); 268296548Sdumbbell alloc_size = priv->max_msg_size; 269235783Skib 270296548Sdumbbell if (priv->ipc_type == SOF_IPC_TYPE_4) 271235783Skib alloc_size += sizeof(struct sof_ipc4_msg); 272277487Skib 273277487Skib priv->tx_buffer = devm_kmalloc(dev, alloc_size, GFP_KERNEL); 274277487Skib priv->rx_buffer = devm_kzalloc(dev, alloc_size, GFP_KERNEL); 275277487Skib if (!priv->tx_buffer || !priv->rx_buffer) 276277487Skib return -ENOMEM; 277277487Skib 278277487Skib if (priv->ipc_type == SOF_IPC_TYPE_4) { 279277487Skib struct sof_ipc4_msg *ipc4_msg; 280277487Skib 281277487Skib ipc4_msg = priv->tx_buffer; 282277487Skib ipc4_msg->data_ptr = priv->tx_buffer + sizeof(struct sof_ipc4_msg); 283277487Skib 284277487Skib ipc4_msg = priv->rx_buffer; 285235783Skib ipc4_msg->data_ptr = priv->rx_buffer + sizeof(struct sof_ipc4_msg); 286235783Skib 287235783Skib fops = &sof_msg_inject_ipc4_fops; 288235783Skib } else { 289235783Skib fops = &sof_msg_inject_fops; 290235783Skib } 291235783Skib 292235783Skib cdev->data = priv; 293235783Skib 294235783Skib priv->dfs_file = debugfs_create_file("ipc_msg_inject", 0644, debugfs_root, 295235783Skib cdev, fops); 296235783Skib 297277487Skib /* enable runtime PM */ 298277487Skib pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS); 299277487Skib pm_runtime_use_autosuspend(dev); 300277487Skib pm_runtime_enable(dev); 301277487Skib pm_runtime_mark_last_busy(dev); 302235783Skib pm_runtime_idle(dev); 303235783Skib 304235783Skib return 0; 305235783Skib} 306235783Skib 307235783Skibstatic void sof_msg_inject_remove(struct auxiliary_device *auxdev) 308235783Skib{ 309235783Skib struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); 310235783Skib struct sof_msg_inject_priv *priv = cdev->data; 311235783Skib 312235783Skib pm_runtime_disable(&auxdev->dev); 313235783Skib 314235783Skib debugfs_remove(priv->dfs_file); 315235783Skib} 316296548Sdumbbell 317296548Sdumbbellstatic const struct auxiliary_device_id sof_msg_inject_client_id_table[] = { 318296548Sdumbbell { .name = "snd_sof.msg_injector" }, 319235783Skib {}, 320235783Skib}; 321235783SkibMODULE_DEVICE_TABLE(auxiliary, sof_msg_inject_client_id_table); 322235783Skib 323235783Skib/* 324235783Skib * No need for driver pm_ops as the generic pm callbacks in the auxiliary bus 325235783Skib * type are enough to ensure that the parent SOF device resumes to bring the DSP 326235783Skib * back to D0. 327235783Skib * Driver name will be set based on KBUILD_MODNAME. 328235783Skib */ 329235783Skibstatic struct auxiliary_driver sof_msg_inject_client_drv = { 330235783Skib .probe = sof_msg_inject_probe, 331235783Skib .remove = sof_msg_inject_remove, 332235783Skib 333235783Skib .id_table = sof_msg_inject_client_id_table, 334235783Skib}; 335235783Skib 336235783Skibmodule_auxiliary_driver(sof_msg_inject_client_drv); 337235783Skib 338235783SkibMODULE_DESCRIPTION("SOF IPC Message Injector Client Driver"); 339235783SkibMODULE_LICENSE("GPL"); 340235783SkibMODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); 341235783Skib