Skip to content

Commit 94c545a

Browse files
committed
firmware: cirrus: Add KUnit tests for cs_dsp
Merge series from Richard Fitzgerald <rf@opensource.cirrus.com>: This series adds KUnit tests for the cs_dsp module. Most of the functionality in cs_dsp is for downloading firmware to DSP memory and interacting with "control" words defined in that memory. This doesn't require any emulation of running firmware, because it is only reading and writing registers. So the testing can be done using a dummy regmap. The way this is used to perform testing is described in more detail in the commit message for each test. ADSP1 is not tested because this was only used by the WM2200 codec, a long-obsolete part that was discontinued in 2015.
2 parents 9b94f41 + 75a4a6e commit 94c545a

19 files changed

Lines changed: 17229 additions & 2 deletions

MAINTAINERS

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5501,8 +5501,8 @@ L: patches@opensource.cirrus.com
55015501
S: Supported
55025502
W: https://github.com/CirrusLogic/linux-drivers/wiki
55035503
T: git https://github.com/CirrusLogic/linux-drivers.git
5504-
F: drivers/firmware/cirrus/*
5505-
F: include/linux/firmware/cirrus/*
5504+
F: drivers/firmware/cirrus/
5505+
F: include/linux/firmware/cirrus/
55065506

55075507
CIRRUS LOGIC EP93XX ETHERNET DRIVER
55085508
M: Hartley Sweeten <hsweeten@visionengravers.com>

drivers/firmware/cirrus/Kconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,23 @@
33
config FW_CS_DSP
44
tristate
55
default n
6+
7+
config FW_CS_DSP_KUNIT_TEST_UTILS
8+
tristate
9+
depends on KUNIT
10+
select REGMAP
11+
select FW_CS_DSP
12+
13+
config FW_CS_DSP_KUNIT_TEST
14+
tristate "KUnit tests for Cirrus Logic cs_dsp" if !KUNIT_ALL_TESTS
15+
depends on KUNIT
16+
default KUNIT_ALL_TESTS
17+
select REGMAP
18+
select FW_CS_DSP
19+
select FW_CS_DSP_KUNIT_TEST_UTILS
20+
help
21+
This builds KUnit tests for cs_dsp.
22+
For more information on KUnit and unit tests in general,
23+
please refer to the KUnit documentation in
24+
Documentation/dev-tools/kunit/.
25+
If in doubt, say "N".

drivers/firmware/cirrus/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0
22
#
33
obj-$(CONFIG_FW_CS_DSP) += cs_dsp.o
4+
5+
obj-y += test/
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
4+
cs_dsp_test_utils-objs := \
5+
cs_dsp_mock_mem_maps.o \
6+
cs_dsp_mock_bin.o \
7+
cs_dsp_mock_regmap.o \
8+
cs_dsp_mock_utils.o \
9+
cs_dsp_mock_wmfw.o
10+
11+
cs_dsp_test-objs := \
12+
cs_dsp_test_bin.o \
13+
cs_dsp_test_bin_error.o \
14+
cs_dsp_test_callbacks.o \
15+
cs_dsp_test_control_parse.o \
16+
cs_dsp_test_control_cache.o \
17+
cs_dsp_test_control_rw.o \
18+
cs_dsp_test_wmfw.o \
19+
cs_dsp_test_wmfw_error.o \
20+
cs_dsp_tests.o
21+
22+
obj-$(CONFIG_FW_CS_DSP_KUNIT_TEST_UTILS) += cs_dsp_test_utils.o
23+
obj-$(CONFIG_FW_CS_DSP_KUNIT_TEST) += cs_dsp_test.o
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
//
3+
// bin file builder for cs_dsp KUnit tests.
4+
//
5+
// Copyright (C) 2024 Cirrus Logic, Inc. and
6+
// Cirrus Logic International Semiconductor Ltd.
7+
8+
#include <kunit/resource.h>
9+
#include <kunit/test.h>
10+
#include <linux/firmware/cirrus/cs_dsp.h>
11+
#include <linux/firmware/cirrus/cs_dsp_test_utils.h>
12+
#include <linux/firmware/cirrus/wmfw.h>
13+
#include <linux/firmware.h>
14+
#include <linux/math.h>
15+
#include <linux/overflow.h>
16+
#include <linux/string.h>
17+
#include <linux/vmalloc.h>
18+
19+
/* Buffer large enough for bin file content */
20+
#define CS_DSP_MOCK_BIN_BUF_SIZE 32768
21+
22+
KUNIT_DEFINE_ACTION_WRAPPER(vfree_action_wrapper, vfree, void *)
23+
24+
struct cs_dsp_mock_bin_builder {
25+
struct cs_dsp_test *test_priv;
26+
void *buf;
27+
void *write_p;
28+
size_t bytes_used;
29+
};
30+
31+
/**
32+
* cs_dsp_mock_bin_get_firmware() - Get struct firmware wrapper for data.
33+
*
34+
* @builder: Pointer to struct cs_dsp_mock_bin_builder.
35+
*
36+
* Return: Pointer to a struct firmware wrapper for the data.
37+
*/
38+
struct firmware *cs_dsp_mock_bin_get_firmware(struct cs_dsp_mock_bin_builder *builder)
39+
{
40+
struct firmware *fw;
41+
42+
fw = kunit_kzalloc(builder->test_priv->test, sizeof(*fw), GFP_KERNEL);
43+
KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, fw);
44+
45+
fw->data = builder->buf;
46+
fw->size = builder->bytes_used;
47+
48+
return fw;
49+
}
50+
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_get_firmware, "FW_CS_DSP_KUNIT_TEST_UTILS");
51+
52+
/**
53+
* cs_dsp_mock_bin_add_raw_block() - Add a data block to the bin file.
54+
*
55+
* @builder: Pointer to struct cs_dsp_mock_bin_builder.
56+
* @alg_ig: Algorithm ID.
57+
* @alg_ver: Algorithm version.
58+
* @type: Type of the block.
59+
* @offset: Offset.
60+
* @payload_data: Pointer to buffer containing the payload data.
61+
* @payload_len_bytes: Length of payload data in bytes.
62+
*/
63+
void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,
64+
unsigned int alg_id, unsigned int alg_ver,
65+
int type, unsigned int offset,
66+
const void *payload_data, size_t payload_len_bytes)
67+
{
68+
struct wmfw_coeff_item *item;
69+
size_t bytes_needed = struct_size_t(struct wmfw_coeff_item, data, payload_len_bytes);
70+
71+
KUNIT_ASSERT_TRUE(builder->test_priv->test,
72+
(builder->write_p + bytes_needed) <
73+
(builder->buf + CS_DSP_MOCK_BIN_BUF_SIZE));
74+
75+
item = builder->write_p;
76+
77+
item->offset = cpu_to_le16(offset);
78+
item->type = cpu_to_le16(type);
79+
item->id = cpu_to_le32(alg_id);
80+
item->ver = cpu_to_le32(alg_ver << 8);
81+
item->len = cpu_to_le32(payload_len_bytes);
82+
83+
if (payload_len_bytes)
84+
memcpy(item->data, payload_data, payload_len_bytes);
85+
86+
builder->write_p += bytes_needed;
87+
builder->bytes_used += bytes_needed;
88+
}
89+
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_raw_block, "FW_CS_DSP_KUNIT_TEST_UTILS");
90+
91+
static void cs_dsp_mock_bin_add_name_or_info(struct cs_dsp_mock_bin_builder *builder,
92+
const char *info, int type)
93+
{
94+
size_t info_len = strlen(info);
95+
char *tmp = NULL;
96+
97+
if (info_len % 4) {
98+
/* Create a padded string with length a multiple of 4 */
99+
info_len = round_up(info_len, 4);
100+
tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL);
101+
KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp);
102+
memcpy(tmp, info, info_len);
103+
info = tmp;
104+
}
105+
106+
cs_dsp_mock_bin_add_raw_block(builder, 0, 0, WMFW_INFO_TEXT, 0, info, info_len);
107+
kunit_kfree(builder->test_priv->test, tmp);
108+
}
109+
110+
/**
111+
* cs_dsp_mock_bin_add_info() - Add an info block to the bin file.
112+
*
113+
* @builder: Pointer to struct cs_dsp_mock_bin_builder.
114+
* @info: Pointer to info string to be copied into the file.
115+
*
116+
* The string will be padded to a length that is a multiple of 4 bytes.
117+
*/
118+
void cs_dsp_mock_bin_add_info(struct cs_dsp_mock_bin_builder *builder,
119+
const char *info)
120+
{
121+
cs_dsp_mock_bin_add_name_or_info(builder, info, WMFW_INFO_TEXT);
122+
}
123+
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_info, "FW_CS_DSP_KUNIT_TEST_UTILS");
124+
125+
/**
126+
* cs_dsp_mock_bin_add_name() - Add a name block to the bin file.
127+
*
128+
* @builder: Pointer to struct cs_dsp_mock_bin_builder.
129+
* @name: Pointer to name string to be copied into the file.
130+
*/
131+
void cs_dsp_mock_bin_add_name(struct cs_dsp_mock_bin_builder *builder,
132+
const char *name)
133+
{
134+
cs_dsp_mock_bin_add_name_or_info(builder, name, WMFW_NAME_TEXT);
135+
}
136+
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_name, "FW_CS_DSP_KUNIT_TEST_UTILS");
137+
138+
/**
139+
* cs_dsp_mock_bin_add_patch() - Add a patch data block to the bin file.
140+
*
141+
* @builder: Pointer to struct cs_dsp_mock_bin_builder.
142+
* @alg_ig: Algorithm ID for the patch.
143+
* @alg_ver: Algorithm version for the patch.
144+
* @mem_region: Memory region for the patch.
145+
* @reg_addr_offset: Offset to start of data in register addresses.
146+
* @payload_data: Pointer to buffer containing the payload data.
147+
* @payload_len_bytes: Length of payload data in bytes.
148+
*/
149+
void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,
150+
unsigned int alg_id, unsigned int alg_ver,
151+
int mem_region, unsigned int reg_addr_offset,
152+
const void *payload_data, size_t payload_len_bytes)
153+
{
154+
/* Payload length must be a multiple of 4 */
155+
KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);
156+
157+
cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,
158+
mem_region, reg_addr_offset,
159+
payload_data, payload_len_bytes);
160+
}
161+
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch, "FW_CS_DSP_KUNIT_TEST_UTILS");
162+
163+
/**
164+
* cs_dsp_mock_bin_init() - Initialize a struct cs_dsp_mock_bin_builder.
165+
*
166+
* @priv: Pointer to struct cs_dsp_test.
167+
* @format_version: Required bin format version.
168+
* @fw_version: Firmware version to put in bin file.
169+
*
170+
* Return: Pointer to created struct cs_dsp_mock_bin_builder.
171+
*/
172+
struct cs_dsp_mock_bin_builder *cs_dsp_mock_bin_init(struct cs_dsp_test *priv,
173+
int format_version,
174+
unsigned int fw_version)
175+
{
176+
struct cs_dsp_mock_bin_builder *builder;
177+
struct wmfw_coeff_hdr *hdr;
178+
179+
builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL);
180+
KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder);
181+
builder->test_priv = priv;
182+
183+
builder->buf = vmalloc(CS_DSP_MOCK_BIN_BUF_SIZE);
184+
KUNIT_ASSERT_NOT_NULL(priv->test, builder->buf);
185+
kunit_add_action_or_reset(priv->test, vfree_action_wrapper, builder->buf);
186+
187+
/* Create header */
188+
hdr = builder->buf;
189+
memcpy(hdr->magic, "WMDR", sizeof(hdr->magic));
190+
hdr->len = cpu_to_le32(offsetof(struct wmfw_coeff_hdr, data));
191+
hdr->ver = cpu_to_le32(fw_version | (format_version << 24));
192+
hdr->core_ver = cpu_to_le32(((u32)priv->dsp->type << 24) | priv->dsp->rev);
193+
194+
builder->write_p = hdr->data;
195+
builder->bytes_used = offsetof(struct wmfw_coeff_hdr, data);
196+
197+
return builder;
198+
}
199+
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_init, "FW_CS_DSP_KUNIT_TEST_UTILS");

0 commit comments

Comments
 (0)