Skip to content

Commit

Permalink
ASoC: SOF: Convert the generic probe support to SOF client
Browse files Browse the repository at this point in the history
Add a new client driver for probes support and move
all the probes-related code from the core to the
client driver.

The probes client driver registers a component driver
with one CPU DAI driver for extraction and creates a
new sound card with one DUMMY DAI link with a dummy codec
that will be used for extracting audio data from specific
points in the audio pipeline.

The probes debugfs ops are based on the initial
implementation by Cezary Rojewski and have been moved
out of the SOF core into the client driver making it
easier to maintain. This change will make it easier
for the probes functionality to be added for all platforms
without having the need to modify the existing(15+) machine
drivers.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
  • Loading branch information
ujfalusi authored and kv2019i committed Nov 23, 2021
1 parent bc6635b commit d5c4c30
Show file tree
Hide file tree
Showing 20 changed files with 967 additions and 825 deletions.
7 changes: 4 additions & 3 deletions sound/soc/sof/Kconfig
Expand Up @@ -53,13 +53,14 @@ config SND_SOC_SOF_COMPRESS
select SND_SOC_COMPRESS

config SND_SOC_SOF_DEBUG_PROBES
bool "SOF enable data probing"
tristate
select SND_SOC_SOF_CLIENT
select SND_SOC_COMPRESS
help
This option enables the data probing feature that can be used to
gather data directly from specific points of the audio pipeline.
Say Y if you want to enable probes.
If unsure, select "N".
This option is not user-selectable but automagically handled by
'select' statements at a higher level.

config SND_SOC_SOF_CLIENT
tristate
Expand Down
3 changes: 2 additions & 1 deletion sound/soc/sof/Makefile
Expand Up @@ -4,7 +4,6 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o ipc4.o
snd-sof-$(CONFIG_SND_SOC_SOF_CLIENT) += sof-client.o

snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o
snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o

snd-sof-pci-objs := sof-pci-dev.o
Expand All @@ -13,6 +12,7 @@ snd-sof-of-objs := sof-of-dev.o

snd-sof-ipc-flood-test-objs := sof-client-ipc-flood-test.o
snd-sof-ipc-msg-injector-objs := sof-client-ipc-msg-injector.o
snd-sof-probes-objs := sof-client-probes.o

snd-sof-nocodec-objs := nocodec.o

Expand All @@ -29,6 +29,7 @@ obj-$(CONFIG_SND_SOC_SOF_PCI_DEV) += snd-sof-pci.o

obj-$(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) += snd-sof-ipc-flood-test.o
obj-$(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) += snd-sof-ipc-msg-injector.o
obj-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += snd-sof-probes.o

obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/
obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/
Expand Down
6 changes: 0 additions & 6 deletions sound/soc/sof/core.c
Expand Up @@ -14,9 +14,6 @@
#include <sound/sof.h>
#include "sof-priv.h"
#include "ops.h"
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
#include "sof-probes.h"
#endif

/* see SOF_DBG_ flags */
static int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE);
Expand Down Expand Up @@ -358,9 +355,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)

sdev->pdata = plat_data;
sdev->first_boot = true;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
#endif
dev_set_drvdata(dev, sdev);

/* check all mandatory ops */
Expand Down
226 changes: 0 additions & 226 deletions sound/soc/sof/debug.c
Expand Up @@ -19,221 +19,6 @@
#include "sof-priv.h"
#include "ops.h"

#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
#include "sof-probes.h"

