[PATCH 2/6] ASoC: SOF: Introduce descriptors for SOF client
Greg KH
gregkh at linuxfoundation.org
Thu Oct 1 15:02:45 CEST 2020
On Wed, Sep 30, 2020 at 03:50:47PM -0700, Dave Ertman wrote:
> From: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
>
> A client in the SOF (Sound Open Firmware) context is a
> device that needs to communicate with the DSP via IPC
> messages. The SOF core is responsible for serializing the
> IPC messages to the DSP from the different clients. One
> example of an SOF client would be an IPC test client that
> floods the DSP with test IPC messages to validate if the
> serialization works as expected. Multi-client support will
> also add the ability to split the existing audio cards
> into multiple ones, so as to e.g. to deal with HDMI with a
> dedicated client instead of adding HDMI to all cards.
>
> This patch introduces descriptors for SOF client driver
> and SOF client device along with APIs for registering
> and unregistering a SOF client driver, sending IPCs from
> a client device and accessing the SOF core debugfs root entry.
>
> Along with this, add a couple of new members to struct
> snd_sof_dev that will be used for maintaining the list of
> clients.
>
> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> Co-developed-by: Fred Oh <fred.oh at linux.intel.com>
> Signed-off-by: Fred Oh <fred.oh at linux.intel.com>
> Signed-off-by: Dave Ertman <david.m.ertman at intel.com>
> ---
> sound/soc/sof/Kconfig | 19 ++++++
> sound/soc/sof/Makefile | 3 +
> sound/soc/sof/core.c | 2 +
> sound/soc/sof/sof-client.c | 117 +++++++++++++++++++++++++++++++++++++
> sound/soc/sof/sof-client.h | 65 +++++++++++++++++++++
> sound/soc/sof/sof-priv.h | 6 ++
> 6 files changed, 212 insertions(+)
> create mode 100644 sound/soc/sof/sof-client.c
> create mode 100644 sound/soc/sof/sof-client.h
As you are creating new sysfs directories, you should have some
documentation for them :(
>
> diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
> index 4dda4b62509f..cea7efedafef 100644
> --- a/sound/soc/sof/Kconfig
> +++ b/sound/soc/sof/Kconfig
> @@ -50,6 +50,24 @@ config SND_SOC_SOF_DEBUG_PROBES
> Say Y if you want to enable probes.
> If unsure, select "N".
>
> +config SND_SOC_SOF_CLIENT
> + tristate
> + select ANCILLARY_BUS
> + help
> + This option is not user-selectable but automagically handled by
> + 'select' statements at a higher level
> +
> +config SND_SOC_SOF_CLIENT_SUPPORT
> + bool "SOF enable clients"
> + depends on SND_SOC_SOF
> + help
> + This adds support for ancillary client devices to separate out the debug
> + functionality for IPC tests, probes etc. into separate devices. This
> + option would also allow adding client devices based on DSP FW
> + capabilities and ACPI/OF device information.
> + Say Y if you want to enable clients with SOF.
> + If unsure select "N".
> +
> config SND_SOC_SOF_DEVELOPER_SUPPORT
> bool "SOF developer options support"
> depends on EXPERT
> @@ -186,6 +204,7 @@ endif ## SND_SOC_SOF_DEVELOPER_SUPPORT
>
> config SND_SOC_SOF
> tristate
> + select SND_SOC_SOF_CLIENT if SND_SOC_SOF_CLIENT_SUPPORT
> select SND_SOC_TOPOLOGY
> select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
> help
> diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
> index 05718dfe6cd2..5e46f25a3851 100644
> --- a/sound/soc/sof/Makefile
> +++ b/sound/soc/sof/Makefile
> @@ -2,6 +2,7 @@
>
> snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
> control.o trace.o utils.o sof-audio.o
> +snd-sof-client-objs := sof-client.o
> snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += probe.o compress.o
>
> snd-sof-pci-objs := sof-pci-dev.o
> @@ -18,6 +19,8 @@ obj-$(CONFIG_SND_SOC_SOF_ACPI) += snd-sof-acpi.o
> obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o
> obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o
>
> +obj-$(CONFIG_SND_SOC_SOF_CLIENT) += snd-sof-client.o
> +
> obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/
> obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/
> obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/
> diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
> index adc7c37145d6..72a97219395f 100644
> --- a/sound/soc/sof/core.c
> +++ b/sound/soc/sof/core.c
> @@ -314,8 +314,10 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
> INIT_LIST_HEAD(&sdev->widget_list);
> INIT_LIST_HEAD(&sdev->dai_list);
> INIT_LIST_HEAD(&sdev->route_list);
> + INIT_LIST_HEAD(&sdev->client_list);
> spin_lock_init(&sdev->ipc_lock);
> spin_lock_init(&sdev->hw_lock);
> + mutex_init(&sdev->client_mutex);
>
> if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
> INIT_WORK(&sdev->probe_work, sof_probe_work);
> diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c
> new file mode 100644
> index 000000000000..f7e476d99ff6
> --- /dev/null
> +++ b/sound/soc/sof/sof-client.c
> @@ -0,0 +1,117 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +//
> +// Copyright(c) 2020 Intel Corporation. All rights reserved.
> +//
> +// Author: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> +//
> +
> +#include <linux/debugfs.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include "sof-client.h"
> +#include "sof-priv.h"
> +
> +static void sof_client_ancildev_release(struct device *dev)
> +{
> + struct ancillary_device *ancildev = to_ancillary_dev(dev);
> + struct sof_client_dev *cdev = ancillary_dev_to_sof_client_dev(ancildev);
> +
> + ida_simple_remove(cdev->client_ida, ancildev->id);
> + kfree(cdev);
> +}
> +
> +static struct sof_client_dev *sof_client_dev_alloc(struct snd_sof_dev *sdev, const char *name,
> + struct ida *client_ida)
> +{
> + struct sof_client_dev *cdev;
> + struct ancillary_device *ancildev;
> + int ret;
> +
> + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
> + if (!cdev)
> + return NULL;
> +
> + cdev->sdev = sdev;
No reference counting? How can you guarantee the lifespan is ok?
> + cdev->client_ida = client_ida;
> + ancildev = &cdev->ancildev;
> + ancildev->name = name;
> + ancildev->dev.parent = sdev->dev;
Ah, you guarantee it by making it the parent. Sneaky, but is it really
needed?
> + ancildev->dev.release = sof_client_ancildev_release;
> +
> + ancildev->id = ida_alloc(client_ida, GFP_KERNEL);
> + if (ancildev->id < 0) {
> + dev_err(sdev->dev, "error: get IDA idx for ancillary device %s failed\n", name);
> + ret = ancildev->id;
> + goto err_free;
> + }
> +
> + ret = ancillary_device_initialize(ancildev);
> + if (ret < 0) {
> + dev_err(sdev->dev, "error: failed to initialize client dev %s\n", name);
> + ida_simple_remove(client_ida, ancildev->id);
> + goto err_free;
> + }
> +
> + return cdev;
> +
> +err_free:
> + kfree(cdev);
> + return NULL;
> +}
> +
> +int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, struct ida *client_ida)
> +{
> + struct sof_client_dev *cdev;
> + int ret;
> +
> + cdev = sof_client_dev_alloc(sdev, name, client_ida);
> + if (!cdev)
> + return -ENODEV;
> +
> + ret = ancillary_device_add(&cdev->ancildev);
Why have you split this up into two calls? Why not just
"sof_client_dev_create() or something like that?
Having to make a sof_* call, and then a separate ancillary_device_* call
feels pretty ackward, right?
> + if (ret < 0) {
> + dev_err(sdev->dev, "error: failed to add client dev %s\n", name);
> + put_device(&cdev->ancildev.dev);
Ugh that's a deep knowledge of the ancil code, would be nicer if the
caller function handled all of that for you, right?
> + return ret;
> + }
> +
> + /* add to list of SOF client devices */
> + mutex_lock(&sdev->client_mutex);
> + list_add(&cdev->list, &sdev->client_list);
> + mutex_unlock(&sdev->client_mutex);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT);
> +
> +void sof_client_dev_unregister(struct sof_client_dev *cdev)
> +{
> + struct snd_sof_dev *sdev = cdev->sdev;
> +
> + /* remove from list of SOF client devices */
> + mutex_lock(&sdev->client_mutex);
> + list_del(&cdev->list);
> + mutex_unlock(&sdev->client_mutex);
So you add and remove things from the list, but do not do anything with
that list? Why a list at all?
> +
> + ancillary_device_unregister(&cdev->ancildev);
Does this free the expected memory? I think so, but commenting that it
does is nice :)
> +}
> +EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT);
> +
> +int sof_client_ipc_tx_message(struct sof_client_dev *cdev, u32 header, void *msg_data,
> + size_t msg_bytes, void *reply_data, size_t reply_bytes)
> +{
> + return sof_ipc_tx_message(cdev->sdev->ipc, header, msg_data, msg_bytes,
> + reply_data, reply_bytes);
> +}
> +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT);
> +
> +struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev)
> +{
> + return cdev->sdev->debugfs_root;
> +}
> +EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, SND_SOC_SOF_CLIENT);
> +
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h
> new file mode 100644
> index 000000000000..62212f69c236
> --- /dev/null
> +++ b/sound/soc/sof/sof-client.h
> @@ -0,0 +1,65 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only) */
Why the "()"?
thanks,
greg k-h
More information about the Alsa-devel
mailing list