Skip to content

Commit f3b433e

Browse files
crojewsk-intelbroonie
authored andcommitted
ASoC: SOF: Implement Probe IPC API
Add all required types and methods to support each and every request that driver could sent to firmware. Probe is one of SOF firmware features which allows for data extraction and injection directly from or to DMA stream. Exposes eight IPCs: - addition and removal of injection DMAs - addition and removal of probe points - info retrieval of injection DMAs and probe points - probe initialization and cleanup Signed-off-by: Cezary Rojewski <[email protected]> Acked-by: Pierre-Louis Bossart <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 4a9ce6e commit f3b433e

File tree

6 files changed

+394
-1
lines changed

6 files changed

+394
-1
lines changed

include/sound/sof/header.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U)
5252
#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU)
5353
#define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU)
54+
#define SOF_IPC_GLB_PROBE SOF_GLB_TYPE(0xCU)
5455

5556
/*
5657
* DSP Command Message Types
@@ -102,6 +103,16 @@
102103
#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010)
103104
#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011)
104105

106+
/* probe */
107+
#define SOF_IPC_PROBE_INIT SOF_CMD_TYPE(0x001)
108+
#define SOF_IPC_PROBE_DEINIT SOF_CMD_TYPE(0x002)
109+
#define SOF_IPC_PROBE_DMA_ADD SOF_CMD_TYPE(0x003)
110+
#define SOF_IPC_PROBE_DMA_INFO SOF_CMD_TYPE(0x004)
111+
#define SOF_IPC_PROBE_DMA_REMOVE SOF_CMD_TYPE(0x005)
112+
#define SOF_IPC_PROBE_POINT_ADD SOF_CMD_TYPE(0x006)
113+
#define SOF_IPC_PROBE_POINT_INFO SOF_CMD_TYPE(0x007)
114+
#define SOF_IPC_PROBE_POINT_REMOVE SOF_CMD_TYPE(0x008)
115+
105116
/* trace */
106117
#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001)
107118
#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002)

sound/soc/sof/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ config SND_SOC_SOF_OF
4141
required to enable i.MX8 devices.
4242
Say Y if you need this option. If unsure select "N".
4343

44+
config SND_SOC_SOF_DEBUG_PROBES
45+
bool "SOF enable data probing"
46+
help
47+
This option enables the data probing feature that can be used to
48+
gather data directly from specific points of the audio pipeline.
49+
Say Y if you want to enable probes.
50+
If unsure, select "N".
51+
4452
config SND_SOC_SOF_DEVELOPER_SUPPORT
4553
bool "SOF developer options support"
4654
depends on EXPERT

sound/soc/sof/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
44
control.o trace.o utils.o sof-audio.o
5+
snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += probe.o
56

67
snd-sof-pci-objs := sof-pci-dev.o
78
snd-sof-acpi-objs := sof-acpi-dev.o

