ASoC: Intel: avs: Add data probing requests
authorCezary Rojewski <cezary.rojewski@intel.com>
Fri, 2 Dec 2022 15:28:34 +0000 (16:28 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 5 Dec 2022 14:05:26 +0000 (14:05 +0000)
Data probing is a cAVS firmware functionality that allows for data
extraction and injection directly from or to DMA stream. To support it,
new functions and types are added. These facilitate communication
with the firmware.

Total of eight IPCs:
- probe module initialization and cleanup
- addition and removal of probe points
- addition and removal of injection DMAs
- dumping list of currently connected probe points or enlisted DMAs

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20221202152841.672536-10-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/avs/Makefile
sound/soc/intel/avs/messages.c
sound/soc/intel/avs/messages.h
sound/soc/intel/avs/probes.c [new file with mode: 0644]

index a211a0b..1c6924a 100644 (file)
@@ -10,7 +10,7 @@ snd-soc-avs-objs += trace.o
 CFLAGS_trace.o := -I$(src)
 
 ifneq ($(CONFIG_DEBUG_FS),)
-snd-soc-avs-objs += debugfs.o
+snd-soc-avs-objs += probes.o debugfs.o
 endif
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
index f734d49..e11ae42 100644 (file)
@@ -722,4 +722,82 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
        return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
                                        AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
 }
+
+int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas)
+{
+       size_t payload_size;
+       u32 module_id;
+       u8 *payload;
+       int ret;
+
+       module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+       ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
+                                      NULL, 0, &payload, &payload_size);
+       if (ret)
+               return ret;
+
+       *dmas = (struct avs_probe_dma *)payload;
+       *num_dmas = payload_size / sizeof(**dmas);
+
+       return 0;
+}
+
+int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas)
+{
+       u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+       return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
+                                       (u8 *)dmas, array_size(sizeof(*dmas), num_dmas));
+}
+
+int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
+                            size_t num_node_ids)
+{
+       u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+       return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
+                                       AVS_PROBE_INJECTION_DMA_DETACH, (u8 *)node_ids,
+                                       array_size(sizeof(*node_ids), num_node_ids));
+}
+
+int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
+                            size_t *num_descs)
+{
+       size_t payload_size;
+       u32 module_id;
+       u8 *payload;
+       int ret;
+
+       module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+       ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS, NULL,
+                                      0, &payload, &payload_size);
+       if (ret)
+               return ret;
+
+       *descs = (struct avs_probe_point_desc *)payload;
+       *num_descs = payload_size / sizeof(**descs);
+
+       return 0;
+}
+
+int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
+                                size_t num_descs)
+{
+       u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+       return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS,
+                                       (u8 *)descs, array_size(sizeof(*descs), num_descs));
+}
+
+int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
+                                   size_t num_ids)
+{
+       u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+       return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
+                                       AVS_PROBE_POINTS_DISCONNECT, (u8 *)ids,
+                                       array_size(sizeof(*ids), num_ids));
+}
 #endif
index 02b3b7a..9dd8355 100644 (file)
@@ -802,4 +802,57 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
                                   const struct avs_audio_format *src_fmt,
                                   const struct avs_audio_format *sink_fmt);
 
+#define AVS_PROBE_INST_ID      0
+
+enum avs_probe_runtime_param {
+       AVS_PROBE_INJECTION_DMA = 1,
+       AVS_PROBE_INJECTION_DMA_DETACH,
+       AVS_PROBE_POINTS,
+       AVS_PROBE_POINTS_DISCONNECT,
+};
+
+struct avs_probe_dma {
+       union avs_connector_node_id node_id;
+       u32 dma_buffer_size;
+} __packed;
+
+enum avs_probe_type {
+       AVS_PROBE_TYPE_INPUT = 0,
+       AVS_PROBE_TYPE_OUTPUT,
+       AVS_PROBE_TYPE_INTERNAL
+};
+
+union avs_probe_point_id {
+       u32 value;
+       struct {
+               u32 module_id:16;
+               u32 instance_id:8;
+               u32 type:2;
+               u32 index:6;
+       } id;
+} __packed;
+
+enum avs_connection_purpose {
+       AVS_CONNECTION_PURPOSE_EXTRACT = 0,
+       AVS_CONNECTION_PURPOSE_INJECT,
+       AVS_CONNECTION_PURPOSE_INJECT_REEXTRACT,
+};
+
+struct avs_probe_point_desc {
+       union avs_probe_point_id id;
+       u32 purpose;
+       union avs_connector_node_id node_id;
+} __packed;
+
+int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas);
+int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas);
+int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
+                            size_t num_node_ids);
+int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
+                            size_t *num_descs);
+int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
+                                size_t num_descs);
+int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
+                                   size_t num_ids);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
new file mode 100644 (file)
index 0000000..339bad6
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include "avs.h"
+#include "messages.h"
+
+__maybe_unused
+static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
+                             size_t buffer_size)
+
+{
+       struct avs_probe_cfg cfg = {{0}};
+       struct avs_module_entry mentry;
+       u16 dummy;
+
+       avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+
+       /*
+        * Probe module uses no cycles, audio data format and input and output
+        * frame sizes are unused. It is also not owned by any pipeline.
+        */
+       cfg.base.ibs = 1;
+       /* BSS module descriptor is always segment of index=2. */
+       cfg.base.is_pages = mentry.segments[2].flags.length;
+       cfg.gtw_cfg.node_id = node_id;
+       cfg.gtw_cfg.dma_buffer_size = buffer_size;
+
+       return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg,
+                                  sizeof(cfg), &dummy);
+}
+
+__maybe_unused
+static void avs_dsp_delete_probe(struct avs_dev *adev)
+{
+       struct avs_module_entry mentry;
+
+       avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+
+       /* There is only ever one probe module instance. */
+       avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
+}