Commit d491db14 authored by Mark Brown's avatar Mark Brown

ASoC: SOF: sof-client: Update for different IPC versions

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

Hi,

The current IPC client infrastructure can only be used with IPC3.
This series carries updates for the core side of the client support to handle
IPC4 messages and updates the ipc message injector to be usable with IPC4.

The IPC flood test is only supported by SOF_IPC (IPC3), we are not going to
create the aux device for it at all if the firmware is using IPC4.

Regards,
Peter
---
Peter Ujfalusi (8):
  ASoC: SOF: sof-client: Add API to get the maximum IPC payload size
  ASoC: SOF: ipc-msg-injector: Query the maximum IPC payload size
  ASoC: SOF: sof-client-probes: Query the maximum IPC payload size
  ASoC: SOF: sof-client: Add API to get the ipc_type
  ASoC: SOF: sof-client: Add support IPC4 message sending
  ASoC: SOF: ipc-msg-injector: Separate the message sending
  ASoC: SOF: ipc-msg-injector: Add support for IPC4 messages
  ASoC: SOF: sof-client: IPC flood test can only work with SOF_IPC

 sound/soc/sof/sof-client-ipc-msg-injector.c | 181 ++++++++++++++++++--
 sound/soc/sof/sof-client-probes.c           |   5 +-
 sound/soc/sof/sof-client.c                  |  66 ++++++-
 sound/soc/sof/sof-client.h                  |   2 +
 4 files changed, 227 insertions(+), 27 deletions(-)

--
2.36.0
parents d94d1486 5889ccdd
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <sound/sof/header.h> #include <sound/sof/header.h>
#include <sound/sof/ipc4/header.h>
#include "sof-client.h" #include "sof-client.h"
...@@ -22,6 +23,8 @@ ...@@ -22,6 +23,8 @@
struct sof_msg_inject_priv { struct sof_msg_inject_priv {
struct dentry *dfs_file; struct dentry *dfs_file;
size_t max_msg_size;
enum sof_ipc_type ipc_type;
void *tx_buffer; void *tx_buffer;
void *rx_buffer; void *rx_buffer;
...@@ -66,22 +69,54 @@ static ssize_t sof_msg_inject_dfs_read(struct file *file, char __user *buffer, ...@@ -66,22 +69,54 @@ static ssize_t sof_msg_inject_dfs_read(struct file *file, char __user *buffer,
return count; return count;
} }
static ssize_t sof_msg_inject_dfs_write(struct file *file, const char __user *buffer, static ssize_t sof_msg_inject_ipc4_dfs_read(struct file *file,
size_t count, loff_t *ppos) char __user *buffer,
size_t count, loff_t *ppos)
{ {
struct sof_client_dev *cdev = file->private_data; struct sof_client_dev *cdev = file->private_data;
struct sof_msg_inject_priv *priv = cdev->data; struct sof_msg_inject_priv *priv = cdev->data;
struct device *dev = &cdev->auxdev.dev; struct sof_ipc4_msg *ipc4_msg = priv->rx_buffer;
int ret, err; size_t remaining;
size_t size;
if (*ppos) if (!ipc4_msg->header_u64 || !count || *ppos)
return 0; return 0;
size = simple_write_to_buffer(priv->tx_buffer, SOF_IPC_MSG_MAX_SIZE, remaining = sizeof(ipc4_msg->header_u64);
ppos, buffer, count);
if (size != count) /* Only get large config have payload */
return size > 0 ? -EFAULT : size; if (SOF_IPC4_MSG_IS_MODULE_MSG(ipc4_msg->primary) &&
(SOF_IPC4_MSG_TYPE_GET(ipc4_msg->primary) == SOF_IPC4_MOD_LARGE_CONFIG_GET))
remaining += ipc4_msg->data_size;
if (count > remaining)
count = remaining;
/* copy the header first */
if (copy_to_user(buffer, &ipc4_msg->header_u64, sizeof(ipc4_msg->header_u64)))
return -EFAULT;
*ppos += sizeof(ipc4_msg->header_u64);
remaining -= sizeof(ipc4_msg->header_u64);
if (!remaining)
return count;
if (remaining > ipc4_msg->data_size)
remaining = ipc4_msg->data_size;
/* Copy the payload */
if (copy_to_user(buffer + *ppos, ipc4_msg->data_ptr, remaining))
return -EFAULT;
*ppos += remaining;
return count;
}
static int sof_msg_inject_send_message(struct sof_client_dev *cdev)
{
struct sof_msg_inject_priv *priv = cdev->data;
struct device *dev = &cdev->auxdev.dev;
int ret, err;
ret = pm_runtime_resume_and_get(dev); ret = pm_runtime_resume_and_get(dev);
if (ret < 0 && ret != -EACCES) { if (ret < 0 && ret != -EACCES) {
...@@ -90,19 +125,94 @@ static ssize_t sof_msg_inject_dfs_write(struct file *file, const char __user *bu ...@@ -90,19 +125,94 @@ static ssize_t sof_msg_inject_dfs_write(struct file *file, const char __user *bu
} }
/* send the message */ /* send the message */
memset(priv->rx_buffer, 0, SOF_IPC_MSG_MAX_SIZE);
ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer, priv->rx_buffer, ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer, priv->rx_buffer,
SOF_IPC_MSG_MAX_SIZE); priv->max_msg_size);
if (ret)
dev_err(dev, "IPC message send failed: %d\n", ret);
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
err = pm_runtime_put_autosuspend(dev); err = pm_runtime_put_autosuspend(dev);
if (err < 0) if (err < 0)
dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
/* return size if test is successful */
if (ret >= 0)
ret = size;
return ret; return ret;
}
static ssize_t sof_msg_inject_dfs_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct sof_client_dev *cdev = file->private_data;
struct sof_msg_inject_priv *priv = cdev->data;
size_t size;
int ret;
if (*ppos)
return 0;
size = simple_write_to_buffer(priv->tx_buffer, priv->max_msg_size,
ppos, buffer, count);
if (size != count)
return size > 0 ? -EFAULT : size;
memset(priv->rx_buffer, 0, priv->max_msg_size);
ret = sof_msg_inject_send_message(cdev);
/* return the error code if test failed */
if (ret < 0)
size = ret;
return size;
};
static ssize_t sof_msg_inject_ipc4_dfs_write(struct file *file,
const char __user *buffer,
size_t count, loff_t *ppos)
{
struct sof_client_dev *cdev = file->private_data;
struct sof_msg_inject_priv *priv = cdev->data;
struct sof_ipc4_msg *ipc4_msg = priv->tx_buffer;
size_t size;
int ret;
if (*ppos)
return 0;
if (count < sizeof(ipc4_msg->header_u64))
return -EINVAL;
/* copy the header first */
size = simple_write_to_buffer(&ipc4_msg->header_u64,
sizeof(ipc4_msg->header_u64),
ppos, buffer, count);
if (size != sizeof(ipc4_msg->header_u64))
return size > 0 ? -EFAULT : size;
count -= size;
if (!count) {
/* Copy the payload */
size = simple_write_to_buffer(ipc4_msg->data_ptr,
priv->max_msg_size, ppos, buffer,
count);
if (size != count)
return size > 0 ? -EFAULT : size;
}
ipc4_msg->data_size = count;
/* Initialize the reply storage */
ipc4_msg = priv->rx_buffer;
ipc4_msg->header_u64 = 0;
ipc4_msg->data_size = priv->max_msg_size;
memset(ipc4_msg->data_ptr, 0, priv->max_msg_size);
ret = sof_msg_inject_send_message(cdev);
/* return the error code if test failed */
if (ret < 0)
size = ret;
return size;
}; };
static int sof_msg_inject_dfs_release(struct inode *inode, struct file *file) static int sof_msg_inject_dfs_release(struct inode *inode, struct file *file)
...@@ -122,28 +232,61 @@ static const struct file_operations sof_msg_inject_fops = { ...@@ -122,28 +232,61 @@ static const struct file_operations sof_msg_inject_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static const struct file_operations sof_msg_inject_ipc4_fops = {
.open = sof_msg_inject_dfs_open,
.read = sof_msg_inject_ipc4_dfs_read,
.write = sof_msg_inject_ipc4_dfs_write,
.llseek = default_llseek,
.release = sof_msg_inject_dfs_release,
.owner = THIS_MODULE,
};
static int sof_msg_inject_probe(struct auxiliary_device *auxdev, static int sof_msg_inject_probe(struct auxiliary_device *auxdev,
const struct auxiliary_device_id *id) const struct auxiliary_device_id *id)
{ {
struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev); struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev);
static const struct file_operations *fops;
struct device *dev = &auxdev->dev; struct device *dev = &auxdev->dev;
struct sof_msg_inject_priv *priv; struct sof_msg_inject_priv *priv;
size_t alloc_size;
/* allocate memory for client data */ /* allocate memory for client data */
priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
priv->tx_buffer = devm_kmalloc(dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); priv->ipc_type = sof_client_get_ipc_type(cdev);
priv->rx_buffer = devm_kzalloc(dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); priv->max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
alloc_size = priv->max_msg_size;
if (priv->ipc_type == SOF_INTEL_IPC4)
alloc_size += sizeof(struct sof_ipc4_msg);
priv->tx_buffer = devm_kmalloc(dev, alloc_size, GFP_KERNEL);
priv->rx_buffer = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
if (!priv->tx_buffer || !priv->rx_buffer) if (!priv->tx_buffer || !priv->rx_buffer)
return -ENOMEM; return -ENOMEM;
if (priv->ipc_type == SOF_INTEL_IPC4) {
struct sof_ipc4_msg *ipc4_msg;
ipc4_msg = priv->tx_buffer;
ipc4_msg->data_ptr = priv->tx_buffer + sizeof(struct sof_ipc4_msg);
ipc4_msg = priv->rx_buffer;
ipc4_msg->data_ptr = priv->rx_buffer + sizeof(struct sof_ipc4_msg);
fops = &sof_msg_inject_ipc4_fops;
} else {
fops = &sof_msg_inject_fops;
}
cdev->data = priv; cdev->data = priv;
priv->dfs_file = debugfs_create_file("ipc_msg_inject", 0644, debugfs_root, priv->dfs_file = debugfs_create_file("ipc_msg_inject", 0644, debugfs_root,
cdev, &sof_msg_inject_fops); cdev, fops);
/* enable runtime PM */ /* enable runtime PM */
pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS); pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS);
......
...@@ -132,6 +132,7 @@ static int sof_probes_deinit(struct sof_client_dev *cdev) ...@@ -132,6 +132,7 @@ static int sof_probes_deinit(struct sof_client_dev *cdev)
static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd, static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
void **params, size_t *num_params) void **params, size_t *num_params)
{ {
size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
struct sof_ipc_probe_info_params msg = {{{0}}}; struct sof_ipc_probe_info_params msg = {{{0}}};
struct sof_ipc_probe_info_params *reply; struct sof_ipc_probe_info_params *reply;
size_t bytes; size_t bytes;
...@@ -140,13 +141,13 @@ static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd, ...@@ -140,13 +141,13 @@ static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
*params = NULL; *params = NULL;
*num_params = 0; *num_params = 0;
reply = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); reply = kzalloc(max_msg_size, GFP_KERNEL);
if (!reply) if (!reply)
return -ENOMEM; return -ENOMEM;
msg.rhdr.hdr.size = sizeof(msg); msg.rhdr.hdr.size = sizeof(msg);
msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd; msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
ret = sof_client_ipc_tx_message(cdev, &msg, reply, SOF_IPC_MSG_MAX_SIZE); ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size);
if (ret < 0 || reply->rhdr.error < 0) if (ret < 0 || reply->rhdr.error < 0)
goto exit; goto exit;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/sof/ipc4/header.h>
#include "ops.h" #include "ops.h"
#include "sof-client.h" #include "sof-client.h"
#include "sof-priv.h" #include "sof-priv.h"
...@@ -72,6 +73,9 @@ static int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) ...@@ -72,6 +73,9 @@ static int sof_register_ipc_flood_test(struct snd_sof_dev *sdev)
int ret = 0; int ret = 0;
int i; int i;
if (sdev->pdata->ipc_type != SOF_IPC)
return 0;
for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) { for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) {
ret = sof_client_dev_register(sdev, "ipc_flood", i, NULL, 0); ret = sof_client_dev_register(sdev, "ipc_flood", i, NULL, 0);
if (ret < 0) if (ret < 0)
...@@ -245,10 +249,19 @@ EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT); ...@@ -245,10 +249,19 @@ EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT);
int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
void *reply_data, size_t reply_bytes) void *reply_data, size_t reply_bytes)
{ {
struct sof_ipc_cmd_hdr *hdr = ipc_msg; if (cdev->sdev->pdata->ipc_type == SOF_IPC) {
struct sof_ipc_cmd_hdr *hdr = ipc_msg;
return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, hdr->size,
reply_data, reply_bytes);
} else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
struct sof_ipc4_msg *msg = ipc_msg;
return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, hdr->size, return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, msg->data_size,
reply_data, reply_bytes); reply_data, reply_bytes);
}
return -EINVAL;
} }
EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT);
...@@ -319,6 +332,22 @@ const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev ...@@ -319,6 +332,22 @@ const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev
} }
EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT);
size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
return sdev->ipc->max_payload_size;
}
EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, SND_SOC_SOF_CLIENT);
enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
return sdev->pdata->ipc_type;
}
EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, SND_SOC_SOF_CLIENT);
/* module refcount management of SOF core */ /* module refcount management of SOF core */
int sof_client_core_module_get(struct sof_client_dev *cdev) int sof_client_core_module_get(struct sof_client_dev *cdev)
{ {
...@@ -342,9 +371,22 @@ EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); ...@@ -342,9 +371,22 @@ EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT);
/* IPC event handling */ /* IPC event handling */
void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf)
{ {
struct sof_ipc_cmd_hdr *hdr = msg_buf;
u32 msg_type = hdr->cmd & SOF_GLB_TYPE_MASK;
struct sof_ipc_event_entry *event; struct sof_ipc_event_entry *event;
u32 msg_type;
if (sdev->pdata->ipc_type == SOF_IPC) {
struct sof_ipc_cmd_hdr *hdr = msg_buf;
msg_type = hdr->cmd & SOF_GLB_TYPE_MASK;
} else if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
struct sof_ipc4_msg *msg = msg_buf;
msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary);
} else {
dev_dbg_once(sdev->dev, "%s: Not supported IPC version: %d\n",
__func__, sdev->pdata->ipc_type);
return;
}
mutex_lock(&sdev->client_event_handler_mutex); mutex_lock(&sdev->client_event_handler_mutex);
...@@ -363,9 +405,21 @@ int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, ...@@ -363,9 +405,21 @@ int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev,
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct sof_ipc_event_entry *event; struct sof_ipc_event_entry *event;
if (!callback || !(ipc_msg_type & SOF_GLB_TYPE_MASK)) if (!callback)
return -EINVAL; return -EINVAL;
if (cdev->sdev->pdata->ipc_type == SOF_IPC) {
if (!(ipc_msg_type & SOF_GLB_TYPE_MASK))
return -EINVAL;
} else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
if (!(ipc_msg_type & SOF_IPC4_NOTIFICATION_TYPE_MASK))
return -EINVAL;
} else {
dev_warn(sdev->dev, "%s: Not supported IPC version: %d\n",
__func__, sdev->pdata->ipc_type);
return -EINVAL;
}
event = kmalloc(sizeof(*event), GFP_KERNEL); event = kmalloc(sizeof(*event), GFP_KERNEL);
if (!event) if (!event)
return -ENOMEM; return -ENOMEM;
......
...@@ -41,6 +41,8 @@ int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, ...@@ -41,6 +41,8 @@ int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev); struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev);
struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev); struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev);
const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev); const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev);
size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev);
enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev);
/* module refcount management of SOF core */ /* module refcount management of SOF core */
int sof_client_core_module_get(struct sof_client_dev *cdev); int sof_client_core_module_get(struct sof_client_dev *cdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment