summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2025-08-29 23:19:49 +0100
committerMark Brown <broonie@kernel.org>2025-08-29 23:19:49 +0100
commit0e58316d6a877231b3ece367ab9b445cb429b8ba (patch)
treed7f73e13ef4c904071562b6148126f1feede119d
parent0b1d93750f1c771c92b26832d5a6bdd6641dee03 (diff)
parentd57d27171c92e9049d5301785fb38de127b28fbf (diff)
ASoC: SOF: sof-client-probes-ipc4: Query available
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>: This series improves the IPC4 probes implementation by improving the report quality and adds support for querying the available probes on the firmware side.
-rw-r--r--include/sound/sof/ipc4/header.h4
-rw-r--r--sound/soc/sof/sof-client-probes-ipc3.c25
-rw-r--r--sound/soc/sof/sof-client-probes-ipc4.c134
-rw-r--r--sound/soc/sof/sof-client-probes.c58
-rw-r--r--sound/soc/sof/sof-client-probes.h9
-rw-r--r--sound/soc/sof/sof-client.c13
-rw-r--r--sound/soc/sof/sof-client.h2
7 files changed, 220 insertions, 25 deletions
diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h
index e85c7afd85a4..15fac532688e 100644
--- a/include/sound/sof/ipc4/header.h
+++ b/include/sound/sof/ipc4/header.h
@@ -326,10 +326,14 @@ struct sof_ipc4_base_module_cfg {
#define SOF_IPC4_MOD_INSTANCE_SHIFT 16
#define SOF_IPC4_MOD_INSTANCE_MASK GENMASK(23, 16)
#define SOF_IPC4_MOD_INSTANCE(x) ((x) << SOF_IPC4_MOD_INSTANCE_SHIFT)
+#define SOF_IPC4_MOD_INSTANCE_GET(x) (((x) & SOF_IPC4_MOD_INSTANCE_MASK) \
+ >> SOF_IPC4_MOD_INSTANCE_SHIFT)
#define SOF_IPC4_MOD_ID_SHIFT 0
#define SOF_IPC4_MOD_ID_MASK GENMASK(15, 0)
#define SOF_IPC4_MOD_ID(x) ((x) << SOF_IPC4_MOD_ID_SHIFT)
+#define SOF_IPC4_MOD_ID_GET(x) (((x) & SOF_IPC4_MOD_ID_MASK) \
+ >> SOF_IPC4_MOD_ID_SHIFT)
/* init module ipc msg */
#define SOF_IPC4_MOD_EXT_PARAM_SIZE_SHIFT 0
diff --git a/sound/soc/sof/sof-client-probes-ipc3.c b/sound/soc/sof/sof-client-probes-ipc3.c
index 816df745c9af..a78ec0954a61 100644
--- a/sound/soc/sof/sof-client-probes-ipc3.c
+++ b/sound/soc/sof/sof-client-probes-ipc3.c
@@ -100,9 +100,11 @@ static int ipc3_probes_deinit(struct sof_client_dev *cdev)
}
static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
- void **params, size_t *num_params)
+ void **params, size_t *num_params,
+ enum sof_probe_info_type type)
{
size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
+ struct device *dev = &cdev->auxdev.dev;
struct sof_ipc_probe_info_params msg = {{{0}}};
struct sof_ipc_probe_info_params *reply;
size_t bytes;
@@ -111,6 +113,11 @@ static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
*params = NULL;
*num_params = 0;
+ if (type != PROBES_INFO_ACTIVE_PROBES) {
+ dev_err(dev, "%s: info type %u not supported", __func__, type);
+ return -EOPNOTSUPP;
+ }
+
reply = kzalloc(max_msg_size, GFP_KERNEL);
if (!reply)
return -ENOMEM;
@@ -142,21 +149,25 @@ exit:
}
/**
- * ipc3_probes_points_info - retrieve list of active probe points
+ * ipc3_probes_points_info - retrieve list of probe points
* @cdev: SOF client device
* @desc: Returned list of active probes
* @num_desc: Returned count of active probes
+ * @type: Either PROBES_INFO_ACTIVE_PROBES or PROBES_INFO_AVAILABE_PROBES
+ *
+ * If type is PROBES_INFO_ACTIVE_PROBES, host sends PROBE_POINT_INFO
+ * request to obtain list of active probe points, valid for
+ * disconnection when given probe is no longer required.
*
- * Host sends PROBE_POINT_INFO request to obtain list of active probe
- * points, valid for disconnection when given probe is no longer
- * required.
+ * Type PROBES_INFO_AVAILABE_PROBES is not yet supported.
*/
static int ipc3_probes_points_info(struct sof_client_dev *cdev,
struct sof_probe_point_desc **desc,
- size_t *num_desc)
+ size_t *num_desc,
+ enum sof_probe_info_type type)
{
return ipc3_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO,
- (void **)desc, num_desc);
+ (void **)desc, num_desc, type);
}
/**
diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c
index 603aed222480..758a56d271d7 100644
--- a/sound/soc/sof/sof-client-probes-ipc4.c
+++ b/sound/soc/sof/sof-client-probes-ipc4.c
@@ -8,7 +8,7 @@
#include <sound/soc.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
-#include "sof-priv.h"
+#include "sof-audio.h"
#include "ipc4-priv.h"
#include "sof-client.h"
#include "sof-client-probes.h"
@@ -28,6 +28,7 @@ enum sof_ipc4_probe_runtime_param {
SOF_IPC4_PROBE_INJECTION_DMA_DETACH,
SOF_IPC4_PROBE_POINTS,
SOF_IPC4_PROBE_POINTS_DISCONNECT,
+ SOF_IPC4_PROBE_POINTS_AVAILABLE,
};
struct sof_ipc4_probe_gtw_cfg {
@@ -49,14 +50,42 @@ enum sof_ipc4_probe_type {
SOF_IPC4_PROBE_TYPE_INTERNAL
};
+#define SOF_IPC4_PROBE_TYPE_SHIFT 24
+#define SOF_IPC4_PROBE_TYPE_MASK GENMASK(25, 24)
+#define SOF_IPC4_PROBE_TYPE_GET(x) (((x) & SOF_IPC4_PROBE_TYPE_MASK) \
+ >> SOF_IPC4_PROBE_TYPE_SHIFT)
+#define SOF_IPC4_PROBE_IDX_SHIFT 26
+#define SOF_IPC4_PROBE_IDX_MASK GENMASK(31, 26)
+#define SOF_IPC4_PROBE_IDX_GET(x) (((x) & SOF_IPC4_PROBE_IDX_MASK) \
+ >> SOF_IPC4_PROBE_IDX_SHIFT)
+
struct sof_ipc4_probe_point {
u32 point_id;
u32 purpose;
u32 stream_tag;
} __packed __aligned(4);
+struct sof_ipc4_probe_info {
+ unsigned int num_elems;
+ DECLARE_FLEX_ARRAY(struct sof_ipc4_probe_point, points);
+} __packed;
+
#define INVALID_PIPELINE_ID 0xFF
+static const char *sof_probe_ipc4_type_string(u32 type)
+{
+ switch (type) {
+ case SOF_IPC4_PROBE_TYPE_INPUT:
+ return "input";
+ case SOF_IPC4_PROBE_TYPE_OUTPUT:
+ return "output";
+ case SOF_IPC4_PROBE_TYPE_INTERNAL:
+ return "internal";
+ default:
+ return "UNKNOWN";
+ }
+}
+
/**
* sof_ipc4_probe_get_module_info - Get IPC4 module info for probe module
* @cdev: SOF client device
@@ -164,25 +193,113 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev)
}
/**
- * ipc4_probes_points_info - retrieve list of active probe points
+ * ipc4_probes_points_info - retrieve list of probe points
* @cdev: SOF client device
* @desc: Returned list of active probes
* @num_desc: Returned count of active probes
+ * @type: Either PROBES_INFO_ACTIVE_PROBES or PROBES_INFO_AVAILABE_PROBES
* @return: 0 on success, negative error code on error
*
- * Dummy implementation returning empty list of probes.
+ * Returns list if active probe points if type is
+ * PROBES_INFO_ACTIVE_PROBES, or list of all available probe points if
+ * type is PROBES_INFO_AVAILABE_PROBES.
*/
static int ipc4_probes_points_info(struct sof_client_dev *cdev,
struct sof_probe_point_desc **desc,
- size_t *num_desc)
+ size_t *num_desc,
+ enum sof_probe_info_type type)
{
- /* TODO: Firmware side implementation needed first */
- *desc = NULL;
- *num_desc = 0;
+ struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+ struct device *dev = &cdev->auxdev.dev;
+ struct sof_ipc4_probe_info *info;
+ struct sof_ipc4_msg msg;
+ u32 param_id;
+ int i, ret;
+
+ if (!mentry)
+ return -ENODEV;
+
+ switch (type) {
+ case PROBES_INFO_ACTIVE_PROBES:
+ param_id = SOF_IPC4_PROBE_POINTS;
+ break;
+ case PROBES_INFO_AVAILABE_PROBES:
+ param_id = SOF_IPC4_PROBE_POINTS_AVAILABLE;
+ break;
+ default:
+ dev_err(dev, "%s: info type %u not supported", __func__, type);
+ return -EOPNOTSUPP;
+ }
+
+ msg.primary = mentry->id;
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(param_id);
+
+ msg.data_size = sof_client_get_ipc_max_payload_size(cdev);
+ msg.data_ptr = kzalloc(msg.data_size, GFP_KERNEL);
+ if (!msg.data_ptr)
+ return -ENOMEM;
+
+ ret = sof_client_ipc_set_get_data(cdev, &msg, false);
+ if (ret) {
+ kfree(msg.data_ptr);
+ return ret;
+ }
+ info = msg.data_ptr;
+ *num_desc = info->num_elems;
+ dev_dbg(dev, "%s: got %zu probe points", __func__, *num_desc);
+
+ *desc = kzalloc(*num_desc * sizeof(**desc), GFP_KERNEL);
+ if (!*desc) {
+ kfree(msg.data_ptr);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < *num_desc; i++) {
+ (*desc)[i].buffer_id = info->points[i].point_id;
+ (*desc)[i].purpose = info->points[i].purpose;
+ (*desc)[i].stream_tag = info->points[i].stream_tag;
+ }
+ kfree(msg.data_ptr);
+
return 0;
}
/**
+ * ipc4_probes_point_print - Human readable print of probe point descriptor
+ * @cdev: SOF client device
+ * @buf: Buffer to print to
+ * @size: Available bytes in buffer
+ * @desc: Describes the probe point to print
+ * @return: Number of bytes printed or an error code (snprintf return value)
+ */
+static int ipc4_probes_point_print(struct sof_client_dev *cdev, char *buf, size_t size,
+ struct sof_probe_point_desc *desc)
+{
+ struct device *dev = &cdev->auxdev.dev;
+ struct snd_sof_widget *swidget;
+ int ret;
+
+ swidget = sof_client_ipc4_find_swidget_by_id(cdev, SOF_IPC4_MOD_ID_GET(desc->buffer_id),
+ SOF_IPC4_MOD_INSTANCE_GET(desc->buffer_id));
+ if (!swidget)
+ dev_err(dev, "%s: Failed to find widget for module %lu.%lu\n",
+ __func__, SOF_IPC4_MOD_ID_GET(desc->buffer_id),
+ SOF_IPC4_MOD_INSTANCE_GET(desc->buffer_id));
+
+ ret = snprintf(buf, size, "%#x,%#x,%#x\t%s %s buf idx %lu %s\n",
+ desc->buffer_id, desc->purpose, desc->stream_tag,
+ swidget ? swidget->widget->name : "<unknown>",
+ sof_probe_ipc4_type_string(SOF_IPC4_PROBE_TYPE_GET(desc->buffer_id)),
+ SOF_IPC4_PROBE_IDX_GET(desc->buffer_id),
+ desc->stream_tag ? "(connected)" : "");
+
+ return ret;
+}
+
+/**
* ipc4_probes_points_add - connect specified probes
* @cdev: SOF client device
* @desc: List of probe points to connect
@@ -202,7 +319,7 @@ static int ipc4_probes_points_add(struct sof_client_dev *cdev,
int i, ret;
if (!mentry)
- return -ENODEV;
+ return -EOPNOTSUPP;
/* The sof_probe_point_desc and sof_ipc4_probe_point structs
* are of same size and even the integers are the same in the
@@ -286,6 +403,7 @@ const struct sof_probes_ipc_ops ipc4_probe_ops = {
.init = ipc4_probes_init,
.deinit = ipc4_probes_deinit,
.points_info = ipc4_probes_points_info,
+ .point_print = ipc4_probes_point_print,
.points_add = ipc4_probes_points_add,
.points_remove = ipc4_probes_points_remove,
};
diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c
index 663c0d3c314c..3ca8460774bb 100644
--- a/sound/soc/sof/sof-client-probes.c
+++ b/sound/soc/sof/sof-client-probes.c
@@ -17,8 +17,14 @@
#include <sound/soc.h>
#include <sound/sof/header.h>
+#include <sound/sof/ipc4/header.h>
#include "sof-client.h"
#include "sof-client-probes.h"
+#include "sof-audio.h"
+
+#ifdef CONFIG_SND_SOC_SOF_IPC4
+#include "ipc4-priv.h"
+#endif
#define SOF_PROBES_SUSPEND_DELAY_MS 3000
/* only extraction supported for now */
@@ -69,7 +75,8 @@ static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream,
int i, ret;
/* disconnect all probe points */
- ret = ipc->points_info(cdev, &desc, &num_desc);
+ ret = ipc->points_info(cdev, &desc, &num_desc,
+ PROBES_INFO_ACTIVE_PROBES);
if (ret < 0) {
dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
goto exit;
@@ -189,7 +196,8 @@ static const struct snd_compress_ops sof_probes_compressed_ops = {
};
static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos,
+ enum sof_probe_info_type type)
{
struct sof_client_dev *cdev = file->private_data;
struct sof_probes_priv *priv = cdev->data;
@@ -216,16 +224,20 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
goto exit;
}
- ret = ipc->points_info(cdev, &desc, &num_desc);
+ ret = ipc->points_info(cdev, &desc, &num_desc, type);
if (ret < 0)
goto pm_error;
for (i = 0; i < num_desc; i++) {
offset = strlen(buf);
remaining = PAGE_SIZE - offset;
- ret = snprintf(buf + offset, remaining,
- "Id: %#010x Purpose: %u Node id: %#x\n",
- desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag);
+ if (ipc->point_print)
+ ret = ipc->point_print(cdev, buf + offset, remaining, &desc[i]);
+ else
+ ret = snprintf(buf + offset, remaining,
+ "Id: %#010x Purpose: %u Node id: %#x\n",
+ desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag);
+
if (ret < 0 || ret >= remaining) {
/* truncate the output buffer at the last full line */
buf[offset] = '\0';
@@ -247,6 +259,22 @@ exit:
return ret;
}
+static ssize_t sof_probes_dfs_active_points_read(struct file *file,
+ char __user *to,
+ size_t count, loff_t *ppos)
+{
+ return sof_probes_dfs_points_read(file, to, count, ppos,
+ PROBES_INFO_ACTIVE_PROBES);
+}
+
+static ssize_t sof_probes_dfs_available_points_read(struct file *file,
+ char __user *to,
+ size_t count, loff_t *ppos)
+{
+ return sof_probes_dfs_points_read(file, to, count, ppos,
+ PROBES_INFO_AVAILABE_PROBES);
+}
+
static ssize_t
sof_probes_dfs_points_write(struct file *file, const char __user *from,
size_t count, loff_t *ppos)
@@ -296,15 +324,23 @@ exit:
return ret;
}
-static const struct file_operations sof_probes_points_fops = {
+static const struct file_operations sof_probes_active_points_fops = {
.open = simple_open,
- .read = sof_probes_dfs_points_read,
+ .read = sof_probes_dfs_active_points_read,
.write = sof_probes_dfs_points_write,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
+static const struct file_operations sof_probes_available_points_fops = {
+ .open = simple_open,
+ .read = sof_probes_dfs_available_points_read,
+ .llseek = default_llseek,
+
+ .owner = THIS_MODULE,
+};
+
static ssize_t
sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
size_t count, loff_t *ppos)
@@ -449,13 +485,17 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
/* create read-write probes_points debugfs entry */
priv->dfs_points = debugfs_create_file("probe_points", 0644, dfsroot,
- cdev, &sof_probes_points_fops);
+ cdev, &sof_probes_active_points_fops);
/* create read-write probe_points_remove debugfs entry */
priv->dfs_points_remove = debugfs_create_file("probe_points_remove", 0644,
dfsroot, cdev,
&sof_probes_points_remove_fops);
+ /* create read-write probes_points debugfs entry */
+ priv->dfs_points = debugfs_create_file("probe_points_available", 0644, dfsroot,
+ cdev, &sof_probes_available_points_fops);
+
links = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*links), GFP_KERNEL);
cpus = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*cpus), GFP_KERNEL);
if (!links || !cpus) {
diff --git a/sound/soc/sof/sof-client-probes.h b/sound/soc/sof/sof-client-probes.h
index da04d65b8d99..5fb95553ea53 100644
--- a/sound/soc/sof/sof-client-probes.h
+++ b/sound/soc/sof/sof-client-probes.h
@@ -34,13 +34,20 @@ struct sof_probe_point_desc {
unsigned int stream_tag;
} __packed;
+enum sof_probe_info_type {
+ PROBES_INFO_ACTIVE_PROBES,
+ PROBES_INFO_AVAILABE_PROBES,
+};
+
struct sof_probes_ipc_ops {
int (*init)(struct sof_client_dev *cdev, u32 stream_tag,
size_t buffer_size);
int (*deinit)(struct sof_client_dev *cdev);
int (*points_info)(struct sof_client_dev *cdev,
struct sof_probe_point_desc **desc,
- size_t *num_desc);
+ size_t *num_desc, enum sof_probe_info_type type);
+ int (*point_print)(struct sof_client_dev *cdev, char *buf, size_t size,
+ struct sof_probe_point_desc *desc);
int (*points_add)(struct sof_client_dev *cdev,
struct sof_probe_point_desc *desc,
size_t num_desc);
diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c
index 12be97540e4c..2dbfc7699c73 100644
--- a/sound/soc/sof/sof-client.c
+++ b/sound/soc/sof/sof-client.c
@@ -380,6 +380,19 @@ struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c,
return NULL;
}
EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT");
+
+struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev,
+ u32 module_id, int instance_id)
+{
+ struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4)
+ return sof_ipc4_find_swidget_by_ids(sdev, module_id, instance_id);
+ dev_err(sdev->dev, "Only supported with IPC4\n");
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_swidget_by_id, "SND_SOC_SOF_CLIENT");
#endif
int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state)
diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h
index 6e9dd77f7c9b..1a9015e38474 100644
--- a/sound/soc/sof/sof-client.h
+++ b/sound/soc/sof/sof-client.h
@@ -41,6 +41,8 @@ int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg,
bool set);
struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *u);
+struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev,
+ u32 module_id, int instance_id);
struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev);
struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev);