Skip to content

Commit c85c067

Browse files
marcinszkudlinskilgirdwood
authored andcommitted
debug: tester loadable module framework
Tester module is a framework for a runtime testing that need a special internal code i.e. provide an extra load to CPU by running additional thread, etc. The idea is to allow testing of special cases using a standard "production" build. The module should be compiled as a loadable module only, as it is not needed in any real production case. In order to keep only one testing module (in meaning of a SOF module with separate UUID), a framework is introduced, where a test to be executed is selected by IPC parameter Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
1 parent 7c688b8 commit c85c067

File tree

16 files changed

+550
-1
lines changed

16 files changed

+550
-1
lines changed

app/configs/mtl/modules.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ CONFIG_COMP_CROSSOVER=m
2020
CONFIG_COMP_MULTIBAND_DRC=m
2121
CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=m
2222
CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m
23+
CONFIG_COMP_TESTER=m

src/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ rsource "library_manager/Kconfig"
2525
rsource "debug/telemetry/Kconfig"
2626

2727
rsource "debug/debug_stream/Kconfig"
28+
29+
rsource "debug/tester/Kconfig"

src/debug/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ if(CONFIG_GDB_DEBUG)
44
add_subdirectory(gdb)
55
endif()
66

7+
if(CONFIG_COMP_TESTER)
8+
add_subdirectory(tester)
9+
endif()
10+
711
add_local_sources(sof panic.c)

src/debug/tester/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_local_sources(tester.c)
2+
add_local_sources(tester_dummy_test.c)