/**
* strsplit_u32 - Split string into sequence of u32 tokens
* @buf: String to split into tokens.
* @delim: String containing delimiter characters.
* @tkns: Returned u32 sequence pointer.
* @num_tkns: Returned number of tokens obtained.
*/
static int
strsplit_u32(char **buf, const char *delim, u32 **tkns, size_t *num_tkns)
{
char *s;
u32 *data, *tmp;
size_t count = 0;
size_t cap = 32;
int ret = 0;

*tkns = NULL;
*num_tkns = 0;
data = kcalloc(cap, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;

while ((s = strsep(buf, delim)) != NULL) {
ret = kstrtouint(s, 0, data + count);
if (ret)
goto exit;
if (++count >= cap) {
cap *= 2;
tmp = krealloc(data, cap * sizeof(*data), GFP_KERNEL);
if (!tmp) {
ret = -ENOMEM;
goto exit;
}
data = tmp;
}
}

if (!count)
goto exit;
*tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL);
if (*tkns == NULL) {
ret = -ENOMEM;
goto exit;
}
*num_tkns = count;

exit:
kfree(data);
return ret;
}

static int tokenize_input(const char __user *from, size_t count,
loff_t *ppos, u32 **tkns, size_t *num_tkns)
{
char *buf;
int ret;

buf = kmalloc(count + 1, GFP_KERNEL);
if (!buf)
return -ENOMEM;

ret = simple_write_to_buffer(buf, count, ppos, from, count);
if (ret != count) {
ret = ret >= 0 ? -EIO : ret;
goto exit;
}

buf[count] = '\0';
ret = strsplit_u32((char **)&buf, ",", tkns, num_tkns);
exit:
kfree(buf);
return ret;
}

static ssize_t probe_points_read(struct file *file,
char __user *to, size_t count, loff_t *ppos)
{
struct snd_sof_dfsentry *dfse = file->private_data;
struct snd_sof_dev *sdev = dfse->sdev;
struct sof_probe_point_desc *desc;
size_t num_desc, len = 0;
char *buf;
int i, ret;

if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
dev_warn(sdev->dev, "no extractor stream running\n");
return -ENOENT;
}

buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;

ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc);
if (ret < 0)
goto exit;

for (i = 0; i < num_desc; i++) {
ret = snprintf(buf + len, PAGE_SIZE - len,
"Id: %#010x Purpose: %d Node id: %#x\n",
desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag);
if (ret < 0)
goto free_desc;
len += ret;
}

ret = simple_read_from_buffer(to, count, ppos, buf, len);
free_desc:
kfree(desc);
exit:
kfree(buf);
return ret;
}

static ssize_t probe_points_write(struct file *file,
const char __user *from, size_t count, loff_t *ppos)
{
struct snd_sof_dfsentry *dfse = file->private_data;
struct snd_sof_dev *sdev = dfse->sdev;
struct sof_probe_point_desc *desc;
size_t num_tkns, bytes;
u32 *tkns;
int ret;

if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
dev_warn(sdev->dev, "no extractor stream running\n");
return -ENOENT;
}

ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
if (ret < 0)
return ret;
bytes = sizeof(*tkns) * num_tkns;
if (!num_tkns || (bytes % sizeof(*desc))) {
ret = -EINVAL;
goto exit;
}

desc = (struct sof_probe_point_desc *)tkns;
ret = sof_ipc_probe_points_add(sdev,
desc, bytes / sizeof(*desc));
if (!ret)
ret = count;
exit:
kfree(tkns);
return ret;
}

static const struct file_operations probe_points_fops = {
.open = simple_open,
.read = probe_points_read,
.write = probe_points_write,
.llseek = default_llseek,
};

static ssize_t probe_points_remove_write(struct file *file,
const char __user *from, size_t count, loff_t *ppos)
{
struct snd_sof_dfsentry *dfse = file->private_data;
struct snd_sof_dev *sdev = dfse->sdev;
size_t num_tkns;
u32 *tkns;
int ret;

if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
dev_warn(sdev->dev, "no extractor stream running\n");
return -ENOENT;
}

ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
if (ret < 0)
return ret;
if (!num_tkns) {
ret = -EINVAL;
goto exit;
}

ret = sof_ipc_probe_points_remove(sdev, tkns, num_tkns);
if (!ret)
ret = count;
exit:
kfree(tkns);
return ret;
}

