From f4b3b713bd16f2fccfe71b2fcdef383c31927676 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:39 +0000 Subject: [PATCH 1/9] Revert "ASoC: SOF: Convert the generic probe support to SOF client" This reverts commit d5c4c30af5aa45fb574b8dec346db3ff5404146e. --- sound/soc/sof/Kconfig | 7 +- sound/soc/sof/Makefile | 3 +- sound/soc/sof/core.c | 6 + sound/soc/sof/debug.c | 226 ++++++++ sound/soc/sof/intel/Kconfig | 19 +- sound/soc/sof/intel/apl.c | 13 +- sound/soc/sof/intel/cnl.c | 13 +- sound/soc/sof/intel/hda-dai.c | 19 + sound/soc/sof/intel/hda-probes.c | 71 +-- sound/soc/sof/intel/hda.c | 10 - sound/soc/sof/intel/hda.h | 49 +- sound/soc/sof/intel/icl.c | 13 +- sound/soc/sof/intel/tgl.c | 13 +- sound/soc/sof/ops.h | 43 ++ sound/soc/sof/pcm.c | 8 +- sound/soc/sof/sof-client-probes.c | 821 ------------------------------ sound/soc/sof/sof-client-probes.h | 31 -- sound/soc/sof/sof-priv.h | 25 + sound/soc/sof/sof-probes.c | 364 +++++++++++++ sound/soc/sof/sof-probes.h | 38 ++ 20 files changed, 825 insertions(+), 967 deletions(-) delete mode 100644 sound/soc/sof/sof-client-probes.c delete mode 100644 sound/soc/sof/sof-client-probes.h create mode 100644 sound/soc/sof/sof-probes.c create mode 100644 sound/soc/sof/sof-probes.h diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index a8b6f15f493568..72843e42dc533c 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -53,14 +53,13 @@ config SND_SOC_SOF_COMPRESS select SND_SOC_COMPRESS config SND_SOC_SOF_DEBUG_PROBES - tristate - select SND_SOC_SOF_CLIENT + bool "SOF enable data probing" 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. - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. + Say Y if you want to enable probes. + If unsure, select "N". config SND_SOC_SOF_CLIENT tristate diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index cb8b2bfa6e4f9d..6e746dca8cafdb 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -4,6 +4,7 @@ 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 @@ -12,7 +13,6 @@ 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 @@ -29,7 +29,6 @@ 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/ diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index d99ecbb4282dbd..f29fe573ec3cc4 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -14,6 +14,9 @@ #include #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); @@ -355,6 +358,9 @@ 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 */ diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 145fd0d1e16634..937fe6e11d0d56 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -19,6 +19,221 @@ #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) { @@ -354,6 +569,17 @@ 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); diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index b53f216d4ecc32..88b6176af021c1 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -215,7 +215,6 @@ 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. @@ -241,6 +240,15 @@ 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 @@ -258,15 +266,6 @@ 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 diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index cd8d08c175619f..810b8b6748a0e4 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -80,6 +80,15 @@ 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, @@ -101,10 +110,6 @@ 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, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index ab1ec6c6df5ac8..e615125d575e2c 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -300,6 +300,15 @@ 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, @@ -321,10 +330,6 @@ 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, diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a6a5d93c8e8cf2..73b943ae75919f 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -16,6 +16,10 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) +#include "../sof-probes.h" +#endif + struct hda_pipe_params { u32 ch; u32 s_freq; @@ -746,5 +750,20 @@ struct snd_soc_dai_driver skl_dai[] = { .channels_max = 16, }, }, +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) +{ + .name = "Probe Extraction CPU DAI", + .compress_new = snd_soc_new_compress, + .cops = &sof_probe_compr_ops, + .capture = { + .stream_name = "Probe Extraction", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + }, +}, +#endif #endif }; diff --git a/sound/soc/sof/intel/hda-probes.c b/sound/soc/sof/intel/hda-probes.c index 3ccb42d907fb6d..35e548da3609d5 100644 --- a/sound/soc/sof/intel/hda-probes.c +++ b/sound/soc/sof/intel/hda-probes.c @@ -3,19 +3,14 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2019-2021 Intel Corporation. All rights reserved. +// Copyright(c) 2019-2020 Intel Corporation. All rights reserved. // // Author: Cezary Rojewski -// Converted to SOF client: -// Ranjani Sridharan -// Peter Ujfalusi // #include #include #include "../sof-priv.h" -#include "../sof-client-probes.h" -#include "../sof-client.h" #include "hda.h" static inline struct hdac_ext_stream * @@ -24,11 +19,10 @@ hda_compr_get_stream(struct snd_compr_stream *cstream) return cstream->runtime->private_data; } -static int hda_probes_compr_assign(struct sof_client_dev *cdev, - struct snd_compr_stream *cstream, - struct snd_soc_dai *dai, u32 *stream_id) +int hda_probe_compr_assign(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) { - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct hdac_ext_stream *hext_stream; hext_stream = hda_dsp_stream_get(sdev, cstream->direction, 0); @@ -39,17 +33,14 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev, hdac_stream(hext_stream)->cstream = cstream; cstream->runtime->private_data = hext_stream; - *stream_id = hdac_stream(hext_stream)->stream_tag; - - return 0; + return hdac_stream(hext_stream)->stream_tag; } -static int hda_probes_compr_free(struct sof_client_dev *cdev, - struct snd_compr_stream *cstream, - struct snd_soc_dai *dai) +int hda_probe_compr_free(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) { struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); int ret; ret = hda_dsp_stream_put(sdev, cstream->direction, @@ -65,13 +56,12 @@ static int hda_probes_compr_free(struct sof_client_dev *cdev, return 0; } -static int hda_probes_compr_set_params(struct sof_client_dev *cdev, - struct snd_compr_stream *cstream, - struct snd_compr_params *params, - struct snd_soc_dai *dai) +int hda_probe_compr_set_params(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai) { struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct hdac_stream *hstream = hdac_stream(hext_stream); struct snd_dma_buffer *dmab; u32 bits, rate; @@ -99,20 +89,19 @@ static int hda_probes_compr_set_params(struct sof_client_dev *cdev, return 0; } -static int hda_probes_compr_trigger(struct sof_client_dev *cdev, - struct snd_compr_stream *cstream, - int cmd, struct snd_soc_dai *dai) +int hda_probe_compr_trigger(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, int cmd, + struct snd_soc_dai *dai) { struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); return hda_dsp_stream_trigger(sdev, hext_stream, cmd); } -static int hda_probes_compr_pointer(struct sof_client_dev *cdev, - struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, - struct snd_soc_dai *dai) +int hda_probe_compr_pointer(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai) { struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); struct snd_soc_pcm_stream *pstream; @@ -123,25 +112,3 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev, return 0; } - -/* SOF client implementation */ -static const struct sof_probes_host_ops hda_probes_ops = { - .assign = hda_probes_compr_assign, - .free = hda_probes_compr_free, - .set_params = hda_probes_compr_set_params, - .trigger = hda_probes_compr_trigger, - .pointer = hda_probes_compr_pointer, -}; - -int hda_probes_register(struct snd_sof_dev *sdev) -{ - return sof_client_dev_register(sdev, "hda-probes", 0, &hda_probes_ops, - sizeof(hda_probes_ops)); -} - -void hda_probes_unregister(struct snd_sof_dev *sdev) -{ - sof_client_dev_unregister(sdev, "hda-probes", 0); -} - -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d03a98d44ad1a8..18abbd13d59376 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1431,16 +1431,6 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) } EXPORT_SYMBOL_NS(hda_pci_intel_probe, SND_SOC_SOF_INTEL_HDA_COMMON); -int hda_register_clients(struct snd_sof_dev *sdev) -{ - return hda_probes_register(sdev); -} - -void hda_unregister_clients(struct snd_sof_dev *sdev) -{ - hda_probes_unregister(sdev); -} - MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 665846caff3ba7..24064e08d5fa91 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -16,7 +16,6 @@ #include #include #include -#include "../sof-client-probes.h" #include "shim.h" /* PCI registers */ @@ -352,7 +351,13 @@ /* Number of DAIs */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) +#define SOF_SKL_NUM_DAIS 16 +#else #define SOF_SKL_NUM_DAIS 15 +#endif + #else #define SOF_SKL_NUM_DAIS 8 #endif @@ -570,6 +575,29 @@ int hda_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, const struct sof_ipc_pcm_params_reply *reply); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) +/* + * Probe Compress Operations. + */ +int hda_probe_compr_assign(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai); +int hda_probe_compr_free(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai); +int hda_probe_compr_set_params(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai); +int hda_probe_compr_trigger(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, int cmd, + struct snd_soc_dai *dai); +int hda_probe_compr_pointer(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai); +#endif + /* * DSP IPC Operations. */ @@ -701,25 +729,6 @@ extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; -/* Probes support */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) -int hda_probes_register(struct snd_sof_dev *sdev); -void hda_probes_unregister(struct snd_sof_dev *sdev); -#else -static inline int hda_probes_register(struct snd_sof_dev *sdev) -{ - return 0; -} - -static inline void hda_probes_unregister(struct snd_sof_dev *sdev) -{ -} -#endif /* CONFIG_SND_SOC_SOF_HDA_PROBES */ - -/* SOF client registration for HDA platforms */ -int hda_register_clients(struct snd_sof_dev *sdev); -void hda_unregister_clients(struct snd_sof_dev *sdev); - /* machine driver select */ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev); void hda_set_mach_params(struct snd_soc_acpi_mach *mach, diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index f20ab60e8a523d..f75e3983969f2b 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -142,6 +142,15 @@ const struct snd_sof_dsp_ops sof_icl_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, @@ -164,10 +173,6 @@ const struct snd_sof_dsp_ops sof_icl_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, diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index c7d1c244bc4832..7f7929c5cb88fd 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -115,6 +115,15 @@ const struct snd_sof_dsp_ops sof_tgl_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, @@ -137,10 +146,6 @@ const struct snd_sof_dsp_ops sof_tgl_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, diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 999a36208b1161..1f84d30296cf41 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -497,6 +497,49 @@ static inline int snd_sof_pcm_platform_ack(struct snd_sof_dev *sdev, return 0; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) +static inline int +snd_sof_probe_compr_assign(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, struct snd_soc_dai *dai) +{ + return sof_ops(sdev)->probe_assign(sdev, cstream, dai); +} + +static inline int +snd_sof_probe_compr_free(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, struct snd_soc_dai *dai) +{ + return sof_ops(sdev)->probe_free(sdev, cstream, dai); +} + +static inline int +snd_sof_probe_compr_set_params(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, struct snd_soc_dai *dai) +{ + return sof_ops(sdev)->probe_set_params(sdev, cstream, params, dai); +} + +static inline int +snd_sof_probe_compr_trigger(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, int cmd, + struct snd_soc_dai *dai) +{ + return sof_ops(sdev)->probe_trigger(sdev, cstream, cmd, dai); +} + +static inline int +snd_sof_probe_compr_pointer(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai) +{ + if (sof_ops(sdev) && sof_ops(sdev)->probe_pointer) + return sof_ops(sdev)->probe_pointer(sdev, cstream, tstamp, dai); + + return 0; +} +#endif + /* machine driver */ static inline int snd_sof_machine_register(struct snd_sof_dev *sdev, void *pdata) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 126b1a14f8e399..02c75a23c67f66 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -15,8 +15,11 @@ #include #include "sof-priv.h" #include "sof-audio.h" -#include "sof-utils.h" #include "ops.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) +#include "sof-probes.h" +#endif +#include "sof-utils.h" /* Create DMA buffer page table for DSP */ static int create_page_table(struct snd_soc_component *component, @@ -942,6 +945,9 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->pointer = sof_pcm_pointer; pd->ack = sof_pcm_ack; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) + pd->compress_ops = &sof_probe_compressed_ops; +#endif pd->pcm_construct = sof_pcm_new; pd->ignore_machine = drv_name; pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c deleted file mode 100644 index 727aa25ca1fec9..00000000000000 --- a/sound/soc/sof/sof-client-probes.c +++ /dev/null @@ -1,821 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// -// Copyright(c) 2019-2021 Intel Corporation. All rights reserved. -// -// Author: Cezary Rojewski -// -// SOF client support: -// Ranjani Sridharan -// Peter Ujfalusi -// - -#include -#include -#include -#include -#include -#include "sof-client.h" -#include "sof-client-probes.h" - -#define SOF_PROBES_SUSPEND_DELAY_MS 3000 -/* only extraction supported for now */ -#define SOF_PROBES_NUM_DAI_LINKS 1 - -#define SOF_PROBES_INVALID_NODE_ID UINT_MAX - -static bool __read_mostly sof_probes_enabled; -module_param_named(enable, sof_probes_enabled, bool, 0444); -MODULE_PARM_DESC(enable, "Enable SOF probes support"); - -struct sof_probes_priv { - struct dentry *dfs_points; - struct dentry *dfs_points_remove; - u32 extractor_stream_tag; - struct snd_soc_card card; - - const struct sof_probes_host_ops *host_ops; -}; - -struct sof_probe_point_desc { - unsigned int buffer_id; - unsigned int purpose; - unsigned int stream_tag; -} __packed; - -struct sof_probe_dma { - unsigned int stream_tag; - unsigned int dma_buffer_size; -} __packed; - -struct sof_ipc_probe_dma_add_params { - struct sof_ipc_cmd_hdr hdr; - unsigned int num_elems; - struct sof_probe_dma dma[]; -} __packed; - -struct sof_ipc_probe_info_params { - struct sof_ipc_reply rhdr; - unsigned int num_elems; - union { - struct sof_probe_dma dma[0]; - struct sof_probe_point_desc desc[0]; - }; -} __packed; - -struct sof_ipc_probe_point_add_params { - struct sof_ipc_cmd_hdr hdr; - unsigned int num_elems; - struct sof_probe_point_desc desc[]; -} __packed; - -struct sof_ipc_probe_point_remove_params { - struct sof_ipc_cmd_hdr hdr; - unsigned int num_elems; - unsigned int buffer_id[]; -} __packed; - -/** - * sof_probes_init - initialize data probing - * @cdev: SOF client device - * @stream_tag: Extractor stream tag - * @buffer_size: DMA buffer size to set for extractor - * - * Host chooses whether extraction is supported or not by providing - * valid stream tag to DSP. Once specified, stream described by that - * tag will be tied to DSP for extraction for the entire lifetime of - * probe. - * - * Probing is initialized only once and each INIT request must be - * matched by DEINIT call. - */ -static int sof_probes_init(struct sof_client_dev *cdev, u32 stream_tag, - size_t buffer_size) -{ - struct sof_ipc_probe_dma_add_params *msg; - size_t size = struct_size(msg, dma, 1); - struct sof_ipc_reply reply; - int ret; - - msg = kmalloc(size, GFP_KERNEL); - if (!msg) - return -ENOMEM; - msg->hdr.size = size; - msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT; - msg->num_elems = 1; - msg->dma[0].stream_tag = stream_tag; - msg->dma[0].dma_buffer_size = buffer_size; - - ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply)); - kfree(msg); - return ret; -} - -/** - * sof_probes_deinit - cleanup after data probing - * @cdev: SOF client device - * - * Host sends DEINIT request to free previously initialized probe - * on DSP side once it is no longer needed. DEINIT only when there - * are no probes connected and with all injectors detached. - */ -static int sof_probes_deinit(struct sof_client_dev *cdev) -{ - struct sof_ipc_cmd_hdr msg; - struct sof_ipc_reply reply; - - msg.size = sizeof(msg); - msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT; - - return sof_client_ipc_tx_message(cdev, &msg, &reply, sizeof(reply)); -} - -static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd, - void **params, size_t *num_params) -{ - struct sof_ipc_probe_info_params msg = {{{0}}}; - struct sof_ipc_probe_info_params *reply; - size_t bytes; - int ret; - - *params = NULL; - *num_params = 0; - - reply = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); - if (!reply) - return -ENOMEM; - msg.rhdr.hdr.size = sizeof(msg); - msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd; - - ret = sof_client_ipc_tx_message(cdev, &msg, reply, SOF_IPC_MSG_MAX_SIZE); - if (ret < 0 || reply->rhdr.error < 0) - goto exit; - - if (!reply->num_elems) - goto exit; - - if (cmd == SOF_IPC_PROBE_DMA_INFO) - bytes = sizeof(reply->dma[0]); - else - bytes = sizeof(reply->desc[0]); - bytes *= reply->num_elems; - *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL); - if (!*params) { - ret = -ENOMEM; - goto exit; - } - *num_params = reply->num_elems; - -exit: - kfree(reply); - return ret; -} - -/** - * sof_probes_points_info - retrieve list of active probe points - * @cdev: SOF client device - * @desc: Returned list of active probes - * @num_desc: Returned count of 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. - */ -static int sof_probes_points_info(struct sof_client_dev *cdev, - struct sof_probe_point_desc **desc, - size_t *num_desc) -{ - return sof_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO, - (void **)desc, num_desc); -} - -/** - * sof_probes_points_add - connect specified probes - * @cdev: SOF client device - * @desc: List of probe points to connect - * @num_desc: Number of elements in @desc - * - * Dynamically connects to provided set of endpoints. Immediately - * after connection is established, host must be prepared to - * transfer data from or to target stream given the probing purpose. - * - * Each probe point should be removed using PROBE_POINT_REMOVE - * request when no longer needed. - */ -static int sof_probes_points_add(struct sof_client_dev *cdev, - struct sof_probe_point_desc *desc, - size_t num_desc) -{ - struct sof_ipc_probe_point_add_params *msg; - size_t size = struct_size(msg, desc, num_desc); - struct sof_ipc_reply reply; - int ret; - - msg = kmalloc(size, GFP_KERNEL); - if (!msg) - return -ENOMEM; - msg->hdr.size = size; - msg->num_elems = num_desc; - msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD; - memcpy(&msg->desc[0], desc, size - sizeof(*msg)); - - ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply)); - kfree(msg); - return ret; -} - -/** - * sof_probes_points_remove - disconnect specified probes - * @cdev: SOF client device - * @buffer_id: List of probe points to disconnect - * @num_buffer_id: Number of elements in @desc - * - * Removes previously connected probes from list of active probe - * points and frees all resources on DSP side. - */ -static int sof_probes_points_remove(struct sof_client_dev *cdev, - unsigned int *buffer_id, size_t num_buffer_id) -{ - struct sof_ipc_probe_point_remove_params *msg; - size_t size = struct_size(msg, buffer_id, num_buffer_id); - struct sof_ipc_reply reply; - int ret; - - msg = kmalloc(size, GFP_KERNEL); - if (!msg) - return -ENOMEM; - msg->hdr.size = size; - msg->num_elems = num_buffer_id; - msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE; - memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg)); - - ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply)); - kfree(msg); - return ret; -} - -static int sof_probes_compr_startup(struct snd_compr_stream *cstream, - struct snd_soc_dai *dai) -{ - struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); - struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); - struct sof_probes_priv *priv = cdev->data; - const struct sof_probes_host_ops *ops = priv->host_ops; - int ret; - - if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED) - return -ENODEV; - - ret = sof_client_core_module_get(cdev); - if (ret) - return ret; - - ret = ops->assign(cdev, cstream, dai, &priv->extractor_stream_tag); - if (ret) { - dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret); - priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; - sof_client_core_module_put(cdev); - } - - return ret; -} - -static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream, - struct snd_soc_dai *dai) -{ - struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); - struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); - struct sof_probes_priv *priv = cdev->data; - const struct sof_probes_host_ops *ops = priv->host_ops; - struct sof_probe_point_desc *desc; - size_t num_desc; - int i, ret; - - /* disconnect all probe points */ - ret = sof_probes_points_info(cdev, &desc, &num_desc); - if (ret < 0) { - dev_err(dai->dev, "Failed to get probe points: %d\n", ret); - goto exit; - } - - for (i = 0; i < num_desc; i++) - sof_probes_points_remove(cdev, &desc[i].buffer_id, 1); - kfree(desc); - -exit: - ret = sof_probes_deinit(cdev); - if (ret < 0) - dev_err(dai->dev, "Failed to deinit probe: %d\n", ret); - - priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; - snd_compr_free_pages(cstream); - - ret = ops->free(cdev, cstream, dai); - - sof_client_core_module_put(cdev); - - return ret; -} - -static int sof_probes_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); - struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); - struct snd_compr_runtime *rtd = cstream->runtime; - struct sof_probes_priv *priv = cdev->data; - const struct sof_probes_host_ops *ops = priv->host_ops; - int ret; - - cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; - cstream->dma_buffer.dev.dev = sof_client_get_dma_dev(cdev); - ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); - if (ret < 0) - return ret; - - ret = ops->set_params(cdev, cstream, params, dai); - if (ret) - return ret; - - ret = sof_probes_init(cdev, priv->extractor_stream_tag, rtd->dma_bytes); - if (ret < 0) { - dev_err(dai->dev, "Failed to init probe: %d\n", ret); - return ret; - } - - return 0; -} - -static int sof_probes_compr_trigger(struct snd_compr_stream *cstream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); - struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); - struct sof_probes_priv *priv = cdev->data; - const struct sof_probes_host_ops *ops = priv->host_ops; - - return ops->trigger(cdev, cstream, cmd, dai); -} - -static int sof_probes_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, - struct snd_soc_dai *dai) -{ - struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); - struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card); - struct sof_probes_priv *priv = cdev->data; - const struct sof_probes_host_ops *ops = priv->host_ops; - - return ops->pointer(cdev, cstream, tstamp, dai); -} - -static struct snd_soc_cdai_ops sof_probes_compr_ops = { - .startup = sof_probes_compr_startup, - .shutdown = sof_probes_compr_shutdown, - .set_params = sof_probes_compr_set_params, - .trigger = sof_probes_compr_trigger, - .pointer = sof_probes_compr_pointer, -}; - -static int sof_probes_compr_copy(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - char __user *buf, size_t count) -{ - struct snd_compr_runtime *rtd = cstream->runtime; - unsigned int offset, n; - void *ptr; - int ret; - - if (count > rtd->buffer_size) - count = rtd->buffer_size; - - div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); - ptr = rtd->dma_area + offset; - n = rtd->buffer_size - offset; - - if (count < n) { - ret = copy_to_user(buf, ptr, count); - } else { - ret = copy_to_user(buf, ptr, n); - ret += copy_to_user(buf + n, rtd->dma_area, count - n); - } - - if (ret) - return count - ret; - return count; -} - -static const struct snd_compress_ops sof_probes_compressed_ops = { - .copy = sof_probes_compr_copy, -}; - -/** - * 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)) { - 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(buf, ",", tkns, num_tkns); -exit: - kfree(buf); - return ret; -} - -static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, - size_t count, loff_t *ppos) -{ - struct sof_client_dev *cdev = file->private_data; - struct sof_probes_priv *priv = cdev->data; - struct device *dev = &cdev->auxdev.dev; - struct sof_probe_point_desc *desc; - size_t num_desc; - int remaining; - char *buf; - int i, ret, err; - - if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { - dev_warn(dev, "no extractor stream running\n"); - return -ENOENT; - } - - buf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = pm_runtime_get_sync(dev); - if (ret < 0 && ret != -EACCES) { - dev_err_ratelimited(dev, "debugfs read failed to resume %d\n", ret); - pm_runtime_put_noidle(dev); - goto exit; - } - - ret = sof_probes_points_info(cdev, &desc, &num_desc); - if (ret < 0) - goto exit; - - pm_runtime_mark_last_busy(dev); - err = pm_runtime_put_autosuspend(dev); - if (err < 0) - dev_err_ratelimited(dev, "debugfs read failed to idle %d\n", err); - - for (i = 0; i < num_desc; i++) { - remaining = PAGE_SIZE - strlen(buf); - if (remaining > 0) { - ret = snprintf(buf + strlen(buf), remaining, - "Id: %#010x Purpose: %u Node id: %#x\n", - desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag); - if (ret < 0) - goto free_desc; - } else { - break; - } - } - - ret = simple_read_from_buffer(to, count, ppos, buf, strlen(buf)); -free_desc: - kfree(desc); -exit: - kfree(buf); - return ret; -} - -static ssize_t -sof_probes_dfs_points_write(struct file *file, const char __user *from, - size_t count, loff_t *ppos) -{ - struct sof_client_dev *cdev = file->private_data; - struct sof_probes_priv *priv = cdev->data; - struct device *dev = &cdev->auxdev.dev; - struct sof_probe_point_desc *desc; - size_t num_tkns, bytes; - u32 *tkns; - int ret, err; - - if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { - dev_warn(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 = pm_runtime_get_sync(dev); - if (ret < 0 && ret != -EACCES) { - dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret); - pm_runtime_put_noidle(dev); - goto exit; - } - - ret = sof_probes_points_add(cdev, desc, bytes / sizeof(*desc)); - if (!ret) - ret = count; - - pm_runtime_mark_last_busy(dev); - err = pm_runtime_put_autosuspend(dev); - if (err < 0) - dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); -exit: - kfree(tkns); - return ret; -} - -static const struct file_operations sof_probes_points_fops = { - .open = simple_open, - .read = sof_probes_dfs_points_read, - .write = sof_probes_dfs_points_write, - .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) -{ - struct sof_client_dev *cdev = file->private_data; - struct sof_probes_priv *priv = cdev->data; - struct device *dev = &cdev->auxdev.dev; - size_t num_tkns; - u32 *tkns; - int ret, err; - - if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { - dev_warn(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 = pm_runtime_get_sync(dev); - if (ret < 0) { - dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret); - pm_runtime_put_noidle(dev); - goto exit; - } - - ret = sof_probes_points_remove(cdev, tkns, num_tkns); - if (!ret) - ret = count; - - pm_runtime_mark_last_busy(dev); - err = pm_runtime_put_autosuspend(dev); - if (err < 0) - dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); -exit: - kfree(tkns); - return ret; -} - -static const struct file_operations sof_probes_points_remove_fops = { - .open = simple_open, - .write = sof_probes_dfs_points_remove_write, - .llseek = default_llseek, - - .owner = THIS_MODULE, -}; - -static struct snd_soc_dai_driver sof_probes_dai_drv[] = { -{ - .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, - .cops = &sof_probes_compr_ops, - .capture = { - .stream_name = "Probe Extraction", - .channels_min = 1, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - }, -}, -}; - -static const struct snd_soc_component_driver sof_probes_component = { - .name = "sof-probes-component", - .compress_ops = &sof_probes_compressed_ops, - .module_get_upon_open = 1, -}; - -SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); - -static int sof_probes_client_probe(struct auxiliary_device *auxdev, - const struct auxiliary_device_id *id) -{ - struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - struct dentry *dfsroot = sof_client_get_debugfs_root(cdev); - struct device *dev = &auxdev->dev; - struct snd_soc_dai_link_component platform_component[] = { - { - .name = dev_name(dev), - } - }; - struct snd_soc_card *card; - struct sof_probes_priv *priv; - struct snd_soc_dai_link_component *cpus; - struct sof_probes_host_ops *ops; - struct snd_soc_dai_link *links; - int ret; - - /* do not set up the probes support if it is not enabled */ - if (!sof_probes_enabled) - return -ENXIO; - - if (!dev->platform_data) { - dev_err(dev, "missing platform data\n"); - return -ENODEV; - } - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - ops = dev->platform_data; - - if (!ops->assign || !ops->free || !ops->set_params || !ops->trigger || - !ops->pointer) { - dev_err(dev, "missing platform callback(s)\n"); - return -ENODEV; - } - - priv->host_ops = ops; - cdev->data = priv; - - /* register probes component driver and dai */ - ret = devm_snd_soc_register_component(dev, &sof_probes_component, - sof_probes_dai_drv, - ARRAY_SIZE(sof_probes_dai_drv)); - if (ret < 0) { - dev_err(dev, "failed to register SOF probes DAI driver %d\n", ret); - return ret; - } - - /* set client data */ - priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; - - /* create read-write probes_points debugfs entry */ - priv->dfs_points = debugfs_create_file("probe_points", 0644, dfsroot, - cdev, &sof_probes_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); - - 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) { - debugfs_remove(priv->dfs_points); - debugfs_remove(priv->dfs_points_remove); - return -ENOMEM; - } - - /* extraction DAI link */ - links[0].name = "Compress Probe Capture"; - links[0].id = 0; - links[0].cpus = &cpus[0]; - links[0].num_cpus = 1; - links[0].cpus->dai_name = "Probe Extraction CPU DAI"; - links[0].codecs = dummy; - links[0].num_codecs = 1; - links[0].platforms = platform_component; - links[0].num_platforms = ARRAY_SIZE(platform_component); - links[0].nonatomic = 1; - - card = &priv->card; - - card->dev = dev; - card->name = "sof-probes"; - card->owner = THIS_MODULE; - card->num_links = SOF_PROBES_NUM_DAI_LINKS; - card->dai_link = links; - - /* set idle_bias_off to prevent the core from resuming the card->dev */ - card->dapm.idle_bias_off = true; - - snd_soc_card_set_drvdata(card, cdev); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) { - debugfs_remove(priv->dfs_points); - debugfs_remove(priv->dfs_points_remove); - dev_err(dev, "Probes card register failed %d\n", ret); - return ret; - } - - /* enable runtime PM */ - pm_runtime_set_autosuspend_delay(dev, SOF_PROBES_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(dev); - pm_runtime_enable(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_idle(dev); - - return 0; -} - -static void sof_probes_client_remove(struct auxiliary_device *auxdev) -{ - struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - struct sof_probes_priv *priv = cdev->data; - - if (!sof_probes_enabled) - return; - - pm_runtime_disable(&auxdev->dev); - debugfs_remove(priv->dfs_points); - debugfs_remove(priv->dfs_points_remove); -} - -static const struct auxiliary_device_id sof_probes_client_id_table[] = { - { .name = "snd_sof.hda-probes", }, - {}, -}; -MODULE_DEVICE_TABLE(auxiliary, sof_probes_client_id_table); - -/* driver name will be set based on KBUILD_MODNAME */ -static struct auxiliary_driver sof_probes_client_drv = { - .probe = sof_probes_client_probe, - .remove = sof_probes_client_remove, - - .id_table = sof_probes_client_id_table, -}; - -module_auxiliary_driver(sof_probes_client_drv); - -MODULE_DESCRIPTION("SOF Probes Client Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); diff --git a/sound/soc/sof/sof-client-probes.h b/sound/soc/sof/sof-client-probes.h deleted file mode 100644 index 0f9ed4569fd3bb..00000000000000 --- a/sound/soc/sof/sof-client-probes.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#ifndef __SOF_CLIENT_PROBES_H -#define __SOF_CLIENT_PROBES_H - -struct snd_compr_stream; -struct snd_compr_tstamp; -struct snd_compr_params; -struct sof_client_dev; -struct snd_soc_dai; - -/* - * Callbacks used on platforms where the control for audio is split between - * DSP and host, like HDA. - */ -struct sof_probes_host_ops { - int (*assign)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_soc_dai *dai, u32 *stream_id); - int (*free)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_soc_dai *dai); - int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_compr_params *params, - struct snd_soc_dai *dai); - int (*trigger)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - int cmd, struct snd_soc_dai *dai); - int (*pointer)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, - struct snd_soc_dai *dai); -}; - -#endif diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 3222454385891a..859a117df8f1ed 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -199,6 +199,27 @@ struct snd_sof_dsp_ops { /* pcm ack */ int (*pcm_ack)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) + /* Except for probe_pointer, all probe ops are mandatory */ + int (*probe_assign)(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai); /* mandatory */ + int (*probe_free)(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai); /* mandatory */ + int (*probe_set_params)(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai); /* mandatory */ + int (*probe_trigger)(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, int cmd, + struct snd_soc_dai *dai); /* mandatory */ + int (*probe_pointer)(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai); /* optional */ +#endif + /* host read DSP stream data */ int (*ipc_msg_data)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, @@ -437,6 +458,10 @@ struct snd_sof_dev { int ipc_timeout; int boot_timeout; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) + unsigned int extractor_stream_tag; +#endif + /* DMA for Trace */ struct snd_dma_buffer dmatb; struct snd_dma_buffer dmatp; diff --git a/sound/soc/sof/sof-probes.c b/sound/soc/sof/sof-probes.c new file mode 100644 index 00000000000000..5586af9f1a251c --- /dev/null +++ b/sound/soc/sof/sof-probes.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2019-2021 Intel Corporation. All rights reserved. +// Author: Cezary Rojewski +// + +#include +#include "ops.h" +#include "sof-priv.h" +#include "sof-probes.h" + +struct sof_probe_dma { + unsigned int stream_tag; + unsigned int dma_buffer_size; +} __packed; + +struct sof_ipc_probe_dma_add_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + struct sof_probe_dma dma[]; +} __packed; + +struct sof_ipc_probe_info_params { + struct sof_ipc_reply rhdr; + unsigned int num_elems; + union { + struct sof_probe_dma dma[0]; + struct sof_probe_point_desc desc[0]; + }; +} __packed; + +struct sof_ipc_probe_point_add_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + struct sof_probe_point_desc desc[]; +} __packed; + +struct sof_ipc_probe_point_remove_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + unsigned int buffer_id[]; +} __packed; + +/** + * sof_ipc_probe_init - initialize data probing + * @sdev: SOF sound device + * @stream_tag: Extractor stream tag + * @buffer_size: DMA buffer size to set for extractor + * + * Host chooses whether extraction is supported or not by providing + * valid stream tag to DSP. Once specified, stream described by that + * tag will be tied to DSP for extraction for the entire lifetime of + * probe. + * + * Probing is initialized only once and each INIT request must be + * matched by DEINIT call. + */ +static int sof_ipc_probe_init(struct snd_sof_dev *sdev, u32 stream_tag, + size_t buffer_size) +{ + struct sof_ipc_probe_dma_add_params *msg; + struct sof_ipc_reply reply; + size_t size = struct_size(msg, dma, 1); + int ret; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + msg->hdr.size = size; + msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT; + msg->num_elems = 1; + msg->dma[0].stream_tag = stream_tag; + msg->dma[0].dma_buffer_size = buffer_size; + + ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size, + &reply, sizeof(reply)); + kfree(msg); + return ret; +} + +/** + * sof_ipc_probe_deinit - cleanup after data probing + * @sdev: SOF sound device + * + * Host sends DEINIT request to free previously initialized probe + * on DSP side once it is no longer needed. DEINIT only when there + * are no probes connected and with all injectors detached. + */ +static int sof_ipc_probe_deinit(struct snd_sof_dev *sdev) +{ + struct sof_ipc_cmd_hdr msg; + struct sof_ipc_reply reply; + + msg.size = sizeof(msg); + msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT; + + return sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, + &reply, sizeof(reply)); +} + +static int sof_ipc_probe_info(struct snd_sof_dev *sdev, unsigned int cmd, + void **params, size_t *num_params) +{ + struct sof_ipc_probe_info_params msg = {{{0}}}; + struct sof_ipc_probe_info_params *reply; + size_t bytes; + int ret; + + *params = NULL; + *num_params = 0; + + reply = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + if (!reply) + return -ENOMEM; + msg.rhdr.hdr.size = sizeof(msg); + msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd; + + ret = sof_ipc_tx_message(sdev->ipc, msg.rhdr.hdr.cmd, &msg, + msg.rhdr.hdr.size, reply, SOF_IPC_MSG_MAX_SIZE); + if (ret < 0 || reply->rhdr.error < 0) + goto exit; + + if (!reply->num_elems) + goto exit; + + if (cmd == SOF_IPC_PROBE_DMA_INFO) + bytes = sizeof(reply->dma[0]); + else + bytes = sizeof(reply->desc[0]); + bytes *= reply->num_elems; + *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL); + if (!*params) { + ret = -ENOMEM; + goto exit; + } + *num_params = reply->num_elems; + +exit: + kfree(reply); + return ret; +} + +/** + * sof_ipc_probe_points_info - retrieve list of active probe points + * @sdev: SOF sound device + * @desc: Returned list of active probes + * @num_desc: Returned count of 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. + */ +int sof_ipc_probe_points_info(struct snd_sof_dev *sdev, + struct sof_probe_point_desc **desc, + size_t *num_desc) +{ + return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_POINT_INFO, + (void **)desc, num_desc); +} +EXPORT_SYMBOL(sof_ipc_probe_points_info); + +/** + * sof_ipc_probe_points_add - connect specified probes + * @sdev: SOF sound device + * @desc: List of probe points to connect + * @num_desc: Number of elements in @desc + * + * Dynamically connects to provided set of endpoints. Immediately + * after connection is established, host must be prepared to + * transfer data from or to target stream given the probing purpose. + * + * Each probe point should be removed using PROBE_POINT_REMOVE + * request when no longer needed. + */ +int sof_ipc_probe_points_add(struct snd_sof_dev *sdev, + struct sof_probe_point_desc *desc, size_t num_desc) +{ + struct sof_ipc_probe_point_add_params *msg; + struct sof_ipc_reply reply; + size_t size = struct_size(msg, desc, num_desc); + int ret; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + msg->hdr.size = size; + msg->num_elems = num_desc; + msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD; + memcpy(&msg->desc[0], desc, size - sizeof(*msg)); + + ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size, + &reply, sizeof(reply)); + kfree(msg); + return ret; +} +EXPORT_SYMBOL(sof_ipc_probe_points_add); + +/** + * sof_ipc_probe_points_remove - disconnect specified probes + * @sdev: SOF sound device + * @buffer_id: List of probe points to disconnect + * @num_buffer_id: Number of elements in @desc + * + * Removes previously connected probes from list of active probe + * points and frees all resources on DSP side. + */ +int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev, + unsigned int *buffer_id, size_t num_buffer_id) +{ + struct sof_ipc_probe_point_remove_params *msg; + struct sof_ipc_reply reply; + size_t size = struct_size(msg, buffer_id, num_buffer_id); + int ret; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + msg->hdr.size = size; + msg->num_elems = num_buffer_id; + msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE; + memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg)); + + ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size, + &reply, sizeof(reply)); + kfree(msg); + return ret; +} +EXPORT_SYMBOL(sof_ipc_probe_points_remove); + +static int sof_probe_compr_startup(struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + int ret; + + ret = snd_sof_probe_compr_assign(sdev, cstream, dai); + if (ret < 0) { + dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret); + return ret; + } + + sdev->extractor_stream_tag = ret; + return 0; +} + +static int sof_probe_compr_shutdown(struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + struct sof_probe_point_desc *desc; + size_t num_desc; + int i, ret; + + /* disconnect all probe points */ + ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc); + if (ret < 0) { + dev_err(dai->dev, "Failed to get probe points: %d\n", ret); + goto exit; + } + + for (i = 0; i < num_desc; i++) + sof_ipc_probe_points_remove(sdev, &desc[i].buffer_id, 1); + kfree(desc); + +exit: + ret = sof_ipc_probe_deinit(sdev); + if (ret < 0) + dev_err(dai->dev, "Failed to deinit probe: %d\n", ret); + + sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID; + snd_compr_free_pages(cstream); + + return snd_sof_probe_compr_free(sdev, cstream, dai); +} + +static int sof_probe_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + struct snd_compr_runtime *rtd = cstream->runtime; + int ret; + + cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; + cstream->dma_buffer.dev.dev = sdev->dev; + ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); + if (ret < 0) + return ret; + + ret = snd_sof_probe_compr_set_params(sdev, cstream, params, dai); + if (ret < 0) + return ret; + + ret = sof_ipc_probe_init(sdev, sdev->extractor_stream_tag, + rtd->dma_bytes); + if (ret < 0) { + dev_err(dai->dev, "Failed to init probe: %d\n", ret); + return ret; + } + + return 0; +} + +static int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + + return snd_sof_probe_compr_trigger(sdev, cstream, cmd, dai); +} + +static int sof_probe_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + + return snd_sof_probe_compr_pointer(sdev, cstream, tstamp, dai); +} + +struct snd_soc_cdai_ops sof_probe_compr_ops = { + .startup = sof_probe_compr_startup, + .shutdown = sof_probe_compr_shutdown, + .set_params = sof_probe_compr_set_params, + .trigger = sof_probe_compr_trigger, + .pointer = sof_probe_compr_pointer, +}; +EXPORT_SYMBOL(sof_probe_compr_ops); + +static int sof_probe_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_compr_runtime *rtd = cstream->runtime; + unsigned int offset, n; + void *ptr; + int ret; + + if (count > rtd->buffer_size) + count = rtd->buffer_size; + + div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); + ptr = rtd->dma_area + offset; + n = rtd->buffer_size - offset; + + if (count < n) { + ret = copy_to_user(buf, ptr, count); + } else { + ret = copy_to_user(buf, ptr, n); + ret += copy_to_user(buf + n, rtd->dma_area, count - n); + } + + if (ret) + return count - ret; + return count; +} + +const struct snd_compress_ops sof_probe_compressed_ops = { + .copy = sof_probe_compr_copy, +}; +EXPORT_SYMBOL(sof_probe_compressed_ops); diff --git a/sound/soc/sof/sof-probes.h b/sound/soc/sof/sof-probes.h new file mode 100644 index 00000000000000..35e1dd8d9e0383 --- /dev/null +++ b/sound/soc/sof/sof-probes.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019-2021 Intel Corporation. All rights reserved. + * Author: Cezary Rojewski + */ + +#ifndef __SOF_PROBES_H +#define __SOF_PROBES_H + +#include +#include + +struct snd_sof_dev; + +#define SOF_PROBE_INVALID_NODE_ID UINT_MAX + +struct sof_probe_point_desc { + unsigned int buffer_id; + unsigned int purpose; + unsigned int stream_tag; +} __packed; + +int sof_ipc_probe_points_info(struct snd_sof_dev *sdev, + struct sof_probe_point_desc **desc, + size_t *num_desc); +int sof_ipc_probe_points_add(struct snd_sof_dev *sdev, + struct sof_probe_point_desc *desc, + size_t num_desc); +int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev, + unsigned int *buffer_id, size_t num_buffer_id); + +extern struct snd_soc_cdai_ops sof_probe_compr_ops; +extern const struct snd_compress_ops sof_probe_compressed_ops; + +#endif From 04ba4ffb64876c4d78c2916a7189043d48045432 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:41 +0000 Subject: [PATCH 2/9] Revert "ASoC: SOF: Convert the generic IPC message injector into SOF client" This reverts commit bc6635ba4f714ec39841c4b4e18d333bcc69a70f. --- sound/soc/sof/Kconfig | 3 +- sound/soc/sof/Makefile | 2 - sound/soc/sof/debug.c | 108 +++++++++++ sound/soc/sof/sof-client-ipc-msg-injector.c | 192 -------------------- sound/soc/sof/sof-client.c | 35 +--- sound/soc/sof/sof-priv.h | 4 + 6 files changed, 115 insertions(+), 229 deletions(-) delete mode 100644 sound/soc/sof/sof-client-ipc-msg-injector.c diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 72843e42dc533c..dd763124427220 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -212,8 +212,7 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM Select the number of IPC flood test clients to be created. config SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR - tristate "SOF enable IPC message injector" - select SND_SOC_SOF_CLIENT + bool "SOF enable IPC message injector" help This option enables the IPC message injector which can be used to send crafted IPC messages to the DSP to test its robustness. diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 6e746dca8cafdb..a054c28702bb00 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -12,7 +12,6 @@ snd-sof-acpi-objs := sof-acpi-dev.o 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-nocodec-objs := nocodec.o @@ -28,7 +27,6 @@ obj-$(CONFIG_SND_SOC_SOF_OF_DEV) += snd-sof-of.o 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_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 937fe6e11d0d56..e3a5f77bbd4d04 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -234,6 +234,105 @@ static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev, } #endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) +static ssize_t msg_inject_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct sof_ipc_reply *rhdr = dfse->msg_inject_rx; + + if (!rhdr->hdr.size || !count || *ppos) + return 0; + + if (count > rhdr->hdr.size) + count = rhdr->hdr.size; + + if (copy_to_user(buffer, dfse->msg_inject_rx, count)) + return -EFAULT; + + *ppos += count; + return count; +} + +static ssize_t msg_inject_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + struct sof_ipc_cmd_hdr *hdr = dfse->msg_inject_tx; + size_t size; + int ret, err; + + if (*ppos) + return 0; + + size = simple_write_to_buffer(dfse->msg_inject_tx, SOF_IPC_MSG_MAX_SIZE, + ppos, buffer, count); + if (size != count) + return size > 0 ? -EFAULT : size; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0 && ret != -EACCES) { + dev_err_ratelimited(sdev->dev, "%s: DSP resume failed: %d\n", + __func__, ret); + pm_runtime_put_noidle(sdev->dev); + goto out; + } + + /* send the message */ + memset(dfse->msg_inject_rx, 0, SOF_IPC_MSG_MAX_SIZE); + ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, dfse->msg_inject_tx, count, + dfse->msg_inject_rx, SOF_IPC_MSG_MAX_SIZE); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, "%s: DSP idle failed: %d\n", + __func__, err); + + /* return size if test is successful */ + if (ret >= 0) + ret = size; + +out: + return ret; +} + +static const struct file_operations msg_inject_fops = { + .open = simple_open, + .read = msg_inject_read, + .write = msg_inject_write, + .llseek = default_llseek, +}; + +static int snd_sof_debugfs_msg_inject_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; + + /* pre allocate the tx and rx buffers */ + dfse->msg_inject_tx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + dfse->msg_inject_rx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + if (!dfse->msg_inject_tx || !dfse->msg_inject_rx) + 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) { @@ -580,6 +679,15 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return err; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) + err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644, + &msg_inject_fops); + + /* errors are only due to memory allocation, not debugfs */ + if (err < 0) + return err; +#endif + return 0; } EXPORT_SYMBOL_GPL(snd_sof_dbg_init); diff --git a/sound/soc/sof/sof-client-ipc-msg-injector.c b/sound/soc/sof/sof-client-ipc-msg-injector.c deleted file mode 100644 index 9f617f2f8d9e40..00000000000000 --- a/sound/soc/sof/sof-client-ipc-msg-injector.c +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Peter Ujfalusi -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sof-client.h" - -#define SOF_IPC_CLIENT_SUSPEND_DELAY_MS 3000 - -struct sof_msg_inject_priv { - struct dentry *dfs_file; - - void *tx_buffer; - void *rx_buffer; -}; - -static int sof_msg_inject_dfs_open(struct inode *inode, struct file *file) -{ - struct sof_client_dev *cdev = inode->i_private; - int ret; - - if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED) - return -ENODEV; - - ret = debugfs_file_get(file->f_path.dentry); - if (unlikely(ret)) - return ret; - - ret = simple_open(inode, file); - if (ret) - debugfs_file_put(file->f_path.dentry); - - return ret; -} - -static ssize_t sof_msg_inject_dfs_read(struct file *file, 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_ipc_reply *rhdr = priv->rx_buffer; - - if (!rhdr->hdr.size || !count || *ppos) - return 0; - - if (count > rhdr->hdr.size) - count = rhdr->hdr.size; - - if (copy_to_user(buffer, priv->rx_buffer, count)) - return -EFAULT; - - *ppos += count; - return count; -} - -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; - struct device *dev = &cdev->auxdev.dev; - int ret, err; - size_t size; - - if (*ppos) - return 0; - - size = simple_write_to_buffer(priv->tx_buffer, SOF_IPC_MSG_MAX_SIZE, - ppos, buffer, count); - if (size != count) - return size > 0 ? -EFAULT : size; - - ret = pm_runtime_get_sync(dev); - if (ret < 0 && ret != -EACCES) { - dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret); - pm_runtime_put_noidle(dev); - return ret; - } - - /* 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, - SOF_IPC_MSG_MAX_SIZE); - pm_runtime_mark_last_busy(dev); - err = pm_runtime_put_autosuspend(dev); - if (err < 0) - 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; -}; - -static int sof_msg_inject_dfs_release(struct inode *inode, struct file *file) -{ - debugfs_file_put(file->f_path.dentry); - - return 0; -} - -static const struct file_operations sof_msg_inject_fops = { - .open = sof_msg_inject_dfs_open, - .read = sof_msg_inject_dfs_read, - .write = sof_msg_inject_dfs_write, - .llseek = default_llseek, - .release = sof_msg_inject_dfs_release, - - .owner = THIS_MODULE, -}; - -static int sof_msg_inject_probe(struct auxiliary_device *auxdev, - const struct auxiliary_device_id *id) -{ - struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev); - struct device *dev = &auxdev->dev; - struct sof_msg_inject_priv *priv; - - /* allocate memory for client data */ - priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->tx_buffer = devm_kmalloc(dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); - priv->rx_buffer = devm_kmalloc(dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); - if (!priv->tx_buffer || !priv->rx_buffer) - return -ENOMEM; - - cdev->data = priv; - - priv->dfs_file = debugfs_create_file("ipc_msg_inject", 0644, debugfs_root, - cdev, &sof_msg_inject_fops); - - /* enable runtime PM */ - pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(dev); - pm_runtime_enable(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_idle(dev); - - return 0; -} - -static void sof_msg_inject_remove(struct auxiliary_device *auxdev) -{ - struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - struct sof_msg_inject_priv *priv = cdev->data; - - pm_runtime_disable(&auxdev->dev); - - debugfs_remove(priv->dfs_file); -} - -static const struct auxiliary_device_id sof_msg_inject_client_id_table[] = { - { .name = "snd_sof.msg_injector" }, - {}, -}; -MODULE_DEVICE_TABLE(auxiliary, sof_msg_inject_client_id_table); - -/* - * No need for driver pm_ops as the generic pm callbacks in the auxiliary bus - * type are enough to ensure that the parent SOF device resumes to bring the DSP - * back to D0. - * Driver name will be set based on KBUILD_MODNAME. - */ -static struct auxiliary_driver sof_msg_inject_client_drv = { - .probe = sof_msg_inject_probe, - .remove = sof_msg_inject_remove, - - .id_table = sof_msg_inject_client_id_table, -}; - -module_auxiliary_driver(sof_msg_inject_client_drv); - -MODULE_DESCRIPTION("SOF IPC Message Injector Client Driver"); -MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 90139049c6584a..c625ae04dd98c8 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -102,25 +102,6 @@ static inline int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) static inline void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev) {} #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) -static int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev) -{ - return sof_client_dev_register(sdev, "msg_injector", 0, NULL, 0); -} - -static void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) -{ - sof_client_dev_unregister(sdev, "msg_injector", 0); -} -#else -static inline int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev) -{ - return 0; -} - -static inline void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) {} -#endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR */ - int sof_register_clients(struct snd_sof_dev *sdev) { int ret; @@ -132,24 +113,13 @@ int sof_register_clients(struct snd_sof_dev *sdev) return ret; } - ret = sof_register_ipc_msg_injector(sdev); - if (ret) { - dev_err(sdev->dev, "IPC message injector client registration failed\n"); - goto err_msg_injector; - } - /* Platform depndent client device registration */ if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients) ret = sof_ops(sdev)->register_ipc_clients(sdev); - if (!ret) - return 0; - - sof_unregister_ipc_msg_injector(sdev); - -err_msg_injector: - sof_unregister_ipc_flood_test(sdev); + if (ret) + sof_unregister_ipc_flood_test(sdev); return ret; } @@ -159,7 +129,6 @@ void sof_unregister_clients(struct snd_sof_dev *sdev) if (sof_ops(sdev) && sof_ops(sdev)->unregister_ipc_clients) sof_ops(sdev)->unregister_ipc_clients(sdev); - sof_unregister_ipc_msg_injector(sdev); sof_unregister_ipc_flood_test(sdev); } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 859a117df8f1ed..93ab8008214832 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -322,6 +322,10 @@ struct snd_sof_dfsentry { enum sof_debugfs_access_type access_type; #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) char *cache_buf; /* buffer to cache the contents of debugfs memory */ +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) + void *msg_inject_tx; + void *msg_inject_rx; #endif struct snd_sof_dev *sdev; struct list_head list; /* list in sdev dfsentry list */ From b47be977f25f00bde7c1f00e8ca075b48a49b783 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:43 +0000 Subject: [PATCH 3/9] Revert "ASoC: SOF: Convert the generic IPC flood test into SOF client" This reverts commit 9676d84f82e2d375a7e998b7da87583081b955a7. --- sound/soc/sof/Kconfig | 16 +- sound/soc/sof/Makefile | 4 - sound/soc/sof/core.c | 1 - sound/soc/sof/debug.c | 231 +++++++++++++ sound/soc/sof/sof-client-ipc-flood-test.c | 395 ---------------------- sound/soc/sof/sof-client.c | 56 +-- sound/soc/sof/sof-priv.h | 6 +- 7 files changed, 241 insertions(+), 468 deletions(-) delete mode 100644 sound/soc/sof/sof-client-ipc-flood-test.c diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index dd763124427220..381eb8d670138b 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -194,23 +194,13 @@ config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE If unsure, select "N". config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST - tristate "SOF enable IPC flood test" - select SND_SOC_SOF_CLIENT + bool "SOF enable IPC flood test" help - This option enables a separate client device for IPC flood test - which can be used to flood the DSP with test IPCs and gather stats - about response times. + This option enables the IPC flood test which can be used to flood + the DSP with test IPCs and gather stats about response times. Say Y if you want to enable IPC flood test. If unsure, select "N". -config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM - int "Number of IPC flood test clients" - range 1 32 - default 2 - depends on SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST - help - Select the number of IPC flood test clients to be created. - config SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR bool "SOF enable IPC message injector" help diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index a054c28702bb00..1c580a80e1a7ad 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -11,8 +11,6 @@ snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o snd-sof-of-objs := sof-of-dev.o -snd-sof-ipc-flood-test-objs := sof-client-ipc-flood-test.o - snd-sof-nocodec-objs := nocodec.o snd-sof-utils-objs := sof-utils.o @@ -26,8 +24,6 @@ obj-$(CONFIG_SND_SOC_SOF_ACPI_DEV) += snd-sof-acpi.o obj-$(CONFIG_SND_SOC_SOF_OF_DEV) += snd-sof-of.o 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_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ obj-$(CONFIG_SND_SOC_SOF_AMD_TOPLEVEL) += amd/ diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index f29fe573ec3cc4..2aabaac9007f55 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -484,4 +484,3 @@ MODULE_AUTHOR("Liam Girdwood"); MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:sof-audio"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index e3a5f77bbd4d04..6d6757075f7c3b 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -234,6 +234,107 @@ static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev, } #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) +#define MAX_IPC_FLOOD_DURATION_MS 1000 +#define MAX_IPC_FLOOD_COUNT 10000 +#define IPC_FLOOD_TEST_RESULT_LEN 512 + +static int sof_debug_ipc_flood_test(struct snd_sof_dev *sdev, + struct snd_sof_dfsentry *dfse, + bool flood_duration_test, + unsigned long ipc_duration_ms, + unsigned long ipc_count) +{ + struct sof_ipc_cmd_hdr hdr; + struct sof_ipc_reply reply; + u64 min_response_time = U64_MAX; + ktime_t start, end, test_end; + u64 avg_response_time = 0; + u64 max_response_time = 0; + u64 ipc_response_time; + int i = 0; + int ret; + + /* configure test IPC */ + hdr.cmd = SOF_IPC_GLB_TEST_MSG | SOF_IPC_TEST_IPC_FLOOD; + hdr.size = sizeof(hdr); + + /* set test end time for duration flood test */ + if (flood_duration_test) + test_end = ktime_get_ns() + ipc_duration_ms * NSEC_PER_MSEC; + + /* send test IPC's */ + while (1) { + start = ktime_get(); + ret = sof_ipc_tx_message(sdev->ipc, hdr.cmd, &hdr, hdr.size, + &reply, sizeof(reply)); + end = ktime_get(); + + if (ret < 0) + break; + + /* compute min and max response times */ + ipc_response_time = ktime_to_ns(ktime_sub(end, start)); + min_response_time = min(min_response_time, ipc_response_time); + max_response_time = max(max_response_time, ipc_response_time); + + /* sum up response times */ + avg_response_time += ipc_response_time; + i++; + + /* test complete? */ + if (flood_duration_test) { + if (ktime_to_ns(end) >= test_end) + break; + } else { + if (i == ipc_count) + break; + } + } + + if (ret < 0) + dev_err(sdev->dev, + "error: ipc flood test failed at %d iterations\n", i); + + /* return if the first IPC fails */ + if (!i) + return ret; + + /* compute average response time */ + do_div(avg_response_time, i); + + /* clear previous test output */ + memset(dfse->cache_buf, 0, IPC_FLOOD_TEST_RESULT_LEN); + + if (flood_duration_test) { + dev_dbg(sdev->dev, "IPC Flood test duration: %lums\n", + ipc_duration_ms); + snprintf(dfse->cache_buf, IPC_FLOOD_TEST_RESULT_LEN, + "IPC Flood test duration: %lums\n", ipc_duration_ms); + } + + dev_dbg(sdev->dev, + "IPC Flood count: %d, Avg response time: %lluns\n", + i, avg_response_time); + dev_dbg(sdev->dev, "Max response time: %lluns\n", + max_response_time); + dev_dbg(sdev->dev, "Min response time: %lluns\n", + min_response_time); + + /* format output string */ + snprintf(dfse->cache_buf + strlen(dfse->cache_buf), + IPC_FLOOD_TEST_RESULT_LEN - strlen(dfse->cache_buf), + "IPC Flood count: %d\nAvg response time: %lluns\n", + i, avg_response_time); + + snprintf(dfse->cache_buf + strlen(dfse->cache_buf), + IPC_FLOOD_TEST_RESULT_LEN - strlen(dfse->cache_buf), + "Max response time: %lluns\nMin response time: %lluns\n", + max_response_time, min_response_time); + + return ret; +} +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) static ssize_t msg_inject_read(struct file *file, char __user *buffer, @@ -336,6 +437,15 @@ static int snd_sof_debugfs_msg_inject_item(struct snd_sof_dev *sdev, static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + unsigned long ipc_duration_ms = 0; + bool flood_duration_test = false; + unsigned long ipc_count = 0; + struct dentry *dentry; + int err; +#endif size_t size; char *string; int ret; @@ -347,6 +457,78 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, size = simple_write_to_buffer(string, count, ppos, buffer, count); ret = size; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + /* + * write op is only supported for ipc_flood_count or + * ipc_flood_duration_ms debugfs entries atm. + * ipc_flood_count floods the DSP with the number of IPC's specified. + * ipc_duration_ms test floods the DSP for the time specified + * in the debugfs entry. + */ + dentry = file->f_path.dentry; + if (strcmp(dentry->d_name.name, "ipc_flood_count") && + strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) { + ret = -EINVAL; + goto out; + } + + if (!strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) + flood_duration_test = true; + + /* test completion criterion */ + if (flood_duration_test) + ret = kstrtoul(string, 0, &ipc_duration_ms); + else + ret = kstrtoul(string, 0, &ipc_count); + if (ret < 0) + goto out; + + /* limit max duration/ipc count for flood test */ + if (flood_duration_test) { + if (!ipc_duration_ms) { + ret = size; + goto out; + } + + /* find the minimum. min() is not used to avoid warnings */ + if (ipc_duration_ms > MAX_IPC_FLOOD_DURATION_MS) + ipc_duration_ms = MAX_IPC_FLOOD_DURATION_MS; + } else { + if (!ipc_count) { + ret = size; + goto out; + } + + /* find the minimum. min() is not used to avoid warnings */ + if (ipc_count > MAX_IPC_FLOOD_COUNT) + ipc_count = MAX_IPC_FLOOD_COUNT; + } + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0 && ret != -EACCES) { + dev_err_ratelimited(sdev->dev, + "error: debugfs write failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + goto out; + } + + /* flood test */ + ret = sof_debug_ipc_flood_test(sdev, dfse, flood_duration_test, + ipc_duration_ms, ipc_count); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: debugfs write failed to idle %d\n", + err); + + /* return size if test is successful */ + if (ret >= 0) + ret = size; +out: +#endif kfree(string); return ret; } @@ -362,6 +544,24 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, int size; u8 *buf; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + struct dentry *dentry; + + dentry = file->f_path.dentry; + if ((!strcmp(dentry->d_name.name, "ipc_flood_count") || + !strcmp(dentry->d_name.name, "ipc_flood_duration_ms"))) { + if (*ppos) + return 0; + + count = strlen(dfse->cache_buf); + size_ret = copy_to_user(buffer, dfse->cache_buf, count); + if (size_ret) + return -EFAULT; + + *ppos += count; + return count; + } +#endif size = dfse->size; /* validate position & count */ @@ -519,6 +719,19 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, dfse->size = size; dfse->sdev = sdev; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + if (!strncmp(name, "ipc_flood", strlen("ipc_flood"))) { + /* + * cache_buf is unused for SOF_DFSENTRY_TYPE_BUF debugfs entries. + * So, use it to save the results of the last IPC flood test. + */ + dfse->cache_buf = devm_kzalloc(sdev->dev, IPC_FLOOD_TEST_RESULT_LEN, + GFP_KERNEL); + if (!dfse->cache_buf) + return -ENOMEM; + } +#endif + debugfs_create_file(name, mode, sdev->debugfs_root, dfse, &sof_dfs_fops); /* add to dfsentry list */ @@ -679,6 +892,24 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return err; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + /* create read-write ipc_flood_count debugfs entry */ + err = snd_sof_debugfs_buf_item(sdev, NULL, 0, + "ipc_flood_count", 0666); + + /* errors are only due to memory allocation, not debugfs */ + if (err < 0) + return err; + + /* create read-write ipc_flood_duration_ms debugfs entry */ + err = snd_sof_debugfs_buf_item(sdev, NULL, 0, + "ipc_flood_duration_ms", 0666); + + /* errors are only due to memory allocation, not debugfs */ + if (err < 0) + return err; +#endif + #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644, &msg_inject_fops); diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c deleted file mode 100644 index 60fb9e10a0aa52..00000000000000 --- a/sound/soc/sof/sof-client-ipc-flood-test.c +++ /dev/null @@ -1,395 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Ranjani Sridharan -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sof-client.h" - -#define MAX_IPC_FLOOD_DURATION_MS 1000 -#define MAX_IPC_FLOOD_COUNT 10000 -#define IPC_FLOOD_TEST_RESULT_LEN 512 -#define SOF_IPC_CLIENT_SUSPEND_DELAY_MS 3000 - -#define DEBUGFS_IPC_FLOOD_COUNT "ipc_flood_count" -#define DEBUGFS_IPC_FLOOD_DURATION "ipc_flood_duration_ms" - -struct sof_ipc_flood_priv { - struct dentry *dfs_root; - struct dentry *dfs_link[2]; - char *buf; -}; - -static int sof_ipc_flood_dfs_open(struct inode *inode, struct file *file) -{ - struct sof_client_dev *cdev = inode->i_private; - int ret; - - if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED) - return -ENODEV; - - ret = debugfs_file_get(file->f_path.dentry); - if (unlikely(ret)) - return ret; - - ret = simple_open(inode, file); - if (ret) - debugfs_file_put(file->f_path.dentry); - - return ret; -} - -/* - * helper function to perform the flood test. Only one of the two params, ipc_duration_ms - * or ipc_count, will be non-zero and will determine the type of test - */ -static int sof_debug_ipc_flood_test(struct sof_client_dev *cdev, - bool flood_duration_test, - unsigned long ipc_duration_ms, - unsigned long ipc_count) -{ - struct sof_ipc_flood_priv *priv = cdev->data; - struct device *dev = &cdev->auxdev.dev; - struct sof_ipc_cmd_hdr hdr; - struct sof_ipc_reply reply; - u64 min_response_time = U64_MAX; - ktime_t start, end, test_end; - u64 avg_response_time = 0; - u64 max_response_time = 0; - u64 ipc_response_time; - int i = 0; - int ret; - - /* configure test IPC */ - hdr.cmd = SOF_IPC_GLB_TEST_MSG | SOF_IPC_TEST_IPC_FLOOD; - hdr.size = sizeof(hdr); - - /* set test end time for duration flood test */ - if (flood_duration_test) - test_end = ktime_get_ns() + ipc_duration_ms * NSEC_PER_MSEC; - - /* send test IPC's */ - while (1) { - start = ktime_get(); - ret = sof_client_ipc_tx_message(cdev, &hdr, &reply, sizeof(reply)); - end = ktime_get(); - - if (ret < 0) - break; - - /* compute min and max response times */ - ipc_response_time = ktime_to_ns(ktime_sub(end, start)); - min_response_time = min(min_response_time, ipc_response_time); - max_response_time = max(max_response_time, ipc_response_time); - - /* sum up response times */ - avg_response_time += ipc_response_time; - i++; - - /* test complete? */ - if (flood_duration_test) { - if (ktime_to_ns(end) >= test_end) - break; - } else { - if (i == ipc_count) - break; - } - } - - if (ret < 0) - dev_err(dev, "ipc flood test failed at %d iterations\n", i); - - /* return if the first IPC fails */ - if (!i) - return ret; - - /* compute average response time */ - do_div(avg_response_time, i); - - /* clear previous test output */ - memset(priv->buf, 0, IPC_FLOOD_TEST_RESULT_LEN); - - if (!ipc_count) { - dev_dbg(dev, "IPC Flood test duration: %lums\n", ipc_duration_ms); - snprintf(priv->buf, IPC_FLOOD_TEST_RESULT_LEN, - "IPC Flood test duration: %lums\n", ipc_duration_ms); - } - - dev_dbg(dev, "IPC Flood count: %d, Avg response time: %lluns\n", - i, avg_response_time); - dev_dbg(dev, "Max response time: %lluns\n", max_response_time); - dev_dbg(dev, "Min response time: %lluns\n", min_response_time); - - /* format output string and save test results */ - snprintf(priv->buf + strlen(priv->buf), - IPC_FLOOD_TEST_RESULT_LEN - strlen(priv->buf), - "IPC Flood count: %d\nAvg response time: %lluns\n", - i, avg_response_time); - - snprintf(priv->buf + strlen(priv->buf), - IPC_FLOOD_TEST_RESULT_LEN - strlen(priv->buf), - "Max response time: %lluns\nMin response time: %lluns\n", - max_response_time, min_response_time); - - return ret; -} - -/* - * Writing to the debugfs entry initiates the IPC flood test based on - * the IPC count or the duration specified by the user. - */ -static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct sof_client_dev *cdev = file->private_data; - struct device *dev = &cdev->auxdev.dev; - unsigned long ipc_duration_ms = 0; - bool flood_duration_test = false; - unsigned long ipc_count = 0; - struct dentry *dentry; - int err; - size_t size; - char *string; - int ret; - - string = kzalloc(count + 1, GFP_KERNEL); - if (!string) - return -ENOMEM; - - size = simple_write_to_buffer(string, count, ppos, buffer, count); - - /* - * write op is only supported for ipc_flood_count or - * ipc_flood_duration_ms debugfs entries atm. - * ipc_flood_count floods the DSP with the number of IPC's specified. - * ipc_duration_ms test floods the DSP for the time specified - * in the debugfs entry. - */ - dentry = file->f_path.dentry; - if (strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) && - strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) { - ret = -EINVAL; - goto out; - } - - if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) - flood_duration_test = true; - - /* test completion criterion */ - if (flood_duration_test) - ret = kstrtoul(string, 0, &ipc_duration_ms); - else - ret = kstrtoul(string, 0, &ipc_count); - if (ret < 0) - goto out; - - /* limit max duration/ipc count for flood test */ - if (flood_duration_test) { - if (!ipc_duration_ms) { - ret = size; - goto out; - } - - /* find the minimum. min() is not used to avoid warnings */ - if (ipc_duration_ms > MAX_IPC_FLOOD_DURATION_MS) - ipc_duration_ms = MAX_IPC_FLOOD_DURATION_MS; - } else { - if (!ipc_count) { - ret = size; - goto out; - } - - /* find the minimum. min() is not used to avoid warnings */ - if (ipc_count > MAX_IPC_FLOOD_COUNT) - ipc_count = MAX_IPC_FLOOD_COUNT; - } - - ret = pm_runtime_get_sync(dev); - if (ret < 0 && ret != -EACCES) { - dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret); - pm_runtime_put_noidle(dev); - goto out; - } - - /* flood test */ - ret = sof_debug_ipc_flood_test(cdev, flood_duration_test, - ipc_duration_ms, ipc_count); - - pm_runtime_mark_last_busy(dev); - err = pm_runtime_put_autosuspend(dev); - if (err < 0) - dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); - - /* return size if test is successful */ - if (ret >= 0) - ret = size; -out: - kfree(string); - return ret; -} - -/* return the result of the last IPC flood test */ -static ssize_t sof_ipc_flood_dfs_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct sof_client_dev *cdev = file->private_data; - struct sof_ipc_flood_priv *priv = cdev->data; - size_t size_ret; - - struct dentry *dentry; - - dentry = file->f_path.dentry; - if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) || - !strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) { - if (*ppos) - return 0; - - count = min_t(size_t, count, strlen(priv->buf)); - size_ret = copy_to_user(buffer, priv->buf, count); - if (size_ret) - return -EFAULT; - - *ppos += count; - return count; - } - return count; -} - -static int sof_ipc_flood_dfs_release(struct inode *inode, struct file *file) -{ - debugfs_file_put(file->f_path.dentry); - - return 0; -} - -static const struct file_operations sof_ipc_flood_fops = { - .open = sof_ipc_flood_dfs_open, - .read = sof_ipc_flood_dfs_read, - .llseek = default_llseek, - .write = sof_ipc_flood_dfs_write, - .release = sof_ipc_flood_dfs_release, - - .owner = THIS_MODULE, -}; - -/* - * The IPC test client creates a couple of debugfs entries that will be used - * flood tests. Users can write to these entries to execute the IPC flood test - * by specifying either the number of IPCs to flood the DSP with or the duration - * (in ms) for which the DSP should be flooded with test IPCs. At the - * end of each test, the average, min and max response times are reported back. - * The results of the last flood test can be accessed by reading the debugfs - * entries. - */ -static int sof_ipc_flood_probe(struct auxiliary_device *auxdev, - const struct auxiliary_device_id *id) -{ - struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev); - struct device *dev = &auxdev->dev; - struct sof_ipc_flood_priv *priv; - - /* allocate memory for client data */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->buf = devm_kmalloc(dev, IPC_FLOOD_TEST_RESULT_LEN, GFP_KERNEL); - if (!priv->buf) - return -ENOMEM; - - cdev->data = priv; - - /* create debugfs root folder with device name under parent SOF dir */ - priv->dfs_root = debugfs_create_dir(dev_name(dev), debugfs_root); - if (!IS_ERR_OR_NULL(priv->dfs_root)) { - /* create read-write ipc_flood_count debugfs entry */ - debugfs_create_file(DEBUGFS_IPC_FLOOD_COUNT, 0644, priv->dfs_root, - cdev, &sof_ipc_flood_fops); - - /* create read-write ipc_flood_duration_ms debugfs entry */ - debugfs_create_file(DEBUGFS_IPC_FLOOD_DURATION, 0644, - priv->dfs_root, cdev, &sof_ipc_flood_fops); - - if (auxdev->id == 0) { - /* - * Create symlinks for backwards compatibility to the - * first IPC flood test instance - */ - char target[100]; - - snprintf(target, 100, "%s/" DEBUGFS_IPC_FLOOD_COUNT, - dev_name(dev)); - priv->dfs_link[0] = - debugfs_create_symlink(DEBUGFS_IPC_FLOOD_COUNT, - debugfs_root, target); - - snprintf(target, 100, "%s/" DEBUGFS_IPC_FLOOD_DURATION, - dev_name(dev)); - priv->dfs_link[1] = - debugfs_create_symlink(DEBUGFS_IPC_FLOOD_DURATION, - debugfs_root, target); - } - } - - /* enable runtime PM */ - pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(dev); - pm_runtime_enable(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_idle(dev); - - return 0; -} - -static void sof_ipc_flood_remove(struct auxiliary_device *auxdev) -{ - struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - struct sof_ipc_flood_priv *priv = cdev->data; - - pm_runtime_disable(&auxdev->dev); - - if (auxdev->id == 0) { - debugfs_remove(priv->dfs_link[0]); - debugfs_remove(priv->dfs_link[1]); - } - - debugfs_remove_recursive(priv->dfs_root); -} - -static const struct auxiliary_device_id sof_ipc_flood_client_id_table[] = { - { .name = "snd_sof.ipc_flood" }, - {}, -}; -MODULE_DEVICE_TABLE(auxiliary, sof_ipc_flood_client_id_table); - -/* - * No need for driver pm_ops as the generic pm callbacks in the auxiliary bus - * type are enough to ensure that the parent SOF device resumes to bring the DSP - * back to D0. - * Driver name will be set based on KBUILD_MODNAME. - */ -static struct auxiliary_driver sof_ipc_flood_client_drv = { - .probe = sof_ipc_flood_probe, - .remove = sof_ipc_flood_remove, - - .id_table = sof_ipc_flood_client_id_table, -}; - -module_auxiliary_driver(sof_ipc_flood_client_drv); - -MODULE_DESCRIPTION("SOF IPC Flood Test Client Driver"); -MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index c625ae04dd98c8..6ccf1edfe68168 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -66,70 +66,18 @@ static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) -static int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) -{ - int ret = 0; - int 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); - if (ret < 0) - break; - } - - if (ret) { - for (; i >= 0; --i) - sof_client_dev_unregister(sdev, "ipc_flood", i); - } - - return ret; -} - -static void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev) -{ - int i; - - for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) - sof_client_dev_unregister(sdev, "ipc_flood", i); -} -#else -static inline int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) -{ - return 0; -} - -static inline void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev) {} -#endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST */ - int sof_register_clients(struct snd_sof_dev *sdev) { - int ret; - - /* Register platform independent client devices */ - ret = sof_register_ipc_flood_test(sdev); - if (ret) { - dev_err(sdev->dev, "IPC flood test client registration failed\n"); - return ret; - } - - /* Platform depndent client device registration */ - if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients) - ret = sof_ops(sdev)->register_ipc_clients(sdev); - - if (ret) - sof_unregister_ipc_flood_test(sdev); + return sof_ops(sdev)->register_ipc_clients(sdev); - return ret; + return 0; } void sof_unregister_clients(struct snd_sof_dev *sdev) { if (sof_ops(sdev) && sof_ops(sdev)->unregister_ipc_clients) sof_ops(sdev)->unregister_ipc_clients(sdev); - - sof_unregister_ipc_flood_test(sdev); } int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 93ab8008214832..23ed692c4e867d 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -67,6 +67,10 @@ bool sof_debug_check_flag(int mask); #define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT) +#define ENABLE_DEBUGFS_CACHEBUF \ + (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) || \ + IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)) + /* So far the primary core on all DSPs has ID 0 */ #define SOF_DSP_PRIMARY_CORE 0 @@ -320,7 +324,7 @@ struct snd_sof_dfsentry { * or if it is accessible only when the DSP is in D0. */ enum sof_debugfs_access_type access_type; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) +#if ENABLE_DEBUGFS_CACHEBUF char *cache_buf; /* buffer to cache the contents of debugfs memory */ #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) From 9f3538c1f4a04dd680ca9649e74cdf6cd26513f3 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:44 +0000 Subject: [PATCH 4/9] Revert "ASoC: SOF: sof-client: Add support for clients not managed by pm framework" This reverts commit de94efbc2243413e58952e38d88acbb02568e096. --- sound/soc/sof/pm.c | 13 +---------- sound/soc/sof/sof-client.c | 46 -------------------------------------- sound/soc/sof/sof-priv.h | 12 ---------- 3 files changed, 1 insertion(+), 70 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 7300ecadabd97e..197a88695fef8a 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -167,9 +167,6 @@ static int sof_resume(struct device *dev, bool runtime_resume) return ret; } - /* Notify clients not managed by pm framework about core resume */ - sof_resume_clients(sdev); - /* notify DSP of system resume */ ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE); if (ret < 0) @@ -183,7 +180,6 @@ static int sof_resume(struct device *dev, bool runtime_resume) static int sof_suspend(struct device *dev, bool runtime_suspend) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - pm_message_t pm_state; u32 target_state = 0; int ret; @@ -209,23 +205,16 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) } target_state = snd_sof_dsp_power_target(sdev); - pm_state.event = target_state; /* Skip to platform-specific suspend if DSP is entering D0 */ - if (target_state == SOF_DSP_PM_D0) { - /* Notify clients not managed by pm framework about core suspend */ - sof_suspend_clients(sdev, pm_state); + if (target_state == SOF_DSP_PM_D0) goto suspend; - } sof_tear_down_pipelines(sdev, false); /* release trace */ snd_sof_release_trace(sdev); - /* Notify clients not managed by pm framework about core suspend */ - sof_suspend_clients(sdev, pm_state); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* cache debugfs contents during runtime suspend */ if (runtime_suspend) diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 6ccf1edfe68168..11efd4ba3381fe 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -169,52 +169,6 @@ int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, } EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); -int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) -{ - struct auxiliary_driver *adrv; - struct sof_client_dev *cdev; - - mutex_lock(&sdev->ipc_client_mutex); - - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { - /* Skip devices without loaded driver */ - if (!cdev->auxdev.dev.driver) - continue; - - adrv = to_auxiliary_drv(cdev->auxdev.dev.driver); - if (adrv->suspend) - adrv->suspend(&cdev->auxdev, state); - } - - mutex_unlock(&sdev->ipc_client_mutex); - - return 0; -} -EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, SND_SOC_SOF_CLIENT); - -int sof_resume_clients(struct snd_sof_dev *sdev) -{ - struct auxiliary_driver *adrv; - struct sof_client_dev *cdev; - - mutex_lock(&sdev->ipc_client_mutex); - - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { - /* Skip devices without loaded driver */ - if (!cdev->auxdev.dev.driver) - continue; - - adrv = to_auxiliary_drv(cdev->auxdev.dev.driver); - if (adrv->resume) - adrv->resume(&cdev->auxdev); - } - - mutex_unlock(&sdev->ipc_client_mutex); - - return 0; -} -EXPORT_SYMBOL_NS_GPL(sof_resume_clients, SND_SOC_SOF_CLIENT); - struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) { return cdev->sdev->debugfs_root; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 23ed692c4e867d..6e65830a4ed55e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -676,8 +676,6 @@ int sof_register_clients(struct snd_sof_dev *sdev); void sof_unregister_clients(struct snd_sof_dev *sdev); void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf); void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev); -int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state); -int sof_resume_clients(struct snd_sof_dev *sdev); #else /* CONFIG_SND_SOC_SOF_CLIENT */ static inline int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, const void *data, size_t size) @@ -706,16 +704,6 @@ static inline void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void * static inline void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) { } - -static inline int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) -{ - return 0; -} - -static inline int sof_resume_clients(struct snd_sof_dev *sdev) -{ - return 0; -} #endif /* CONFIG_SND_SOC_SOF_CLIENT */ #endif From 6cd65475662f4d8da06e31de1dad8a751074ada9 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:45 +0000 Subject: [PATCH 5/9] Revert "ASoC: SOF: Introduce IPC SOF client support" This reverts commit 69cfa480b37a5409babf7d7906b06c86df24b776. --- sound/soc/sof/Kconfig | 7 - sound/soc/sof/Makefile | 1 - sound/soc/sof/core.c | 43 +---- sound/soc/sof/ipc.c | 25 ++- sound/soc/sof/sof-client.c | 340 ------------------------------------- sound/soc/sof/sof-client.h | 67 -------- sound/soc/sof/sof-priv.h | 78 +-------- 7 files changed, 21 insertions(+), 540 deletions(-) delete mode 100644 sound/soc/sof/sof-client.c delete mode 100644 sound/soc/sof/sof-client.h diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 381eb8d670138b..ac34c330cf0c0c 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -61,13 +61,6 @@ 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 AUXILIARY_BUS - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - config SND_SOC_SOF_DEVELOPER_SUPPORT bool "SOF developer options support" depends on EXPERT diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 1c580a80e1a7ad..17fb9fcf0b3e79 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -2,7 +2,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 diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 2aabaac9007f55..8f32b5b12b3e91 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -122,27 +122,6 @@ void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level, } EXPORT_SYMBOL(sof_print_oops_and_stack); -/* Helper to manage DSP state */ -void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state) -{ - if (sdev->fw_state == new_state) - return; - - dev_dbg(sdev->dev, "fw_state change: %d -> %d\n", sdev->fw_state, new_state); - sdev->fw_state = new_state; - - switch (new_state) { - case SOF_FW_BOOT_NOT_STARTED: - case SOF_FW_BOOT_COMPLETE: - case SOF_FW_CRASHED: - sof_client_fw_state_dispatcher(sdev); - fallthrough; - default: - break; - } -} -EXPORT_SYMBOL(sof_set_fw_state); - /* * FW Boot State Transition Diagram * @@ -287,12 +266,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_trace_err; } - ret = sof_register_clients(sdev); - if (ret < 0) { - dev_err(sdev->dev, "failed to register clients %d\n", ret); - goto sof_machine_err; - } - /* * Some platforms in SOF, ex: BYT, may not have their platform PM * callbacks set. Increment the usage count so as to @@ -308,8 +281,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return 0; -sof_machine_err: - snd_sof_machine_unregister(sdev, plat_data); fw_trace_err: snd_sof_free_trace(sdev); fw_run_err: @@ -358,6 +329,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->pdata = plat_data; sdev->first_boot = true; + sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID; #endif @@ -378,14 +350,9 @@ 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->ipc_client_list); - INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); - INIT_LIST_HEAD(&sdev->fw_state_handler_list); spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); mutex_init(&sdev->power_state_access); - mutex_init(&sdev->ipc_client_mutex); - mutex_init(&sdev->client_event_handler_mutex); /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) @@ -397,8 +364,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) else sdev->boot_timeout = plat_data->desc->boot_timeout; - sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); - if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) { INIT_WORK(&sdev->probe_work, sof_probe_work); schedule_work(&sdev->probe_work); @@ -426,12 +391,6 @@ int snd_sof_device_remove(struct device *dev) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) cancel_work_sync(&sdev->probe_work); - /* - * Unregister any registered client device first before IPC and debugfs - * to allow client drivers to be removed cleanly - */ - sof_unregister_clients(sdev); - /* * Unregister machine driver. This will unbind the snd_card which * will remove the component driver and unload the topology diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index a9836e47567dc9..09a86ee21b7c0d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -541,25 +541,22 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) break; } - /* read the full message */ - msg_buf = kmalloc(hdr.size, GFP_KERNEL); - if (!msg_buf) - return; + if (rx_callback) { + /* read the full message as we have rx handler for it */ + msg_buf = kmalloc(hdr.size, GFP_KERNEL); + if (!msg_buf) + return; - err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size); - if (err < 0) { - dev_err(sdev->dev, "%s: Failed to read message: %d\n", __func__, err); - } else { - /* Call local handler for the message */ - if (rx_callback) + err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size); + if (err < 0) + dev_err(sdev->dev, "%s: Failed to read message: %d\n", + __func__, err); + else rx_callback(sdev, msg_buf); - /* Notify registered clients */ - sof_client_ipc_rx_dispatcher(sdev, msg_buf); + kfree(msg_buf); } - kfree(msg_buf); - ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); } EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c deleted file mode 100644 index 11efd4ba3381fe..00000000000000 --- a/sound/soc/sof/sof-client.c +++ /dev/null @@ -1,340 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Authors: Ranjani Sridharan -// Peter Ujfalusi -// - -#include -#include -#include -#include -#include -#include -#include "ops.h" -#include "sof-client.h" -#include "sof-priv.h" - -/** - * struct sof_ipc_event_entry - IPC client event description - * @ipc_msg_type: IPC msg type of the event the client is interested - * @cdev: sof_client_dev of the requesting client - * @callback: Callback function of the client - * @list: item in SOF core client event list - */ -struct sof_ipc_event_entry { - u32 ipc_msg_type; - struct sof_client_dev *cdev; - sof_client_event_callback callback; - struct list_head list; -}; - -/** - * struct sof_state_event_entry - DSP panic event subscription entry - * @cdev: sof_client_dev of the requesting client - * @callback: Callback function of the client - * @list: item in SOF core client event list - */ -struct sof_state_event_entry { - struct sof_client_dev *cdev; - sof_client_fw_state_callback callback; - struct list_head list; -}; - -static void sof_client_auxdev_release(struct device *dev) -{ - struct auxiliary_device *auxdev = to_auxiliary_dev(dev); - struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - - kfree(cdev->auxdev.dev.platform_data); - kfree(cdev); -} - -static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data, - size_t size) -{ - void *d = NULL; - - if (data) { - d = kmemdup(data, size, GFP_KERNEL); - if (!d) - return -ENOMEM; - } - - cdev->auxdev.dev.platform_data = d; - return 0; -} - -int sof_register_clients(struct snd_sof_dev *sdev) -{ - if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients) - return sof_ops(sdev)->register_ipc_clients(sdev); - - return 0; -} - -void sof_unregister_clients(struct snd_sof_dev *sdev) -{ - if (sof_ops(sdev) && sof_ops(sdev)->unregister_ipc_clients) - sof_ops(sdev)->unregister_ipc_clients(sdev); -} - -int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, - const void *data, size_t size) -{ - struct auxiliary_device *auxdev; - struct sof_client_dev *cdev; - int ret; - - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (!cdev) - return -ENOMEM; - - cdev->sdev = sdev; - auxdev = &cdev->auxdev; - auxdev->name = name; - auxdev->dev.parent = sdev->dev; - auxdev->dev.release = sof_client_auxdev_release; - auxdev->id = id; - - ret = sof_client_dev_add_data(cdev, data, size); - if (ret < 0) - goto err_dev_add_data; - - ret = auxiliary_device_init(auxdev); - if (ret < 0) { - dev_err(sdev->dev, "failed to initialize client dev %s.%d\n", name, id); - goto err_dev_init; - } - - ret = auxiliary_device_add(&cdev->auxdev); - if (ret < 0) { - dev_err(sdev->dev, "failed to add client dev %s.%d\n", name, id); - /* - * sof_client_auxdev_release() will be invoked to free up memory - * allocations through put_device() - */ - auxiliary_device_uninit(&cdev->auxdev); - return ret; - } - - /* add to list of SOF client devices */ - mutex_lock(&sdev->ipc_client_mutex); - list_add(&cdev->list, &sdev->ipc_client_list); - mutex_unlock(&sdev->ipc_client_mutex); - - return 0; - -err_dev_init: - kfree(cdev->auxdev.dev.platform_data); - -err_dev_add_data: - kfree(cdev); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT); - -void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id) -{ - struct sof_client_dev *cdev; - - mutex_lock(&sdev->ipc_client_mutex); - - /* - * sof_client_auxdev_release() will be invoked to free up memory - * allocations through put_device() - */ - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { - if (!strcmp(cdev->auxdev.name, name) && cdev->auxdev.id == id) { - list_del(&cdev->list); - auxiliary_device_delete(&cdev->auxdev); - auxiliary_device_uninit(&cdev->auxdev); - break; - } - } - - mutex_unlock(&sdev->ipc_client_mutex); -} -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, - void *reply_data, size_t reply_bytes) -{ - struct sof_ipc_cmd_hdr *hdr = ipc_msg; - - return sof_ipc_tx_message(cdev->sdev->ipc, hdr->cmd, ipc_msg, hdr->size, - 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); - -/* DMA buffer allocation in client drivers must use the core SOF device */ -struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) -{ - return cdev->sdev->dev; -} -EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT); - -const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - - return &sdev->fw_ready.version; -} -EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); - -/* module refcount management of SOF core */ -int sof_client_core_module_get(struct sof_client_dev *cdev) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - - if (!try_module_get(sdev->dev->driver->owner)) - return -ENODEV; - - return 0; -} -EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT); - -void sof_client_core_module_put(struct sof_client_dev *cdev) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - - module_put(sdev->dev->driver->owner); -} -EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); - -/* IPC event handling */ -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; - - mutex_lock(&sdev->client_event_handler_mutex); - - list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) { - if (event->ipc_msg_type == msg_type) - event->callback(event->cdev, msg_buf); - } - - mutex_unlock(&sdev->client_event_handler_mutex); -} - -int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, - u32 ipc_msg_type, - sof_client_event_callback callback) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - struct sof_ipc_event_entry *event; - - if (!callback || !(ipc_msg_type & SOF_GLB_TYPE_MASK)) - return -EINVAL; - - event = kmalloc(sizeof(*event), GFP_KERNEL); - if (!event) - return -ENOMEM; - - event->ipc_msg_type = ipc_msg_type; - event->cdev = cdev; - event->callback = callback; - - /* add to list of SOF client devices */ - mutex_lock(&sdev->client_event_handler_mutex); - list_add(&event->list, &sdev->ipc_rx_handler_list); - mutex_unlock(&sdev->client_event_handler_mutex); - - return 0; -} -EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT); - -void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, - u32 ipc_msg_type) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - struct sof_ipc_event_entry *event; - - mutex_lock(&sdev->client_event_handler_mutex); - - list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) { - if (event->cdev == cdev && event->ipc_msg_type == ipc_msg_type) { - list_del(&event->list); - kfree(event); - break; - } - } - - mutex_unlock(&sdev->client_event_handler_mutex); -} -EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT); - -/*DSP state notification and query */ -void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) -{ - struct sof_state_event_entry *event; - - mutex_lock(&sdev->client_event_handler_mutex); - - list_for_each_entry(event, &sdev->fw_state_handler_list, list) - event->callback(event->cdev, sdev->fw_state); - - mutex_unlock(&sdev->client_event_handler_mutex); -} - -int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, - sof_client_fw_state_callback callback) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - struct sof_state_event_entry *event; - - if (!callback) - return -EINVAL; - - event = kmalloc(sizeof(*event), GFP_KERNEL); - if (!event) - return -ENOMEM; - - event->cdev = cdev; - event->callback = callback; - - /* add to list of SOF client devices */ - mutex_lock(&sdev->client_event_handler_mutex); - list_add(&event->list, &sdev->fw_state_handler_list); - mutex_unlock(&sdev->client_event_handler_mutex); - - return 0; -} -EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT); - -void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - struct sof_state_event_entry *event; - - mutex_lock(&sdev->client_event_handler_mutex); - - list_for_each_entry(event, &sdev->fw_state_handler_list, list) { - if (event->cdev == cdev) { - list_del(&event->list); - kfree(event); - break; - } - } - - mutex_unlock(&sdev->client_event_handler_mutex); -} -EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT); - -enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) -{ - struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - - return sdev->fw_state; -} -EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT); diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h deleted file mode 100644 index 4b6394b4c6940d..00000000000000 --- a/sound/soc/sof/sof-client.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#ifndef __SOC_SOF_CLIENT_H -#define __SOC_SOF_CLIENT_H - -#include -#include -#include -#include - -struct sof_ipc_fw_version; -struct sof_ipc_cmd_hdr; -struct snd_sof_dev; -struct dentry; - -/** - * struct sof_client_dev - SOF client device - * @auxdev: auxiliary device - * @sdev: pointer to SOF core device struct - * @list: item in SOF core client dev list - * @data: device specific data - */ -struct sof_client_dev { - struct auxiliary_device auxdev; - struct snd_sof_dev *sdev; - struct list_head list; - void *data; -}; - -#define sof_client_dev_to_sof_dev(cdev) ((cdev)->sdev) - -#define auxiliary_dev_to_sof_client_dev(auxiliary_dev) \ - container_of(auxiliary_dev, struct sof_client_dev, auxdev) - -#define dev_to_sof_client_dev(dev) \ - container_of(to_auxiliary_dev(dev), struct sof_client_dev, auxdev) - -int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, - void *reply_data, size_t reply_bytes); - -struct dentry *sof_client_get_debugfs_root(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); - -/* module refcount management of SOF core */ -int sof_client_core_module_get(struct sof_client_dev *cdev); -void sof_client_core_module_put(struct sof_client_dev *cdev); - -/* IPC notification */ -typedef void (*sof_client_event_callback)(struct sof_client_dev *cdev, void *msg_buf); - -int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, - u32 ipc_msg_type, - sof_client_event_callback callback); -void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, - u32 ipc_msg_type); - -/* DSP state notification and query */ -typedef void (*sof_client_fw_state_callback)(struct sof_client_dev *cdev, - enum sof_fw_state state); - -int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, - sof_client_fw_state_callback callback); -void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev); -enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev); - -#endif /* __SOC_SOF_CLIENT_H */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6e65830a4ed55e..b9eecec41a9144 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -290,10 +290,6 @@ struct snd_sof_dsp_ops { void (*set_mach_params)(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev); /* optional */ - /* IPC client ops */ - int (*register_ipc_clients)(struct snd_sof_dev *sdev); /* optional */ - void (*unregister_ipc_clients)(struct snd_sof_dev *sdev); /* optional */ - /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; @@ -495,30 +491,6 @@ struct snd_sof_dev { */ int dsp_core_ref_count[SOF_MAX_DSP_NUM_CORES]; - /* - * Used to keep track of registered IPC client devices so that they can - * be removed when the parent SOF module is removed. - */ - struct list_head ipc_client_list; - - /* mutex to protect client list */ - struct mutex ipc_client_mutex; - - /* - * Used for tracking the IPC client's RX registration for DSP initiated - * message handling. - */ - struct list_head ipc_rx_handler_list; - - /* - * Used for tracking the IPC client's registration for DSP state change - * notification - */ - struct list_head fw_state_handler_list; - - /* to protect the ipc_rx_handler_list and dsp_state_handler_list list */ - struct mutex client_event_handler_mutex; - void *private; /* core does not touch this */ }; @@ -628,7 +600,15 @@ extern const struct dsp_arch_ops sof_xtensa_arch_ops; /* * Firmware state tracking */ -void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state); +static inline void sof_set_fw_state(struct snd_sof_dev *sdev, + enum sof_fw_state new_state) +{ + if (sdev->fw_state == new_state) + return; + + dev_dbg(sdev->dev, "fw_state change: %d -> %d\n", sdev->fw_state, new_state); + sdev->fw_state = new_state; +} /* * Utilities @@ -666,44 +646,4 @@ static inline int sof_get_abi_major(struct snd_sof_dev *sdev) { return SOF_ABI_VERSION_MAJOR(sdev->fw_ready.version.abi_version); } - -/* SOF client support */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_CLIENT) -int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, - const void *data, size_t size); -void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id); -int sof_register_clients(struct snd_sof_dev *sdev); -void sof_unregister_clients(struct snd_sof_dev *sdev); -void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf); -void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev); -#else /* CONFIG_SND_SOC_SOF_CLIENT */ -static inline int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, - u32 id, const void *data, size_t size) -{ - return 0; -} - -static inline void sof_client_dev_unregister(struct snd_sof_dev *sdev, - const char *name, u32 id) -{ -} - -static inline int sof_register_clients(struct snd_sof_dev *sdev) -{ - return 0; -} - -static inline void sof_unregister_clients(struct snd_sof_dev *sdev) -{ -} - -static inline void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) -{ -} - -static inline void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) -{ -} -#endif /* CONFIG_SND_SOC_SOF_CLIENT */ - #endif From 95f335c12cffbae4f4c48589ca57c32cb5a729c6 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:46 +0000 Subject: [PATCH 6/9] Revert "ASoC: SOF: Split up utils.c into sof-utils and iomem-utils" This reverts commit 2561ff53bddf00084a9009dc31bdcd1d7e86fcdc. --- sound/soc/sof/Makefile | 5 +- sound/soc/sof/pcm.c | 1 - sound/soc/sof/sof-priv.h | 4 ++ sound/soc/sof/sof-utils.c | 77 ------------------------ sound/soc/sof/sof-utils.h | 19 ------ sound/soc/sof/trace.c | 1 - sound/soc/sof/{iomem-utils.c => utils.c} | 61 ++++++++++++++++++- 7 files changed, 65 insertions(+), 103 deletions(-) delete mode 100644 sound/soc/sof/sof-utils.c delete mode 100644 sound/soc/sof/sof-utils.h rename sound/soc/sof/{iomem-utils.c => utils.c} (59%) diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 17fb9fcf0b3e79..6f76927e0a1c2f 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 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 + control.o trace.o utils.o sof-audio.o stream-ipc.o ipc4.o snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o @@ -12,12 +12,9 @@ snd-sof-of-objs := sof-of-dev.o snd-sof-nocodec-objs := nocodec.o -snd-sof-utils-objs := sof-utils.o - obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o -obj-$(CONFIG_SND_SOC_SOF) += snd-sof-utils.o obj-$(CONFIG_SND_SOC_SOF_ACPI_DEV) += snd-sof-acpi.o obj-$(CONFIG_SND_SOC_SOF_OF_DEV) += snd-sof-of.o diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 02c75a23c67f66..e4446defe51e91 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -19,7 +19,6 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) #include "sof-probes.h" #endif -#include "sof-utils.h" /* Create DMA buffer page table for DSP */ static int create_page_table(struct snd_soc_component *component, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index b9eecec41a9144..de1f544de9932d 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -514,6 +514,10 @@ void snd_sof_complete(struct device *dev); void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); +int snd_sof_create_page_table(struct device *dev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size); + /* * Firmware loading. */ diff --git a/sound/soc/sof/sof-utils.c b/sound/soc/sof/sof-utils.c deleted file mode 100644 index 0d48f7174ec237..00000000000000 --- a/sound/soc/sof/sof-utils.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. -// -// Author: Keyon Jie -// - -#include -#include -#include -#include -#include -#include "sof-utils.h" - -/* - * Generic buffer page table creation. - * Take the each physical page address and drop the least significant unused - * bits from each (based on PAGE_SIZE). Then pack valid page address bits - * into compressed page table. - */ - -int snd_sof_create_page_table(struct device *dev, - struct snd_dma_buffer *dmab, - unsigned char *page_table, size_t size) -{ - int i, pages; - - pages = snd_sgbuf_aligned_pages(size); - - dev_dbg(dev, "generating page table for %p size 0x%zx pages %d\n", - dmab->area, size, pages); - - for (i = 0; i < pages; i++) { - /* - * The number of valid address bits for each page is 20. - * idx determines the byte position within page_table - * where the current page's address is stored - * in the compressed page_table. - * This can be calculated by multiplying the page number by 2.5. - */ - u32 idx = (5 * i) >> 1; - u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; - u8 *pg_table; - - dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - - pg_table = (u8 *)(page_table + idx); - - /* - * pagetable compression: - * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 - * ___________pfn 0__________ __________pfn 1___________ _pfn 2... - * .... .... .... .... .... .... .... .... .... .... .... - * It is created by: - * 1. set current location to 0, PFN index i to 0 - * 2. put pfn[i] at current location in Little Endian byte order - * 3. calculate an intermediate value as - * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) - * 4. put x at offset (current location + 2) in LE byte order - * 5. increment current location by 5 bytes, increment i by 2 - * 6. continue to (2) - */ - if (i & 1) - put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, - pg_table); - else - put_unaligned_le32(pfn, pg_table); - } - - return pages; -} -EXPORT_SYMBOL(snd_sof_create_page_table); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/sof-utils.h b/sound/soc/sof/sof-utils.h deleted file mode 100644 index cf508ff7ff5ede..00000000000000 --- a/sound/soc/sof/sof-utils.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2021 Intel Corporation. All rights reserved. - */ - -#ifndef __SOC_SOF_UTILS_H -#define __SOC_SOF_UTILS_H - -struct snd_dma_buffer; -struct device; - -int snd_sof_create_page_table(struct device *dev, - struct snd_dma_buffer *dmab, - unsigned char *page_table, size_t size); - -#endif diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 104388c551cb3f..2335d0f06d4239 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -12,7 +12,6 @@ #include #include "sof-priv.h" #include "ops.h" -#include "sof-utils.h" #define TRACE_FILTER_ELEMENTS_PER_ENTRY 4 #define TRACE_FILTER_MAX_CONFIG_STRING_LENGTH 1024 diff --git a/sound/soc/sof/iomem-utils.c b/sound/soc/sof/utils.c similarity index 59% rename from sound/soc/sof/iomem-utils.c rename to sound/soc/sof/utils.c index 7228a6e041c39f..66fa6602fb67a3 100644 --- a/sound/soc/sof/iomem-utils.c +++ b/sound/soc/sof/utils.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. +// Copyright(c) 2018 Intel Corporation. All rights reserved. // // Author: Keyon Jie // @@ -125,3 +125,62 @@ int sof_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, return 0; } EXPORT_SYMBOL(sof_block_read); + +/* + * Generic buffer page table creation. + * Take the each physical page address and drop the least significant unused + * bits from each (based on PAGE_SIZE). Then pack valid page address bits + * into compressed page table. + */ + +int snd_sof_create_page_table(struct device *dev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size) +{ + int i, pages; + + pages = snd_sgbuf_aligned_pages(size); + + dev_dbg(dev, "generating page table for %p size 0x%zx pages %d\n", + dmab->area, size, pages); + + for (i = 0; i < pages; i++) { + /* + * The number of valid address bits for each page is 20. + * idx determines the byte position within page_table + * where the current page's address is stored + * in the compressed page_table. + * This can be calculated by multiplying the page number by 2.5. + */ + u32 idx = (5 * i) >> 1; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; + u8 *pg_table; + + dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); + + pg_table = (u8 *)(page_table + idx); + + /* + * pagetable compression: + * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 + * ___________pfn 0__________ __________pfn 1___________ _pfn 2... + * .... .... .... .... .... .... .... .... .... .... .... + * It is created by: + * 1. set current location to 0, PFN index i to 0 + * 2. put pfn[i] at current location in Little Endian byte order + * 3. calculate an intermediate value as + * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) + * 4. put x at offset (current location + 2) in LE byte order + * 5. increment current location by 5 bytes, increment i by 2 + * 6. continue to (2) + */ + if (i & 1) + put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, + pg_table); + else + put_unaligned_le32(pfn, pg_table); + } + + return pages; +} +EXPORT_SYMBOL(snd_sof_create_page_table); From fdbaa11658994e6d61e63e6ff411a0d16e783af5 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:47 +0000 Subject: [PATCH 7/9] Revert "ASoC: SOF: ipc: Read and pass the whole message to handlers for IPC events" This reverts commit 9b704f09531cc32cc6beeb3764f21ce698a798d6. --- sound/soc/sof/ipc.c | 85 ++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 09a86ee21b7c0d..710c6ec4ec7a83 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -18,10 +18,8 @@ #include "sof-audio.h" #include "ops.h" -typedef void (*ipc_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf); - -static void ipc_trace_message(struct snd_sof_dev *sdev, void *msg_buf); -static void ipc_stream_message(struct snd_sof_dev *sdev, void *msg_buf); +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_type); +static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); /* * IPC message Tx/Rx message handling. @@ -463,30 +461,44 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) } EXPORT_SYMBOL(snd_sof_ipc_reply); -static void ipc_comp_notification(struct snd_sof_dev *sdev, void *msg_buf) +static void ipc_comp_notification(struct snd_sof_dev *sdev, + struct sof_ipc_cmd_hdr *hdr) { - struct sof_ipc_cmd_hdr *hdr = msg_buf; u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; + struct sof_ipc_ctrl_data *cdata; + int ret; switch (msg_type) { case SOF_IPC_COMP_GET_VALUE: case SOF_IPC_COMP_GET_DATA: + cdata = kmalloc(hdr->size, GFP_KERNEL); + if (!cdata) + return; + + /* read back full message */ + ret = snd_sof_ipc_msg_data(sdev, NULL, cdata, hdr->size); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to read component event: %d\n", ret); + goto err; + } break; default: dev_err(sdev->dev, "error: unhandled component message %#x\n", msg_type); return; } - snd_sof_control_notify(sdev, msg_buf); + snd_sof_control_notify(sdev, cdata); + +err: + kfree(cdata); } /* DSP firmware has sent host a message */ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) { - ipc_rx_callback rx_callback = NULL; struct sof_ipc_cmd_hdr hdr; - void *msg_buf; - u32 cmd; + u32 cmd, type; int err; /* read back header */ @@ -495,15 +507,10 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) dev_warn(sdev->dev, "failed to read IPC header: %d\n", err); return; } - - if (hdr.size < sizeof(hdr)) { - dev_err(sdev->dev, "The received message size is invalid\n"); - return; - } - ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); cmd = hdr.cmd & SOF_GLB_TYPE_MASK; + type = hdr.cmd & SOF_CMD_TYPE_MASK; /* check message type */ switch (cmd) { @@ -528,35 +535,20 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) case SOF_IPC_GLB_PM_MSG: break; case SOF_IPC_GLB_COMP_MSG: - rx_callback = ipc_comp_notification; + ipc_comp_notification(sdev, &hdr); break; case SOF_IPC_GLB_STREAM_MSG: - rx_callback = ipc_stream_message; + /* need to pass msg id into the function */ + ipc_stream_message(sdev, hdr.cmd); break; case SOF_IPC_GLB_TRACE_MSG: - rx_callback = ipc_trace_message; + ipc_trace_message(sdev, type); break; default: - dev_err(sdev->dev, "%s: Unknown DSP message: 0x%x\n", __func__, cmd); + dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd); break; } - if (rx_callback) { - /* read the full message as we have rx handler for it */ - msg_buf = kmalloc(hdr.size, GFP_KERNEL); - if (!msg_buf) - return; - - err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size); - if (err < 0) - dev_err(sdev->dev, "%s: Failed to read message: %d\n", - __func__, err); - else - rx_callback(sdev, msg_buf); - - kfree(msg_buf); - } - ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); } EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); @@ -565,14 +557,19 @@ EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); * IPC trace mechanism. */ -static void ipc_trace_message(struct snd_sof_dev *sdev, void *msg_buf) +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_type) { - struct sof_ipc_cmd_hdr *hdr = msg_buf; - u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; + struct sof_ipc_dma_trace_posn posn; + int ret; switch (msg_type) { case SOF_IPC_TRACE_DMA_POSITION: - snd_sof_trace_update_pos(sdev, msg_buf); + /* read back full message */ + ret = snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn)); + if (ret < 0) + dev_warn(sdev->dev, "failed to read trace position: %d\n", ret); + else + snd_sof_trace_update_pos(sdev, &posn); break; default: dev_err(sdev->dev, "error: unhandled trace message %#x\n", msg_type); @@ -654,11 +651,11 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) } /* stream notifications from DSP FW */ -static void ipc_stream_message(struct snd_sof_dev *sdev, void *msg_buf) +static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) { - struct sof_ipc_cmd_hdr *hdr = msg_buf; - u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; - u32 msg_id = SOF_IPC_MESSAGE_ID(hdr->cmd); + /* get msg cmd type and msd id */ + u32 msg_type = msg_cmd & SOF_CMD_TYPE_MASK; + u32 msg_id = SOF_IPC_MESSAGE_ID(msg_cmd); switch (msg_type) { case SOF_IPC_STREAM_POSITION: From e647ea4576c61050f730298d3b71a371657980b3 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:48 +0000 Subject: [PATCH 8/9] Revert "ASoC: SOF: Move the definition of enum sof_dsp_power_states to global header" This reverts commit af2db260ef23f8214419379b4220822de2bf5c14. --- include/sound/sof.h | 8 -------- sound/soc/sof/sof-priv.h | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 7cdfc954df12df..813680ab9aad4c 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -39,14 +39,6 @@ enum sof_fw_state { SOF_FW_CRASHED, }; -/* DSP power states */ -enum sof_dsp_power_states { - SOF_DSP_PM_D0, - SOF_DSP_PM_D1, - SOF_DSP_PM_D2, - SOF_DSP_PM_D3, -}; - /* * SOF Platform data. */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index de1f544de9932d..abcc055e1c7dfd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -77,6 +77,14 @@ bool sof_debug_check_flag(int mask); /* max number of DSP cores */ #define SOF_MAX_DSP_NUM_CORES 8 +/* DSP power state */ +enum sof_dsp_power_states { + SOF_DSP_PM_D0, + SOF_DSP_PM_D1, + SOF_DSP_PM_D2, + SOF_DSP_PM_D3, +}; + struct sof_dsp_power_state { u32 state; u32 substate; /* platform-specific */ From 42c1f960b65bc87029811f2b6bf6a316f96501dd Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 24 Nov 2021 00:06:49 +0000 Subject: [PATCH 9/9] Revert "ASoC: SOF: Drop unused DSP power states: D3_HOT and D3_COLD" This reverts commit 50b8749e7fba5630e04d9fca2c5a4639b2b99868. --- sound/soc/sof/intel/hda-dsp.c | 6 ++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 8ddde60c56b3f5..0fe522549c912f 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -498,9 +498,15 @@ static void hda_dsp_state_log(struct snd_sof_dev *sdev) case SOF_DSP_PM_D2: dev_dbg(sdev->dev, "Current DSP power state: D2\n"); break; + case SOF_DSP_PM_D3_HOT: + dev_dbg(sdev->dev, "Current DSP power state: D3_HOT\n"); + break; case SOF_DSP_PM_D3: dev_dbg(sdev->dev, "Current DSP power state: D3\n"); break; + case SOF_DSP_PM_D3_COLD: + dev_dbg(sdev->dev, "Current DSP power state: D3_COLD\n"); + break; default: dev_dbg(sdev->dev, "Unknown DSP power state: %d\n", sdev->dsp_power_state.state); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index abcc055e1c7dfd..5061b0078f26a3 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -82,7 +82,9 @@ enum sof_dsp_power_states { SOF_DSP_PM_D0, SOF_DSP_PM_D1, SOF_DSP_PM_D2, + SOF_DSP_PM_D3_HOT, SOF_DSP_PM_D3, + SOF_DSP_PM_D3_COLD, }; struct sof_dsp_power_state {