src/debug/tester/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
config COMP_TESTER
4+
tristate "tester module"
5+
default n
6+
depends on IPC_MAJOR_4
7+
help
8+
Build a tester module. To be used in continuous
9+
integration process for special test cases that
10+
require a test code injected into the system itself
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) 2024 Intel Corporation.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
sof_llext_build("tester"
5+
SOURCES ../tester.c
6+
../tester_dummy_test.c
7+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <tools/rimage/config/platform.toml>
2+
#define LOAD_TYPE "2"
3+
#include "../tester.toml"
4+
5+
[module]
6+
count = __COUNTER__

src/debug/tester/tester.c

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
//SPDX-License-Identifier: BSD-3-Clause
2+
//
3+
// Copyright(c) 2025 Intel Corporation. All rights reserved.
4+
//
5+
// Author: Marcin Szkudlinski <marcin.szkudlinski@linux.intel.com>
6+
7+
#include <stddef.h>
8+
#include <stdint.h>
9+
#include <stdbool.h>
10+
#include <rtos/init.h>
11+
#include <sof/lib/uuid.h>
12+
#include <sof/audio/component.h>
13+
#include <sof/audio/module_adapter/module/generic.h>
14+
#include <sof/audio/sink_api.h>
15+
#include <sof/audio/source_api.h>
16+
#include <sof/audio/sink_source_utils.h>
17+
#include "tester.h"
18+
#include "tester_dummy_test.h"
19+
20+
/**
21+
* Tester module is a framework for a runtime testing that need a special test code
22+
* injected into the SOF system, i.e.
23+
* - provide an extra load to CPU by running additional thread
24+
* - execute some incorrect operations
25+
*
26+
* The idea is to allow using of special cases in testing like Continuous Integration or pre-release
27+
* testing using a standard, production build.
28+
*
29+
* In order to have only one testing module (in meaning of a SOF module with separate UUID),
30+
* a framework is introduced, where a test to be executed is selected by IPC parameter
31+
*
32+
* In production, module should be compiled as a loadable module, as it should not needed to be
33+
* loaded and used on customers' boards.
34+
* During developing, however, the module may be built in to keep debugging simpler
35+
*
36+
*/
37+
38+
LOG_MODULE_REGISTER(tester, CONFIG_SOF_LOG_LEVEL);
39+
40+
SOF_DEFINE_REG_UUID(tester);
41+
42+
DECLARE_TR_CTX(tester_tr, SOF_UUID(tester_uuid), LOG_LEVEL_INFO);
43+
44+
struct tester_init_config {
45+
struct ipc4_base_module_cfg ipc4_cfg;
46+
int32_t test_type;
47+
} __attribute__((packed, aligned(4)));
48+
49+
static int tester_init(struct processing_module *mod)
50+
{
51+
struct module_data *md = &mod->priv;
52+
struct comp_dev *dev = mod->dev;
53+
struct module_config *cfg = &md->cfg;
54+
size_t bs = cfg->size;
55+
struct tester_module_data *cd = NULL;
56+
int ret = 0;
57+
58+
if (bs != sizeof(struct tester_init_config)) {
59+
comp_err(dev, "Invalid config");
60+
return -EINVAL;
61+
}
62+
63+
/* allocate ctx for test module in shared memory - to allow all non-standard operations
64+
* without problems with cache
65+
*/
66+
cd = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));
67+
if (!cd) {
68+
comp_err(dev, "Out of memory");
69+
return -ENOMEM;
70+
}
71+
72+
struct tester_init_config *init_cfg = (struct tester_init_config *)cfg->init_data;
73+
74+
cd->test_case_type = init_cfg->test_type;
75+
switch (cd->test_case_type) {
76+
case TESTER_MODULE_CASE_DUMMY_TEST:
77+
cd->tester_case_interface = &tester_interface_dummy_test;
78+
break;
79+
80+
default:
81+
comp_err(dev, "Invalid config, unknown test type");
82+
rfree(cd);
83+
return -EINVAL;
84+
}
85+
86+
module_set_private_data(mod, cd);
87+
88+
if (cd->tester_case_interface->init)
89+
ret = cd->tester_case_interface->init(mod, &cd->test_case_ctx);
90+
91+
if (ret) {
92+
module_set_private_data(mod, NULL);
93+
rfree(cd);
94+
}
95+
96+
return ret;
97+
}
98+
99+
static int tester_prepare(struct processing_module *mod,
100+
struct sof_source **sources, int num_of_sources,
101+
struct sof_sink **sinks, int num_of_sinks)
102+
{
103+
struct tester_module_data *cd = module_get_private_data(mod);
104+
int ret = 0;
105+
106+
if (cd->tester_case_interface->prepare)
107+
ret = cd->tester_case_interface->prepare(cd->test_case_ctx, mod,
108+
sources, num_of_sources,
109+
sinks, num_of_sinks);
110+
111+
return ret;
112+
}
113+
114+
int tester_set_configuration(struct processing_module *mod,
115+
uint32_t config_id,
116+
enum module_cfg_fragment_position pos, uint32_t data_offset_size,
117+
const uint8_t *fragment, size_t fragment_size, uint8_t *response,
118+
size_t response_size)
119+
{
120+
struct tester_module_data *cd = module_get_private_data(mod);
121+
int ret = 0;
122+
123+
if (cd->tester_case_interface->set_configuration)
124+
ret = cd->tester_case_interface->set_configuration(cd->test_case_ctx, mod,
125+
config_id, pos, data_offset_size,
126+
fragment, fragment_size,
127+
response, response_size);
128+
129+
return ret;
130+
}
131+
132+
static int tester_process(struct processing_module *mod,
133+
struct sof_source **sources, int num_of_sources,
134+
struct sof_sink **sinks, int num_of_sinks)
135+
{
136+
struct tester_module_data *cd = module_get_private_data(mod);
137+
int ret = 0;
138+
bool do_copy = true;
139+
140+
if (cd->tester_case_interface->process)
141+
ret = cd->tester_case_interface->process(cd->test_case_ctx, mod,
142+
sources, num_of_sources,
143+
sinks, num_of_sinks, &do_copy);
144+
145+
if (!ret) {
146+
size_t sink_free = sink_get_free_size(sinks[0]);
147+
size_t source_avail = source_get_data_available(sources[0]);
148+
size_t to_copy = MIN(sink_free, source_avail);
149+
150+
if (do_copy) {
151+
/* copy data from input to output */
152+
source_to_sink_copy(sources[0], sinks[0], true, to_copy);
153+
} else {
154+
/* drop data and generate silence */
155+
source_drop_data(sources[0], to_copy);
156+
sink_fill_with_silence(sinks[0], to_copy);
157+
}
158+
}
159+
160+
return ret;
161+
}
162+
163+
static int tester_reset(struct processing_module *mod)
164+
{
165+
struct tester_module_data *cd = module_get_private_data(mod);
166+
int ret = 0;
167+
168+
if (cd->tester_case_interface->reset)
169+
ret = cd->tester_case_interface->reset(cd->test_case_ctx, mod);
170+
171+
return ret;
172+
}
173+
174+
static int tester_free(struct processing_module *mod)
175+
{
176+
struct tester_module_data *cd = module_get_private_data(mod);
177+
int ret = 0;
178+
179+
if (cd->tester_case_interface->free)
180+
ret = cd->tester_case_interface->free(cd->test_case_ctx, mod);
181+
182+
rfree(cd);
183+
module_set_private_data(mod, NULL);
184+
return ret;
185+
}
186+
187+
static int tester_bind(struct processing_module *mod, void *data)
188+
{
189+
struct tester_module_data *cd = module_get_private_data(mod);
190+
int ret = 0;
191+
192+
if (cd->tester_case_interface->bind)
193+
ret = cd->tester_case_interface->bind(cd->test_case_ctx, mod, data);
194+
195+
return ret;
196+
}
197+
198+
static int tester_unbind(struct processing_module *mod, void *data)
199+
{
200+
struct tester_module_data *cd = module_get_private_data(mod);
201+
int ret = 0;
202+
203+
if (cd->tester_case_interface->unbind)
204+
ret = cd->tester_case_interface->unbind(cd->test_case_ctx, mod, data);
205+
206+
return ret;
207+
}
208+
209+
static int tester_trigger(struct processing_module *mod, int cmd)
210+
{
211+
struct tester_module_data *cd = module_get_private_data(mod);
212+
int ret = 0;
213+
214+
if (cd->tester_case_interface->trigger)
215+
ret = cd->tester_case_interface->trigger(cd->test_case_ctx, mod, cmd);
216+
217+
if (!ret)
218+
ret = module_adapter_set_state(mod, mod->dev, cmd);
219+
220+
return ret;
221+
}
222+
223+
static const struct module_interface tester_interface = {
224+
.init = tester_init,
225+
.prepare = tester_prepare,
226+
.set_configuration = tester_set_configuration,
227+
.process = tester_process,
228+
.reset = tester_reset,
229+
.free = tester_free,
230+
.bind = tester_bind,
231+
.unbind = tester_unbind,
232+
.trigger = tester_trigger
233+
};
234+
235+
DECLARE_MODULE_ADAPTER(tester_interface, tester_uuid, tester_tr);
236+
SOF_MODULE_INIT(tester, sys_comp_module_tester_interface_init);
237+
238+
#if CONFIG_COMP_TESTER_MODULE
239+
/* modular: llext dynamic link */
240+
241+
#include <module/module/api_ver.h>
242+
#include <module/module/llext.h>
243+
#include <rimage/sof/user/manifest.h>
244+
245+
SOF_LLEXT_MOD_ENTRY(tester, &tester_interface);
246+
247+
static const struct sof_man_module_manifest mod_manifest __section(".module") __used =
248+
SOF_LLEXT_MODULE_MANIFEST("TESTER", tester_llext_entry, 1, SOF_REG_UUID(tester), 40);
249+
250+
SOF_LLEXT_BUILDINFO;
251+
252+
#endif

0 commit comments

Comments
 (0)