static const struct file_operations probe_points_remove_fops = {
.open = simple_open,
.write = probe_points_remove_write,
.llseek = default_llseek,
};

static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev,
const char *name, mode_t mode,
const struct file_operations *fops)
{
struct snd_sof_dfsentry *dfse;

dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
if (!dfse)
return -ENOMEM;

dfse->type = SOF_DFSENTRY_TYPE_BUF;
dfse->sdev = sdev;

debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops);
/* add to dfsentry list */
list_add(&dfse->list, &sdev->dfsentry_list);

return 0;
}
#endif

static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
Expand Down Expand Up @@ -569,17 +354,6 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
return err;
}

#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
err = snd_sof_debugfs_probe_item(sdev, "probe_points",
0644, &probe_points_fops);
if (err < 0)
return err;
err = snd_sof_debugfs_probe_item(sdev, "probe_points_remove",
0200, &probe_points_remove_fops);
if (err < 0)
return err;
#endif

return 0;
}
EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
Expand Down
19 changes: 10 additions & 9 deletions sound/soc/sof/intel/Kconfig
Expand Up @@ -215,6 +215,7 @@ config SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_PCI_DEV
select SND_INTEL_DSP_CONFIG
select SND_SOC_SOF_HDA_LINK_BASELINE
select SND_SOC_SOF_HDA_PROBES
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level.
Expand All @@ -240,15 +241,6 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
Say Y if you want to enable HDAudio codecs with SOF.
If unsure select "N".

config SND_SOC_SOF_HDA_PROBES
bool "SOF enable probes over HDA"
depends on SND_SOC_SOF_DEBUG_PROBES
help
This option enables the data probing for Intel(R)
Skylake and newer platforms.
Say Y if you want to enable probes.
If unsure, select "N".

endif ## SND_SOC_SOF_HDA_COMMON

config SND_SOC_SOF_HDA_LINK_BASELINE
Expand All @@ -266,6 +258,15 @@ config SND_SOC_SOF_HDA
This option is not user-selectable but automagically handled by
'select' statements at a higher level.

config SND_SOC_SOF_HDA_PROBES
bool
select SND_SOC_SOF_DEBUG_PROBES
help
The option enables the data probing for Intel(R) Skylake and newer
(HDA) platforms.
This option is not user-selectable but automagically handled by
'select' statements at a higher level.

config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
tristate
select SOUNDWIRE_INTEL if SND_SOC_SOF_INTEL_SOUNDWIRE
Expand Down
13 changes: 4 additions & 9 deletions sound/soc/sof/intel/apl.c
Expand Up @@ -80,15 +80,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
/* probe callbacks */
.probe_assign = hda_probe_compr_assign,
.probe_free = hda_probe_compr_free,
.probe_set_params = hda_probe_compr_set_params,
.probe_trigger = hda_probe_compr_trigger,
.probe_pointer = hda_probe_compr_pointer,
#endif

/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,

Expand All @@ -110,6 +101,10 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,

/* client ops */
.register_ipc_clients = hda_register_clients,
.unregister_ipc_clients = hda_unregister_clients,

/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
Expand Down
13 changes: 4 additions & 9 deletions sound/soc/sof/intel/cnl.c
Expand Up @@ -300,15 +300,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
/* probe callbacks */
.probe_assign = hda_probe_compr_assign,
.probe_free = hda_probe_compr_free,
.probe_set_params = hda_probe_compr_set_params,
.probe_trigger = hda_probe_compr_trigger,
.probe_pointer = hda_probe_compr_pointer,
#endif

/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,

Expand All @@ -330,6 +321,10 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,

/* client ops */
.register_ipc_clients = hda_register_clients,
.unregister_ipc_clients = hda_unregister_clients,

/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
Expand Down

0 comments on commit d5c4c30

Please sign in to comment.