sound/soc/sof/intel/hda-ipc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
106106
ret = reply.error;
107107
} else {
108108
/* reply correct size ? */
109-
if (reply.hdr.size != msg->reply_size) {
109+
if (reply.hdr.size != msg->reply_size &&
110+
/* getter payload is never known upfront */
111+
!(reply.hdr.cmd & SOF_IPC_GLB_PROBE)) {
110112
dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
111113
msg->reply_size, reply.hdr.size);
112114
ret = -EINVAL;

sound/soc/sof/probe.c

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2+
//
3+
// This file is provided under a dual BSD/GPLv2 license. When using or
4+
// redistributing this file, you may do so under either license.
5+
//
6+
// Copyright(c) 2019-2020 Intel Corporation. All rights reserved.
7+
//
8+
// Author: Cezary Rojewski <[email protected]>
9+
//
10+
11+
#include "sof-priv.h"
12+
#include "probe.h"
13+
14+
/**
15+
* sof_ipc_probe_init - initialize data probing
16+
* @sdev: SOF sound device
17+
* @stream_tag: Extractor stream tag
18+
* @buffer_size: DMA buffer size to set for extractor
19+
*
20+
* Host chooses whether extraction is supported or not by providing
21+
* valid stream tag to DSP. Once specified, stream described by that
22+
* tag will be tied to DSP for extraction for the entire lifetime of
23+
* probe.
24+
*
25+
* Probing is initialized only once and each INIT request must be
26+
* matched by DEINIT call.
27+
*/
28+
int sof_ipc_probe_init(struct snd_sof_dev *sdev,
29+
u32 stream_tag, size_t buffer_size)
30+
{
31+
struct sof_ipc_probe_dma_add_params *msg;
32+
struct sof_ipc_reply reply;
33+
size_t size = struct_size(msg, dma, 1);
34+
int ret;
35+
36+
msg = kmalloc(size, GFP_KERNEL);
37+
if (!msg)
38+
return -ENOMEM;
39+
msg->hdr.size = size;
40+
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
41+
msg->num_elems = 1;
42+
msg->dma[0].stream_tag = stream_tag;
43+
msg->dma[0].dma_buffer_size = buffer_size;
44+
45+
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
46+
&reply, sizeof(reply));
47+
kfree(msg);
48+
return ret;
49+
}
50+
EXPORT_SYMBOL(sof_ipc_probe_init);
51+
52+
/**
53+
* sof_ipc_probe_deinit - cleanup after data probing
54+
* @sdev: SOF sound device
55+
*
56+
* Host sends DEINIT request to free previously initialized probe
57+
* on DSP side once it is no longer needed. DEINIT only when there
58+
* are no probes connected and with all injectors detached.
59+
*/
60+
int sof_ipc_probe_deinit(struct snd_sof_dev *sdev)
61+
{
62+
struct sof_ipc_cmd_hdr msg;
63+
struct sof_ipc_reply reply;
64+
65+
msg.size = sizeof(msg);
66+
msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
67+
68+
return sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size,
69+
&reply, sizeof(reply));
70+
}
71+
EXPORT_SYMBOL(sof_ipc_probe_deinit);
72+
73+
static int sof_ipc_probe_info(struct snd_sof_dev *sdev, unsigned int cmd,
74+
void **params, size_t *num_params)
75+
{
76+
struct sof_ipc_probe_info_params msg = {{{0}}};
77+
struct sof_ipc_probe_info_params *reply;
78+
size_t bytes;
79+
int ret;
80+
81+
*params = NULL;
82+
*num_params = 0;
83+
84+
reply = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
85+
if (!reply)
86+
return -ENOMEM;
87+
msg.rhdr.hdr.size = sizeof(msg);
88+
msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
89+
90+
ret = sof_ipc_tx_message(sdev->ipc, msg.rhdr.hdr.cmd, &msg,
91+
msg.rhdr.hdr.size, reply, SOF_IPC_MSG_MAX_SIZE);
92+
if (ret < 0 || reply->rhdr.error < 0)
93+
goto exit;
94+
95+
if (!reply->num_elems)
96+
goto exit;
97+
98+
bytes = reply->num_elems * sizeof(reply->dma[0]);
99+
*params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
100+
if (!*params) {
101+
ret = -ENOMEM;
102+
goto exit;
103+
}
104+
*num_params = msg.num_elems;
105+
106+
exit:
107+
kfree(reply);
108+
return ret;
109+
}
110+
111+
/**
112+
* sof_ipc_probe_dma_info - retrieve list of active injection dmas
113+
* @sdev: SOF sound device
114+
* @dma: Returned list of active dmas
115+
* @num_dma: Returned count of active dmas
116+
*
117+
* Host sends DMA_INFO request to obtain list of injection dmas it
118+
* can use to transfer data over with.
119+
*
120+
* Note that list contains only injection dmas as there is only one
121+
* extractor (dma) and it is always assigned on probing init.
122+
* DSP knows exactly where data from extraction probes is going to,
123+
* which is not the case for injection where multiple streams
124+
* could be engaged.
125+
*/
126+
int sof_ipc_probe_dma_info(struct snd_sof_dev *sdev,
127+
struct sof_probe_dma **dma, size_t *num_dma)
128+
{
129+
return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_DMA_INFO,
130+
(void **)dma, num_dma);
131+
}
132+
EXPORT_SYMBOL(sof_ipc_probe_dma_info);
133+
134+
/**
135+
* sof_ipc_probe_dma_add - attach to specified dmas
136+
* @sdev: SOF sound device
137+
* @dma: List of streams (dmas) to attach to
138+
* @num_dma: Number of elements in @dma
139+
*
140+
* Contrary to extraction, injection streams are never assigned
141+
* on init. Before attempting any data injection, host is responsible
142+
* for specifying streams which will be later used to transfer data
143+
* to connected probe points.
144+
*/
145+
int sof_ipc_probe_dma_add(struct snd_sof_dev *sdev,
146+
struct sof_probe_dma *dma, size_t num_dma)
147+
{
148+
struct sof_ipc_probe_dma_add_params *msg;
149+
struct sof_ipc_reply reply;
150+
size_t size = struct_size(msg, dma, num_dma);
151+
int ret;
152+
153+
msg = kmalloc(size, GFP_KERNEL);
154+
if (!msg)
155+
return -ENOMEM;
156+
msg->hdr.size = size;
157+
msg->num_elems = num_dma;
158+
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DMA_ADD;
159+
memcpy(&msg->dma[0], dma, size - sizeof(*msg));
160+
161+
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
162+
&reply, sizeof(reply));
163+
kfree(msg);
164+
return ret;
165+
}
166+
EXPORT_SYMBOL(sof_ipc_probe_dma_add);
167+
168+
/**
169+
* sof_ipc_probe_dma_remove - detach from specified dmas
170+
* @sdev: SOF sound device
171+
* @stream_tag: List of stream tags to detach from
172+
* @num_stream_tag: Number of elements in @stream_tag
173+
*
174+
* Host sends DMA_REMOVE request to free previously attached stream
175+
* from being occupied for injection. Each detach operation should
176+
* match equivalent DMA_ADD. Detach only when all probes tied to
177+
* given stream have been disconnected.
178+
*/
179+
int sof_ipc_probe_dma_remove(struct snd_sof_dev *sdev,
180+
unsigned int *stream_tag, size_t num_stream_tag)
181+
{
182+
struct sof_ipc_probe_dma_remove_params *msg;
183+
struct sof_ipc_reply reply;
184+
size_t size = struct_size(msg, stream_tag, num_stream_tag);
185+
int ret;
186+
187+
msg = kmalloc(size, GFP_KERNEL);
188+
if (!msg)
189+
return -ENOMEM;
190+
msg->hdr.size = size;
191+
msg->num_elems = num_stream_tag;
192+
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DMA_REMOVE;
193+
memcpy(&msg->stream_tag[0], stream_tag, size - sizeof(*msg));
194+
195+
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
196+
&reply, sizeof(reply));
197+
kfree(msg);
198+
return ret;
199+
}
200+
EXPORT_SYMBOL(sof_ipc_probe_dma_remove);
201+
202+
/**
203+
* sof_ipc_probe_points_info - retrieve list of active probe points
204+
* @sdev: SOF sound device
205+
* @desc: Returned list of active probes
206+
* @num_desc: Returned count of active probes
207+
*
208+
* Host sends PROBE_POINT_INFO request to obtain list of active probe
209+
* points, valid for disconnection when given probe is no longer
210+
* required.
211+
*/
212+
int sof_ipc_probe_points_info(struct snd_sof_dev *sdev,
213+
struct sof_probe_point_desc **desc, size_t *num_desc)
214+
{
215+
return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_POINT_INFO,
216+
(void **)desc, num_desc);
217+
}
218+
EXPORT_SYMBOL(sof_ipc_probe_points_info);
219+
220+
/**
221+
* sof_ipc_probe_points_add - connect specified probes
222+
* @sdev: SOF sound device
223+
* @desc: List of probe points to connect
224+
* @num_desc: Number of elements in @desc
225+
*
226+
* Dynamically connects to provided set of endpoints. Immediately
227+
* after connection is established, host must be prepared to
228+
* transfer data from or to target stream given the probing purpose.
229+
*
230+
* Each probe point should be removed using PROBE_POINT_REMOVE
231+
* request when no longer needed.
232+
*/
233+
int sof_ipc_probe_points_add(struct snd_sof_dev *sdev,
234+
struct sof_probe_point_desc *desc, size_t num_desc)
235+
{
236+
struct sof_ipc_probe_point_add_params *msg;
237+
struct sof_ipc_reply reply;
238+
size_t size = struct_size(msg, desc, num_desc);
239+
int ret;
240+
241+
msg = kmalloc(size, GFP_KERNEL);
242+
if (!msg)
243+
return -ENOMEM;
244+
msg->hdr.size = size;
245+
msg->num_elems = num_desc;
246+
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
247+
memcpy(&msg->desc[0], desc, size - sizeof(*msg));
248+
249+
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
250+
&reply, sizeof(reply));
251+
kfree(msg);
252+
return ret;
253+
}
254+
EXPORT_SYMBOL(sof_ipc_probe_points_add);
255+
256+
/**
257+
* sof_ipc_probe_points_remove - disconnect specified probes
258+
* @sdev: SOF sound device
259+
* @buffer_id: List of probe points to disconnect
260+
* @num_buffer_id: Number of elements in @desc
261+
*
262+
* Removes previously connected probes from list of active probe
263+
* points and frees all resources on DSP side.
264+
*/
265+
int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev,
266+
unsigned int *buffer_id, size_t num_buffer_id)
267+
{
268+
struct sof_ipc_probe_point_remove_params *msg;
269+
struct sof_ipc_reply reply;
270+
size_t size = struct_size(msg, buffer_id, num_buffer_id);
271+
int ret;
272+
273+
msg = kmalloc(size, GFP_KERNEL);
274+
if (!msg)
275+
return -ENOMEM;
276+
msg->hdr.size = size;
277+
msg->num_elems = num_buffer_id;
278+
msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
279+
memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
280+
281+
ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
282+
&reply, sizeof(reply));
283+
kfree(msg);
284+
return ret;
285+
}
286+
EXPORT_SYMBOL(sof_ipc_probe_points_remove);

0 commit comments

Comments
 (0)