1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // KUnit tests for cs_dsp.
4 //
5 // Copyright (C) 2024 Cirrus Logic, Inc. and
6 //                    Cirrus Logic International Semiconductor Ltd.
7 
8 #include <kunit/device.h>
9 #include <kunit/resource.h>
10 #include <kunit/test.h>
11 #include <linux/build_bug.h>
12 #include <linux/firmware/cirrus/cs_dsp.h>
13 #include <linux/firmware/cirrus/cs_dsp_test_utils.h>
14 #include <linux/firmware/cirrus/wmfw.h>
15 #include <linux/list.h>
16 #include <linux/mutex.h>
17 #include <linux/regmap.h>
18 
19 KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *);
20 KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *);
21 
22 struct cs_dsp_test_local {
23 	struct cs_dsp_mock_xm_header *xm_header;
24 	struct cs_dsp_mock_wmfw_builder *wmfw_builder;
25 	int wmfw_version;
26 };
27 
28 struct cs_dsp_ctl_parse_test_param {
29 	int mem_type;
30 	int alg_id;
31 	unsigned int offset;
32 	unsigned int length;
33 	u16 ctl_type;
34 	u16 flags;
35 };
36 
37 static const struct cs_dsp_mock_alg_def cs_dsp_ctl_parse_test_algs[] = {
38 	{
39 		.id = 0xfafa,
40 		.ver = 0x100000,
41 		.xm_size_words = 164,
42 		.ym_size_words = 164,
43 		.zm_size_words = 164,
44 	},
45 	{
46 		.id = 0xb,
47 		.ver = 0x100001,
48 		.xm_size_words = 8,
49 		.ym_size_words = 8,
50 		.zm_size_words = 8,
51 	},
52 	{
53 		.id = 0x9f1234,
54 		.ver = 0x100500,
55 		.xm_size_words = 16,
56 		.ym_size_words = 16,
57 		.zm_size_words = 16,
58 	},
59 	{
60 		.id = 0xff00ff,
61 		.ver = 0x300113,
62 		.xm_size_words = 16,
63 		.ym_size_words = 16,
64 		.zm_size_words = 16,
65 	},
66 };
67 
68 static const struct cs_dsp_mock_coeff_def mock_coeff_template = {
69 	.shortname = "Dummy Coeff",
70 	.type = WMFW_CTL_TYPE_BYTES,
71 	.mem_type = WMFW_ADSP2_YM,
72 	.flags = WMFW_CTL_FLAG_VOLATILE,
73 	.length_bytes = 4,
74 };
75 
cs_dsp_ctl_alloc_test_string(struct kunit * test,char c,size_t len)76 static char *cs_dsp_ctl_alloc_test_string(struct kunit *test, char c, size_t len)
77 {
78 	char *str;
79 
80 	str = kunit_kmalloc(test, len + 1, GFP_KERNEL);
81 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str);
82 	memset(str, c, len);
83 	str[len] = '\0';
84 
85 	return str;
86 }
87 
88 /* Algorithm info block without controls should load */
cs_dsp_ctl_parse_no_coeffs(struct kunit * test)89 static void cs_dsp_ctl_parse_no_coeffs(struct kunit *test)
90 {
91 	struct cs_dsp_test *priv = test->priv;
92 	struct cs_dsp_test_local *local = priv->local;
93 	struct firmware *wmfw;
94 
95 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
96 					      cs_dsp_ctl_parse_test_algs[0].id,
97 					      "dummyalg", NULL);
98 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
99 
100 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
101 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
102 }
103 
104 /*
105  * V1 controls do not have names, the name field in the coefficient entry
106  * should be ignored.
107  */
cs_dsp_ctl_parse_v1_name(struct kunit * test)108 static void cs_dsp_ctl_parse_v1_name(struct kunit *test)
109 {
110 	struct cs_dsp_test *priv = test->priv;
111 	struct cs_dsp_test_local *local = priv->local;
112 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
113 	struct cs_dsp_coeff_ctl *ctl;
114 	struct firmware *wmfw;
115 
116 	def.fullname = "Dummy";
117 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
118 					      cs_dsp_ctl_parse_test_algs[0].id,
119 					      "dummyalg", NULL);
120 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
121 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
122 
123 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
124 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
125 
126 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
127 	KUNIT_ASSERT_NOT_NULL(test, ctl);
128 	KUNIT_EXPECT_EQ(test, ctl->subname_len, 0);
129 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
130 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
131 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
132 }
133 
134 /*
135  * V1 controls do not have names, the name field in the coefficient entry
136  * should be ignored. Test with a zero-length name string.
137  */
cs_dsp_ctl_parse_empty_v1_name(struct kunit * test)138 static void cs_dsp_ctl_parse_empty_v1_name(struct kunit *test)
139 {
140 	struct cs_dsp_test *priv = test->priv;
141 	struct cs_dsp_test_local *local = priv->local;
142 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
143 	struct cs_dsp_coeff_ctl *ctl;
144 	struct firmware *wmfw;
145 
146 	def.fullname = "\0";
147 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
148 					      cs_dsp_ctl_parse_test_algs[0].id,
149 					      "dummyalg", NULL);
150 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
151 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
152 
153 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
154 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
155 
156 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
157 	KUNIT_ASSERT_NOT_NULL(test, ctl);
158 	KUNIT_EXPECT_EQ(test, ctl->subname_len, 0);
159 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
160 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
161 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
162 }
163 
164 /*
165  * V1 controls do not have names, the name field in the coefficient entry
166  * should be ignored. Test with a maximum length name string.
167  */
cs_dsp_ctl_parse_max_v1_name(struct kunit * test)168 static void cs_dsp_ctl_parse_max_v1_name(struct kunit *test)
169 {
170 	struct cs_dsp_test *priv = test->priv;
171 	struct cs_dsp_test_local *local = priv->local;
172 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
173 	struct cs_dsp_coeff_ctl *ctl;
174 	struct firmware *wmfw;
175 
176 	def.fullname = cs_dsp_ctl_alloc_test_string(test, 'A', 255);
177 
178 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
179 					      cs_dsp_ctl_parse_test_algs[0].id,
180 					      "dummyalg", NULL);
181 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
182 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
183 
184 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
185 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
186 
187 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
188 	KUNIT_ASSERT_NOT_NULL(test, ctl);
189 	KUNIT_EXPECT_EQ(test, ctl->subname_len, 0);
190 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
191 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
192 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
193 }
194 
195 /* Short name from coeff descriptor should be used as control name. */
cs_dsp_ctl_parse_short_name(struct kunit * test)196 static void cs_dsp_ctl_parse_short_name(struct kunit *test)
197 {
198 	struct cs_dsp_test *priv = test->priv;
199 	struct cs_dsp_test_local *local = priv->local;
200 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
201 	struct cs_dsp_coeff_ctl *ctl;
202 	struct firmware *wmfw;
203 
204 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
205 					      cs_dsp_ctl_parse_test_algs[0].id,
206 					      "dummyalg", NULL);
207 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
208 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
209 
210 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
211 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
212 
213 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
214 	KUNIT_ASSERT_NOT_NULL(test, ctl);
215 	KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname));
216 	KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len);
217 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
218 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
219 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
220 }
221 
222 /*
223  * Short name from coeff descriptor should be used as control name.
224  * Test with a short name that is a single character.
225  */
cs_dsp_ctl_parse_min_short_name(struct kunit * test)226 static void cs_dsp_ctl_parse_min_short_name(struct kunit *test)
227 {
228 	struct cs_dsp_test *priv = test->priv;
229 	struct cs_dsp_test_local *local = priv->local;
230 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
231 	struct cs_dsp_coeff_ctl *ctl;
232 	struct firmware *wmfw;
233 
234 	def.shortname = "Q";
235 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
236 					      cs_dsp_ctl_parse_test_algs[0].id,
237 					      "dummyalg", NULL);
238 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
239 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
240 
241 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
242 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
243 
244 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
245 	KUNIT_ASSERT_NOT_NULL(test, ctl);
246 	KUNIT_EXPECT_EQ(test, ctl->subname_len, 1);
247 	KUNIT_EXPECT_EQ(test, ctl->subname[0], 'Q');
248 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
249 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
250 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
251 }
252 
253 /*
254  * Short name from coeff descriptor should be used as control name.
255  * Test with a maximum length name.
256  */
cs_dsp_ctl_parse_max_short_name(struct kunit * test)257 static void cs_dsp_ctl_parse_max_short_name(struct kunit *test)
258 {
259 	struct cs_dsp_test *priv = test->priv;
260 	struct cs_dsp_test_local *local = priv->local;
261 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
262 	struct cs_dsp_coeff_ctl *ctl;
263 	struct firmware *wmfw;
264 
265 	def.shortname = cs_dsp_ctl_alloc_test_string(test, 'A', 255);
266 
267 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
268 					      cs_dsp_ctl_parse_test_algs[0].id,
269 					      "dummyalg", NULL);
270 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
271 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
272 
273 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
274 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
275 
276 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
277 	KUNIT_ASSERT_NOT_NULL(test, ctl);
278 	KUNIT_EXPECT_EQ(test, ctl->subname_len, 255);
279 	KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len);
280 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
281 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
282 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
283 }
284 
285 /*
286  * Full name from coeff descriptor should be ignored. It is a variable
287  * length field so affects the position of subsequent fields.
288  * Test with a 1-character full name.
289  */
cs_dsp_ctl_parse_with_min_fullname(struct kunit * test)290 static void cs_dsp_ctl_parse_with_min_fullname(struct kunit *test)
291 {
292 	struct cs_dsp_test *priv = test->priv;
293 	struct cs_dsp_test_local *local = priv->local;
294 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
295 	struct cs_dsp_coeff_ctl *ctl;
296 	struct firmware *wmfw;
297 
298 	def.fullname = "Q";
299 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
300 					      cs_dsp_ctl_parse_test_algs[0].id,
301 					      "dummyalg", NULL);
302 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
303 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
304 
305 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
306 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
307 
308 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
309 	KUNIT_ASSERT_NOT_NULL(test, ctl);
310 	KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname));
311 	KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len);
312 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
313 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
314 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
315 }
316 
317 /*
318  * Full name from coeff descriptor should be ignored. It is a variable
319  * length field so affects the position of subsequent fields.
320  * Test with a maximum length full name.
321  */
cs_dsp_ctl_parse_with_max_fullname(struct kunit * test)322 static void cs_dsp_ctl_parse_with_max_fullname(struct kunit *test)
323 {
324 	struct cs_dsp_test *priv = test->priv;
325 	struct cs_dsp_test_local *local = priv->local;
326 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
327 	struct cs_dsp_coeff_ctl *ctl;
328 	struct firmware *wmfw;
329 
330 	def.fullname = cs_dsp_ctl_alloc_test_string(test, 'A', 255);
331 
332 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
333 					      cs_dsp_ctl_parse_test_algs[0].id,
334 					      "dummyalg", NULL);
335 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
336 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
337 
338 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
339 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
340 
341 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
342 	KUNIT_ASSERT_NOT_NULL(test, ctl);
343 	KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname));
344 	KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len);
345 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
346 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
347 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
348 }
349 
350 /*
351  * Description from coeff descriptor should be ignored. It is a variable
352  * length field so affects the position of subsequent fields.
353  * Test with a 1-character description
354  */
cs_dsp_ctl_parse_with_min_description(struct kunit * test)355 static void cs_dsp_ctl_parse_with_min_description(struct kunit *test)
356 {
357 	struct cs_dsp_test *priv = test->priv;
358 	struct cs_dsp_test_local *local = priv->local;
359 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
360 	struct cs_dsp_coeff_ctl *ctl;
361 	struct firmware *wmfw;
362 
363 	def.description = "Q";
364 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
365 					      cs_dsp_ctl_parse_test_algs[0].id,
366 					      "dummyalg", NULL);
367 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
368 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
369 
370 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
371 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
372 
373 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
374 	KUNIT_ASSERT_NOT_NULL(test, ctl);
375 	KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname));
376 	KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len);
377 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
378 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
379 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
380 }
381 
382 /*
383  * Description from coeff descriptor should be ignored. It is a variable
384  * length field so affects the position of subsequent fields.
385  * Test with a maximum length description
386  */
cs_dsp_ctl_parse_with_max_description(struct kunit * test)387 static void cs_dsp_ctl_parse_with_max_description(struct kunit *test)
388 {
389 	struct cs_dsp_test *priv = test->priv;
390 	struct cs_dsp_test_local *local = priv->local;
391 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
392 	struct cs_dsp_coeff_ctl *ctl;
393 	struct firmware *wmfw;
394 
395 	def.description = cs_dsp_ctl_alloc_test_string(test, 'A', 65535);
396 
397 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
398 					      cs_dsp_ctl_parse_test_algs[0].id,
399 					      "dummyalg", NULL);
400 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
401 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
402 
403 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
404 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
405 
406 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
407 	KUNIT_ASSERT_NOT_NULL(test, ctl);
408 	KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname));
409 	KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len);
410 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
411 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
412 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
413 }
414 
415 /*
416  * Full name and description from coeff descriptor are variable length
417  * fields so affects the position of subsequent fields.
418  * Test with a maximum length full name and description
419  */
cs_dsp_ctl_parse_with_max_fullname_and_description(struct kunit * test)420 static void cs_dsp_ctl_parse_with_max_fullname_and_description(struct kunit *test)
421 {
422 	struct cs_dsp_test *priv = test->priv;
423 	struct cs_dsp_test_local *local = priv->local;
424 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
425 	struct cs_dsp_coeff_ctl *ctl;
426 	struct firmware *wmfw;
427 
428 	def.fullname = cs_dsp_ctl_alloc_test_string(test, 'A', 255);
429 	def.description = cs_dsp_ctl_alloc_test_string(test, 'A', 65535);
430 
431 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
432 					      cs_dsp_ctl_parse_test_algs[0].id,
433 					      "dummyalg", NULL);
434 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
435 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
436 
437 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
438 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
439 
440 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
441 	KUNIT_ASSERT_NOT_NULL(test, ctl);
442 	KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname));
443 	KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len);
444 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
445 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
446 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
447 }
448 
449 static const char * const cs_dsp_ctl_alignment_test_names[] = {
450 	"1", "12", "123", "1234", "12345", "123456", "1234567",
451 	"12345678", "123456789", "123456789A", "123456789AB",
452 	"123456789ABC", "123456789ABCD", "123456789ABCDE",
453 	"123456789ABCDEF",
454 };
455 
456 /*
457  * Variable-length string fields are padded to a multiple of 4-bytes.
458  * Test this with various lengths of short name.
459  */
cs_dsp_ctl_shortname_alignment(struct kunit * test)460 static void cs_dsp_ctl_shortname_alignment(struct kunit *test)
461 {
462 	struct cs_dsp_test *priv = test->priv;
463 	struct cs_dsp_test_local *local = priv->local;
464 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
465 	struct cs_dsp_coeff_ctl *ctl;
466 	struct firmware *wmfw;
467 	int i;
468 
469 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
470 					      cs_dsp_ctl_parse_test_algs[0].id,
471 					      "dummyalg", NULL);
472 
473 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) {
474 		def.shortname = cs_dsp_ctl_alignment_test_names[i];
475 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
476 	}
477 
478 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
479 
480 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
481 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
482 
483 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) {
484 		mutex_lock(&priv->dsp->pwr_lock);
485 		ctl = cs_dsp_get_ctl(priv->dsp, cs_dsp_ctl_alignment_test_names[i],
486 				     def.mem_type, cs_dsp_ctl_parse_test_algs[0].id);
487 		mutex_unlock(&priv->dsp->pwr_lock);
488 		KUNIT_ASSERT_NOT_NULL(test, ctl);
489 		KUNIT_EXPECT_EQ(test, ctl->subname_len, i + 1);
490 		KUNIT_EXPECT_MEMEQ(test, ctl->subname, cs_dsp_ctl_alignment_test_names[i],
491 				   ctl->subname_len);
492 		/* Test fields that are parsed after the variable-length fields */
493 		KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
494 		KUNIT_EXPECT_EQ(test, ctl->type, def.type);
495 		KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
496 	}
497 }
498 
499 /*
500  * Variable-length string fields are padded to a multiple of 4-bytes.
501  * Test this with various lengths of full name.
502  */
cs_dsp_ctl_fullname_alignment(struct kunit * test)503 static void cs_dsp_ctl_fullname_alignment(struct kunit *test)
504 {
505 	struct cs_dsp_test *priv = test->priv;
506 	struct cs_dsp_test_local *local = priv->local;
507 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
508 	struct cs_dsp_coeff_ctl *ctl;
509 	char ctl_name[4];
510 	struct firmware *wmfw;
511 	int i;
512 
513 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
514 					      cs_dsp_ctl_parse_test_algs[0].id,
515 					      "dummyalg", NULL);
516 
517 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) {
518 		/*
519 		 * Create a unique control name of 3 characters so that
520 		 * the shortname field is exactly 4 bytes long including
521 		 * the length byte.
522 		 */
523 		snprintf(ctl_name, sizeof(ctl_name), "%03d", i);
524 		KUNIT_ASSERT_EQ(test, strlen(ctl_name), 3);
525 		def.shortname = ctl_name;
526 
527 		def.fullname = cs_dsp_ctl_alignment_test_names[i];
528 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
529 	}
530 
531 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
532 
533 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
534 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
535 
536 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) {
537 		snprintf(ctl_name, sizeof(ctl_name), "%03d", i);
538 
539 		mutex_lock(&priv->dsp->pwr_lock);
540 		ctl = cs_dsp_get_ctl(priv->dsp, ctl_name, def.mem_type,
541 				     cs_dsp_ctl_parse_test_algs[0].id);
542 		mutex_unlock(&priv->dsp->pwr_lock);
543 		KUNIT_ASSERT_NOT_NULL(test, ctl);
544 		KUNIT_EXPECT_EQ(test, ctl->subname_len, 3);
545 		KUNIT_EXPECT_MEMEQ(test, ctl->subname, ctl_name, ctl->subname_len);
546 		/* Test fields that are parsed after the variable-length fields */
547 		KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
548 		KUNIT_EXPECT_EQ(test, ctl->type, def.type);
549 		KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
550 	}
551 }
552 
553 /*
554  * Variable-length string fields are padded to a multiple of 4-bytes.
555  * Test this with various lengths of description.
556  */
cs_dsp_ctl_description_alignment(struct kunit * test)557 static void cs_dsp_ctl_description_alignment(struct kunit *test)
558 {
559 	struct cs_dsp_test *priv = test->priv;
560 	struct cs_dsp_test_local *local = priv->local;
561 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
562 	struct cs_dsp_coeff_ctl *ctl;
563 	char ctl_name[4];
564 	struct firmware *wmfw;
565 	int i;
566 
567 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
568 					      cs_dsp_ctl_parse_test_algs[0].id,
569 					      "dummyalg", NULL);
570 
571 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) {
572 		/*
573 		 * Create a unique control name of 3 characters so that
574 		 * the shortname field is exactly 4 bytes long including
575 		 * the length byte.
576 		 */
577 		snprintf(ctl_name, sizeof(ctl_name), "%03d", i);
578 		KUNIT_ASSERT_EQ(test, strlen(ctl_name), 3);
579 		def.shortname = ctl_name;
580 
581 		def.description = cs_dsp_ctl_alignment_test_names[i];
582 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
583 	}
584 
585 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
586 
587 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
588 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
589 
590 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) {
591 		snprintf(ctl_name, sizeof(ctl_name), "%03d", i);
592 
593 		mutex_lock(&priv->dsp->pwr_lock);
594 		ctl = cs_dsp_get_ctl(priv->dsp, ctl_name, def.mem_type,
595 				     cs_dsp_ctl_parse_test_algs[0].id);
596 		mutex_unlock(&priv->dsp->pwr_lock);
597 		KUNIT_ASSERT_NOT_NULL(test, ctl);
598 		KUNIT_EXPECT_EQ(test, ctl->subname_len, 3);
599 		KUNIT_EXPECT_MEMEQ(test, ctl->subname, ctl_name, ctl->subname_len);
600 		/* Test fields that are parsed after the variable-length fields */
601 		KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
602 		KUNIT_EXPECT_EQ(test, ctl->type, def.type);
603 		KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
604 	}
605 }
606 
607 static const char * const cs_dsp_get_ctl_test_names[] = {
608 	"Up", "Down", "Switch", "Mute",
609 	"Left Up", "Left Down", "Right Up", "Right Down",
610 	"Left Mute", "Right Mute",
611 	"_trunc_1", "_trunc_2", " trunc",
612 };
613 
614 /* Test using cs_dsp_get_ctl() to lookup various controls. */
cs_dsp_get_ctl_test(struct kunit * test)615 static void cs_dsp_get_ctl_test(struct kunit *test)
616 {
617 	struct cs_dsp_test *priv = test->priv;
618 	struct cs_dsp_test_local *local = priv->local;
619 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
620 	struct cs_dsp_coeff_ctl *ctl;
621 	struct firmware *wmfw;
622 	int i;
623 
624 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
625 					      cs_dsp_ctl_parse_test_algs[0].id,
626 					      "dummyalg", NULL);
627 
628 	for (i = 0; i < ARRAY_SIZE(cs_dsp_get_ctl_test_names); i++) {
629 		def.shortname = cs_dsp_get_ctl_test_names[i];
630 		def.offset_dsp_words = i;
631 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
632 	}
633 
634 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
635 
636 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
637 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
638 
639 	for (i = 0; i < ARRAY_SIZE(cs_dsp_get_ctl_test_names); i++) {
640 		mutex_lock(&priv->dsp->pwr_lock);
641 		ctl = cs_dsp_get_ctl(priv->dsp, cs_dsp_get_ctl_test_names[i],
642 				     def.mem_type, cs_dsp_ctl_parse_test_algs[0].id);
643 		mutex_unlock(&priv->dsp->pwr_lock);
644 		KUNIT_ASSERT_NOT_NULL(test, ctl);
645 		KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(cs_dsp_get_ctl_test_names[i]));
646 		KUNIT_EXPECT_MEMEQ(test, ctl->subname, cs_dsp_get_ctl_test_names[i],
647 				   ctl->subname_len);
648 		KUNIT_EXPECT_EQ(test, ctl->offset, i);
649 	}
650 }
651 
652 /*
653  * cs_dsp_get_ctl() searches for the control in the currently loaded
654  * firmware, so create identical controls in multiple firmware and
655  * test that the correct one is found.
656  */
cs_dsp_get_ctl_test_multiple_wmfw(struct kunit * test)657 static void cs_dsp_get_ctl_test_multiple_wmfw(struct kunit *test)
658 {
659 	struct cs_dsp_test *priv = test->priv;
660 	struct cs_dsp_test_local *local = priv->local;
661 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
662 	struct cs_dsp_coeff_ctl *ctl;
663 	struct cs_dsp_mock_wmfw_builder *builder2;
664 	struct firmware *wmfw;
665 
666 	def.shortname = "_A_CONTROL";
667 
668 	/* Create a second mock wmfw builder */
669 	builder2 = cs_dsp_mock_wmfw_init(priv,
670 					 cs_dsp_mock_wmfw_format_version(local->wmfw_builder));
671 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, builder2);
672 	cs_dsp_mock_wmfw_add_data_block(builder2,
673 					WMFW_ADSP2_XM, 0,
674 					local->xm_header->blob_data,
675 					local->xm_header->blob_size_bytes);
676 
677 	/* Load a 'misc' firmware with a control */
678 	def.offset_dsp_words = 1;
679 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
680 					      cs_dsp_ctl_parse_test_algs[0].id,
681 					      "dummyalg", NULL);
682 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
683 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
684 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
685 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
686 	cs_dsp_power_down(priv->dsp);
687 
688 	/* Load a 'mbc/vss' firmware with a control of the same name */
689 	def.offset_dsp_words = 2;
690 	cs_dsp_mock_wmfw_start_alg_info_block(builder2,
691 					      cs_dsp_ctl_parse_test_algs[0].id,
692 					      "dummyalg", NULL);
693 	cs_dsp_mock_wmfw_add_coeff_desc(builder2, &def);
694 	cs_dsp_mock_wmfw_end_alg_info_block(builder2);
695 	wmfw = cs_dsp_mock_wmfw_get_firmware(builder2);
696 	KUNIT_ASSERT_EQ(test,
697 			cs_dsp_power_up(priv->dsp, wmfw, "mock_fw2", NULL, NULL, "mbc/vss"), 0);
698 
699 	/* A lookup should return the control for the current firmware */
700 	mutex_lock(&priv->dsp->pwr_lock);
701 	ctl = cs_dsp_get_ctl(priv->dsp, def.shortname,
702 			     def.mem_type, cs_dsp_ctl_parse_test_algs[0].id);
703 	mutex_unlock(&priv->dsp->pwr_lock);
704 	KUNIT_ASSERT_NOT_NULL(test, ctl);
705 	KUNIT_EXPECT_EQ(test, ctl->offset, 2);
706 
707 	/* Re-load the 'misc' firmware and a lookup should return its control */
708 	cs_dsp_power_down(priv->dsp);
709 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
710 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
711 
712 	mutex_lock(&priv->dsp->pwr_lock);
713 	ctl = cs_dsp_get_ctl(priv->dsp, def.shortname,
714 			     def.mem_type, cs_dsp_ctl_parse_test_algs[0].id);
715 	mutex_unlock(&priv->dsp->pwr_lock);
716 	KUNIT_ASSERT_NOT_NULL(test, ctl);
717 	KUNIT_EXPECT_EQ(test, ctl->offset, 1);
718 }
719 
720 /* Test that the value of the memory type field is parsed correctly. */
cs_dsp_ctl_parse_memory_type(struct kunit * test)721 static void cs_dsp_ctl_parse_memory_type(struct kunit *test)
722 {
723 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
724 	struct cs_dsp_test *priv = test->priv;
725 	struct cs_dsp_test_local *local = priv->local;
726 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
727 	struct cs_dsp_coeff_ctl *ctl;
728 	struct firmware *wmfw;
729 
730 	/* kunit_skip() marks the test skipped forever, so just return */
731 	if ((param->mem_type == WMFW_ADSP2_ZM) && !cs_dsp_mock_has_zm(priv))
732 		return;
733 
734 	def.mem_type = param->mem_type;
735 
736 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
737 					      cs_dsp_ctl_parse_test_algs[0].id,
738 					      "dummyalg", NULL);
739 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
740 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
741 
742 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
743 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
744 
745 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
746 	KUNIT_ASSERT_NOT_NULL(test, ctl);
747 	KUNIT_EXPECT_EQ(test, ctl->alg_region.type, param->mem_type);
748 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
749 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
750 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
751 }
752 
753 /*
754  * Test that the algorithm id from the parent alg-info block is
755  * correctly stored in the cs_dsp_coeff_ctl.
756  */
cs_dsp_ctl_parse_alg_id(struct kunit * test)757 static void cs_dsp_ctl_parse_alg_id(struct kunit *test)
758 {
759 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
760 	struct cs_dsp_test *priv = test->priv;
761 	struct cs_dsp_test_local *local = priv->local;
762 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
763 	struct cs_dsp_coeff_ctl *ctl;
764 	struct firmware *wmfw;
765 
766 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
767 					      param->alg_id,
768 					      "dummyalg", NULL);
769 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
770 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
771 
772 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
773 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
774 
775 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
776 	KUNIT_ASSERT_NOT_NULL(test, ctl);
777 	KUNIT_EXPECT_EQ(test, ctl->alg_region.alg, param->alg_id);
778 	KUNIT_EXPECT_EQ(test, ctl->alg_region.type, def.mem_type);
779 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
780 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
781 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
782 }
783 
784 /*
785  * Test that the values of (alg id, memory type) tuple is parsed correctly.
786  * The alg id is parsed from the alg-info block, but the memory type is
787  * parsed from the coefficient info descriptor.
788  */
cs_dsp_ctl_parse_alg_mem(struct kunit * test)789 static void cs_dsp_ctl_parse_alg_mem(struct kunit *test)
790 {
791 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
792 	struct cs_dsp_test *priv = test->priv;
793 	struct cs_dsp_test_local *local = priv->local;
794 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
795 	struct cs_dsp_coeff_ctl *ctl;
796 	struct firmware *wmfw;
797 
798 	/* kunit_skip() marks the test skipped forever, so just return */
799 	if ((param->mem_type == WMFW_ADSP2_ZM) && !cs_dsp_mock_has_zm(priv))
800 		return;
801 
802 	def.mem_type = param->mem_type;
803 
804 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
805 					      param->alg_id,
806 					      "dummyalg", NULL);
807 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
808 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
809 
810 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
811 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
812 
813 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
814 	KUNIT_ASSERT_NOT_NULL(test, ctl);
815 	KUNIT_EXPECT_EQ(test, ctl->alg_region.alg, param->alg_id);
816 	KUNIT_EXPECT_EQ(test, ctl->alg_region.type, param->mem_type);
817 }
818 
819 /* Test that the value of the offset field is parsed correctly. */
cs_dsp_ctl_parse_offset(struct kunit * test)820 static void cs_dsp_ctl_parse_offset(struct kunit *test)
821 {
822 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
823 	struct cs_dsp_test *priv = test->priv;
824 	struct cs_dsp_test_local *local = priv->local;
825 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
826 	struct cs_dsp_coeff_ctl *ctl;
827 	struct firmware *wmfw;
828 
829 	def.offset_dsp_words = param->offset;
830 
831 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
832 					      cs_dsp_ctl_parse_test_algs[0].id,
833 					      "dummyalg", NULL);
834 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
835 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
836 
837 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
838 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
839 
840 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
841 	KUNIT_ASSERT_NOT_NULL(test, ctl);
842 	KUNIT_EXPECT_EQ(test, ctl->offset, param->offset);
843 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
844 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
845 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
846 }
847 
848 /* Test that the value of the length field is parsed correctly. */
cs_dsp_ctl_parse_length(struct kunit * test)849 static void cs_dsp_ctl_parse_length(struct kunit *test)
850 {
851 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
852 	struct cs_dsp_test *priv = test->priv;
853 	struct cs_dsp_test_local *local = priv->local;
854 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
855 	struct cs_dsp_coeff_ctl *ctl;
856 	struct firmware *wmfw;
857 
858 	def.length_bytes = param->length;
859 
860 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
861 					      cs_dsp_ctl_parse_test_algs[0].id,
862 					      "dummyalg", NULL);
863 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
864 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
865 
866 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
867 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
868 
869 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
870 	KUNIT_ASSERT_NOT_NULL(test, ctl);
871 	KUNIT_EXPECT_EQ(test, ctl->offset, def.offset_dsp_words);
872 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
873 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
874 	KUNIT_EXPECT_EQ(test, ctl->len, param->length);
875 }
876 
877 /* Test that the value of the control type field is parsed correctly. */
cs_dsp_ctl_parse_ctl_type(struct kunit * test)878 static void cs_dsp_ctl_parse_ctl_type(struct kunit *test)
879 {
880 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
881 	struct cs_dsp_test *priv = test->priv;
882 	struct cs_dsp_test_local *local = priv->local;
883 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
884 	struct cs_dsp_coeff_ctl *ctl;
885 	struct firmware *wmfw;
886 
887 	def.type = param->ctl_type;
888 	def.flags = param->flags;
889 
890 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
891 					      cs_dsp_ctl_parse_test_algs[0].id,
892 					      "dummyalg", NULL);
893 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
894 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
895 
896 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
897 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
898 
899 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
900 	KUNIT_ASSERT_NOT_NULL(test, ctl);
901 	KUNIT_EXPECT_EQ(test, ctl->type, param->ctl_type);
902 	KUNIT_EXPECT_EQ(test, ctl->flags, def.flags);
903 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
904 }
905 
906 /* Test that the value of the flags field is parsed correctly. */
cs_dsp_ctl_parse_flags(struct kunit * test)907 static void cs_dsp_ctl_parse_flags(struct kunit *test)
908 {
909 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
910 	struct cs_dsp_test *priv = test->priv;
911 	struct cs_dsp_test_local *local = priv->local;
912 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
913 	struct cs_dsp_coeff_ctl *ctl;
914 	struct firmware *wmfw;
915 	u32 reg_val;
916 
917 	/*
918 	 * Non volatile controls will be read to initialize the cache
919 	 * so the regmap cache must contain something to read.
920 	 */
921 	reg_val = 0xf11100;
922 	regmap_raw_write(priv->dsp->regmap,
923 			 cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM),
924 			 &reg_val, sizeof(reg_val));
925 
926 	def.flags = param->flags;
927 	def.mem_type = WMFW_ADSP2_YM;
928 
929 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
930 					      cs_dsp_ctl_parse_test_algs[0].id,
931 					      "dummyalg", NULL);
932 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
933 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
934 
935 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
936 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
937 
938 	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
939 	KUNIT_ASSERT_NOT_NULL(test, ctl);
940 	KUNIT_EXPECT_EQ(test, ctl->type, def.type);
941 	KUNIT_EXPECT_EQ(test, ctl->flags, param->flags);
942 	KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes);
943 }
944 
945 /* Test that invalid combinations of (control type, flags) are rejected. */
cs_dsp_ctl_illegal_type_flags(struct kunit * test)946 static void cs_dsp_ctl_illegal_type_flags(struct kunit *test)
947 {
948 	const struct cs_dsp_ctl_parse_test_param *param = test->param_value;
949 	struct cs_dsp_test *priv = test->priv;
950 	struct cs_dsp_test_local *local = priv->local;
951 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
952 	struct firmware *wmfw;
953 	u32 reg_val;
954 
955 	/*
956 	 * Non volatile controls will be read to initialize the cache
957 	 * so the regmap cache must contain something to read.
958 	 */
959 	reg_val = 0xf11100;
960 	regmap_raw_write(priv->dsp->regmap,
961 			 cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM),
962 			 &reg_val, sizeof(reg_val));
963 
964 	def.type = param->ctl_type;
965 	def.flags = param->flags;
966 	def.mem_type = WMFW_ADSP2_YM;
967 
968 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
969 					      cs_dsp_ctl_parse_test_algs[0].id,
970 					      "dummyalg", NULL);
971 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
972 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
973 
974 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
975 	KUNIT_ASSERT_LT(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
976 }
977 
978 /* Test that the correct firmware name is entered in the cs_dsp_coeff_ctl. */
cs_dsp_ctl_parse_fw_name(struct kunit * test)979 static void cs_dsp_ctl_parse_fw_name(struct kunit *test)
980 {
981 	struct cs_dsp_test *priv = test->priv;
982 	struct cs_dsp_test_local *local = priv->local;
983 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
984 	struct cs_dsp_coeff_ctl *walkctl, *ctl1, *ctl2;
985 	struct cs_dsp_mock_wmfw_builder *builder2;
986 	struct firmware *wmfw;
987 
988 	/* Create a second mock wmfw builder */
989 	builder2 = cs_dsp_mock_wmfw_init(priv,
990 					 cs_dsp_mock_wmfw_format_version(local->wmfw_builder));
991 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, builder2);
992 	cs_dsp_mock_wmfw_add_data_block(builder2,
993 					WMFW_ADSP2_XM, 0,
994 					local->xm_header->blob_data,
995 					local->xm_header->blob_size_bytes);
996 
997 	/* Load a 'misc' firmware with a control */
998 	def.offset_dsp_words = 1;
999 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1000 					      cs_dsp_ctl_parse_test_algs[0].id,
1001 					      "dummyalg", NULL);
1002 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1003 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1004 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
1005 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1006 	cs_dsp_power_down(priv->dsp);
1007 
1008 	/* Load a 'mbc/vss' firmware with a control */
1009 	def.offset_dsp_words = 2;
1010 	cs_dsp_mock_wmfw_start_alg_info_block(builder2,
1011 					      cs_dsp_ctl_parse_test_algs[0].id,
1012 					      "dummyalg", NULL);
1013 	cs_dsp_mock_wmfw_add_coeff_desc(builder2, &def);
1014 	cs_dsp_mock_wmfw_end_alg_info_block(builder2);
1015 	wmfw = cs_dsp_mock_wmfw_get_firmware(builder2);
1016 	KUNIT_ASSERT_EQ(test,
1017 			cs_dsp_power_up(priv->dsp, wmfw, "mock_fw2", NULL, NULL, "mbc/vss"), 0);
1018 
1019 	/* Both controls should be in the list (order not guaranteed) */
1020 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2);
1021 	ctl1 = NULL;
1022 	ctl2 = NULL;
1023 	list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) {
1024 		if (strcmp(walkctl->fw_name, "misc") == 0)
1025 			ctl1 = walkctl;
1026 		else if (strcmp(walkctl->fw_name, "mbc/vss") == 0)
1027 			ctl2 = walkctl;
1028 	}
1029 
1030 	KUNIT_EXPECT_NOT_NULL(test, ctl1);
1031 	KUNIT_EXPECT_NOT_NULL(test, ctl2);
1032 	KUNIT_EXPECT_EQ(test, ctl1->offset, 1);
1033 	KUNIT_EXPECT_EQ(test, ctl2->offset, 2);
1034 }
1035 
1036 /* Controls are unique if the algorithm ID is different */
cs_dsp_ctl_alg_id_uniqueness(struct kunit * test)1037 static void cs_dsp_ctl_alg_id_uniqueness(struct kunit *test)
1038 {
1039 	struct cs_dsp_test *priv = test->priv;
1040 	struct cs_dsp_test_local *local = priv->local;
1041 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
1042 	struct cs_dsp_coeff_ctl *ctl1, *ctl2;
1043 	struct firmware *wmfw;
1044 
1045 	/* Create an algorithm containing the control */
1046 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1047 					      cs_dsp_ctl_parse_test_algs[0].id,
1048 					      "dummyalg", NULL);
1049 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1050 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1051 
1052 	/* Create a different algorithm containing an identical control */
1053 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1054 					      cs_dsp_ctl_parse_test_algs[1].id,
1055 					      "dummyalg", NULL);
1056 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1057 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1058 
1059 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
1060 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1061 	cs_dsp_power_down(priv->dsp);
1062 
1063 	/* Both controls should be in the list */
1064 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2);
1065 	ctl1 = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
1066 	ctl2 = list_next_entry(ctl1, list);
1067 	KUNIT_EXPECT_NOT_NULL(test, ctl1);
1068 	KUNIT_EXPECT_NOT_NULL(test, ctl2);
1069 	KUNIT_EXPECT_NE(test, ctl1->alg_region.alg, ctl2->alg_region.alg);
1070 	KUNIT_EXPECT_EQ(test, ctl1->alg_region.type, ctl2->alg_region.type);
1071 	KUNIT_EXPECT_EQ(test, ctl1->offset, ctl2->offset);
1072 	KUNIT_EXPECT_EQ(test, ctl1->type, ctl2->type);
1073 	KUNIT_EXPECT_EQ(test, ctl1->flags, ctl2->flags);
1074 	KUNIT_EXPECT_EQ(test, ctl1->len, ctl2->len);
1075 	KUNIT_EXPECT_STREQ(test, ctl1->fw_name, ctl2->fw_name);
1076 	KUNIT_EXPECT_EQ(test, ctl1->subname_len, ctl2->subname_len);
1077 	if (ctl1->subname_len)
1078 		KUNIT_EXPECT_MEMEQ(test, ctl1->subname, ctl2->subname, ctl1->subname_len);
1079 }
1080 
1081 /* Controls are unique if the memory region is different */
cs_dsp_ctl_mem_uniqueness(struct kunit * test)1082 static void cs_dsp_ctl_mem_uniqueness(struct kunit *test)
1083 {
1084 	struct cs_dsp_test *priv = test->priv;
1085 	struct cs_dsp_test_local *local = priv->local;
1086 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
1087 	struct cs_dsp_coeff_ctl *ctl1, *ctl2;
1088 	struct firmware *wmfw;
1089 
1090 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1091 					      cs_dsp_ctl_parse_test_algs[0].id,
1092 					      "dummyalg", NULL);
1093 	/* Create control in XM */
1094 	def.mem_type = WMFW_ADSP2_XM;
1095 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1096 
1097 	/* Create control in YM */
1098 	def.mem_type = WMFW_ADSP2_YM;
1099 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1100 
1101 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1102 
1103 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
1104 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1105 	cs_dsp_power_down(priv->dsp);
1106 
1107 	/* Both controls should be in the list */
1108 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2);
1109 	ctl1 = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
1110 	ctl2 = list_next_entry(ctl1, list);
1111 	KUNIT_EXPECT_NOT_NULL(test, ctl1);
1112 	KUNIT_EXPECT_NOT_NULL(test, ctl2);
1113 	KUNIT_EXPECT_EQ(test, ctl1->alg_region.alg, ctl2->alg_region.alg);
1114 	KUNIT_EXPECT_NE(test, ctl1->alg_region.type, ctl2->alg_region.type);
1115 	KUNIT_EXPECT_EQ(test, ctl1->offset, ctl2->offset);
1116 	KUNIT_EXPECT_EQ(test, ctl1->type, ctl2->type);
1117 	KUNIT_EXPECT_EQ(test, ctl1->flags, ctl2->flags);
1118 	KUNIT_EXPECT_EQ(test, ctl1->len, ctl2->len);
1119 	KUNIT_EXPECT_STREQ(test, ctl1->fw_name, ctl2->fw_name);
1120 	KUNIT_EXPECT_EQ(test, ctl1->subname_len, ctl2->subname_len);
1121 	if (ctl1->subname_len)
1122 		KUNIT_EXPECT_MEMEQ(test, ctl1->subname, ctl2->subname, ctl1->subname_len);
1123 }
1124 
1125 /* Controls are unique if they are in different firmware */
cs_dsp_ctl_fw_uniqueness(struct kunit * test)1126 static void cs_dsp_ctl_fw_uniqueness(struct kunit *test)
1127 {
1128 	struct cs_dsp_test *priv = test->priv;
1129 	struct cs_dsp_test_local *local = priv->local;
1130 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
1131 	struct cs_dsp_coeff_ctl *ctl1, *ctl2;
1132 	struct cs_dsp_mock_wmfw_builder *builder2;
1133 	struct firmware *wmfw;
1134 
1135 	/* Create a second mock wmfw builder */
1136 	builder2 = cs_dsp_mock_wmfw_init(priv,
1137 					 cs_dsp_mock_wmfw_format_version(local->wmfw_builder));
1138 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, builder2);
1139 	cs_dsp_mock_wmfw_add_data_block(builder2,
1140 					WMFW_ADSP2_XM, 0,
1141 					local->xm_header->blob_data,
1142 					local->xm_header->blob_size_bytes);
1143 
1144 	/* Load a 'misc' firmware with a control */
1145 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1146 					      cs_dsp_ctl_parse_test_algs[0].id,
1147 					      "dummyalg", NULL);
1148 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1149 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1150 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
1151 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1152 	cs_dsp_power_down(priv->dsp);
1153 
1154 	/* Load a 'mbc/vss' firmware with the same control */
1155 	cs_dsp_mock_wmfw_start_alg_info_block(builder2,
1156 					      cs_dsp_ctl_parse_test_algs[0].id,
1157 					      "dummyalg", NULL);
1158 	cs_dsp_mock_wmfw_add_coeff_desc(builder2, &def);
1159 	cs_dsp_mock_wmfw_end_alg_info_block(builder2);
1160 	wmfw = cs_dsp_mock_wmfw_get_firmware(builder2);
1161 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw2",
1162 			NULL, NULL, "mbc/vss"), 0);
1163 	cs_dsp_power_down(priv->dsp);
1164 
1165 	/* Both controls should be in the list */
1166 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2);
1167 	ctl1 = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
1168 	ctl2 = list_next_entry(ctl1, list);
1169 	KUNIT_EXPECT_NOT_NULL(test, ctl1);
1170 	KUNIT_EXPECT_NOT_NULL(test, ctl2);
1171 	KUNIT_EXPECT_EQ(test, ctl1->alg_region.alg, ctl2->alg_region.alg);
1172 	KUNIT_EXPECT_EQ(test, ctl1->alg_region.type, ctl2->alg_region.type);
1173 	KUNIT_EXPECT_EQ(test, ctl1->offset, ctl2->offset);
1174 	KUNIT_EXPECT_EQ(test, ctl1->type, ctl2->type);
1175 	KUNIT_EXPECT_EQ(test, ctl1->flags, ctl2->flags);
1176 	KUNIT_EXPECT_EQ(test, ctl1->len, ctl2->len);
1177 	KUNIT_EXPECT_STRNEQ(test, ctl1->fw_name, ctl2->fw_name);
1178 	KUNIT_EXPECT_EQ(test, ctl1->subname_len, ctl2->subname_len);
1179 	if (ctl1->subname_len)
1180 		KUNIT_EXPECT_MEMEQ(test, ctl1->subname, ctl2->subname, ctl1->subname_len);
1181 }
1182 
1183 /*
1184  * Controls from a wmfw are only added to the list once. If the same
1185  * wmfw is reloaded the controls are not added again.
1186  * This creates multiple algorithms with one control each, which will
1187  * work on both V1 format and >=V2 format controls.
1188  */
cs_dsp_ctl_squash_reloaded_controls(struct kunit * test)1189 static void cs_dsp_ctl_squash_reloaded_controls(struct kunit *test)
1190 {
1191 	struct cs_dsp_test *priv = test->priv;
1192 	struct cs_dsp_test_local *local = priv->local;
1193 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
1194 	struct cs_dsp_coeff_ctl *ctls[ARRAY_SIZE(cs_dsp_ctl_parse_test_algs)];
1195 	struct cs_dsp_coeff_ctl *walkctl;
1196 	struct firmware *wmfw;
1197 	int i;
1198 
1199 	/* Create some algorithms with a control */
1200 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_parse_test_algs); i++) {
1201 		cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1202 						      cs_dsp_ctl_parse_test_algs[i].id,
1203 						      "dummyalg", NULL);
1204 		def.mem_type = WMFW_ADSP2_YM;
1205 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1206 		cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1207 	}
1208 
1209 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
1210 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1211 	cs_dsp_power_down(priv->dsp);
1212 
1213 	/* All controls should be in the list */
1214 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list),
1215 			ARRAY_SIZE(cs_dsp_ctl_parse_test_algs));
1216 
1217 	/* Take a copy of the pointers to controls to compare against. */
1218 	i = 0;
1219 	list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) {
1220 		KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls));
1221 		ctls[i++] = walkctl;
1222 	}
1223 
1224 
1225 	/* Load the wmfw again */
1226 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1227 	cs_dsp_power_down(priv->dsp);
1228 
1229 	/* The number of controls should be the same */
1230 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list),
1231 			ARRAY_SIZE(cs_dsp_ctl_parse_test_algs));
1232 
1233 	/* And they should be the same objects */
1234 	i = 0;
1235 	list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) {
1236 		KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls));
1237 		KUNIT_ASSERT_PTR_EQ(test, walkctl, ctls[i++]);
1238 	}
1239 }
1240 
1241 /*
1242  * Controls from a wmfw are only added to the list once. If the same
1243  * wmfw is reloaded the controls are not added again.
1244  * This tests >=V2 firmware that can have multiple named controls in
1245  * the same algorithm.
1246  */
cs_dsp_ctl_v2_squash_reloaded_controls(struct kunit * test)1247 static void cs_dsp_ctl_v2_squash_reloaded_controls(struct kunit *test)
1248 {
1249 	struct cs_dsp_test *priv = test->priv;
1250 	struct cs_dsp_test_local *local = priv->local;
1251 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
1252 	struct cs_dsp_coeff_ctl *ctls[ARRAY_SIZE(cs_dsp_get_ctl_test_names)];
1253 	struct cs_dsp_coeff_ctl *walkctl;
1254 	struct firmware *wmfw;
1255 	int i;
1256 
1257 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1258 					      cs_dsp_ctl_parse_test_algs[0].id,
1259 					      "dummyalg", NULL);
1260 
1261 	/* Create some controls */
1262 	for (i = 0; i < ARRAY_SIZE(cs_dsp_get_ctl_test_names); i++) {
1263 		def.shortname = cs_dsp_get_ctl_test_names[i];
1264 		def.offset_dsp_words = i;
1265 		if (i & BIT(0))
1266 			def.mem_type = WMFW_ADSP2_XM;
1267 		else
1268 			def.mem_type = WMFW_ADSP2_YM;
1269 
1270 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1271 	}
1272 
1273 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1274 
1275 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
1276 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1277 	cs_dsp_power_down(priv->dsp);
1278 
1279 	/* All controls should be in the list */
1280 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list),
1281 			ARRAY_SIZE(cs_dsp_get_ctl_test_names));
1282 
1283 	/* Take a copy of the pointers to controls to compare against. */
1284 	i = 0;
1285 	list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) {
1286 		KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls));
1287 		ctls[i++] = walkctl;
1288 	}
1289 
1290 
1291 	/* Load the wmfw again */
1292 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1293 	cs_dsp_power_down(priv->dsp);
1294 
1295 	/* The number of controls should be the same */
1296 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list),
1297 			ARRAY_SIZE(cs_dsp_get_ctl_test_names));
1298 
1299 	/* And they should be the same objects */
1300 	i = 0;
1301 	list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) {
1302 		KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls));
1303 		KUNIT_ASSERT_PTR_EQ(test, walkctl, ctls[i++]);
1304 	}
1305 }
1306 
1307 static const char * const cs_dsp_ctl_v2_compare_len_names[] = {
1308 	"LEFT",
1309 	"LEFT_",
1310 	"LEFT_SPK",
1311 	"LEFT_SPK_V",
1312 	"LEFT_SPK_VOL",
1313 	"LEFT_SPK_MUTE",
1314 	"LEFT_SPK_1",
1315 	"LEFT_X",
1316 	"LEFT2",
1317 };
1318 
1319 /*
1320  * When comparing shortnames the full length of both strings is
1321  * considered, not only the characters in of the shortest string.
1322  * So that "LEFT" is not the same as "LEFT2".
1323  * This is specifically to test for the bug that was fixed by commit:
1324  * 7ac1102b227b ("firmware: cs_dsp: Fix new control name check")
1325  */
cs_dsp_ctl_v2_compare_len(struct kunit * test)1326 static void cs_dsp_ctl_v2_compare_len(struct kunit *test)
1327 {
1328 	struct cs_dsp_test *priv = test->priv;
1329 	struct cs_dsp_test_local *local = priv->local;
1330 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
1331 	struct cs_dsp_coeff_ctl *ctl;
1332 	struct firmware *wmfw;
1333 	int i;
1334 
1335 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
1336 					      cs_dsp_ctl_parse_test_algs[0].id,
1337 					      "dummyalg", NULL);
1338 
1339 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_v2_compare_len_names); i++) {
1340 		def.shortname = cs_dsp_ctl_v2_compare_len_names[i];
1341 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
1342 	}
1343 
1344 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
1345 
1346 	wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
1347 	KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0);
1348 
1349 	for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_v2_compare_len_names); i++) {
1350 		mutex_lock(&priv->dsp->pwr_lock);
1351 		ctl = cs_dsp_get_ctl(priv->dsp, cs_dsp_ctl_v2_compare_len_names[i],
1352 				     def.mem_type, cs_dsp_ctl_parse_test_algs[0].id);
1353 		mutex_unlock(&priv->dsp->pwr_lock);
1354 		KUNIT_ASSERT_NOT_NULL(test, ctl);
1355 		KUNIT_EXPECT_EQ(test, ctl->subname_len,
1356 				strlen(cs_dsp_ctl_v2_compare_len_names[i]));
1357 		KUNIT_EXPECT_MEMEQ(test, ctl->subname, cs_dsp_ctl_v2_compare_len_names[i],
1358 				   ctl->subname_len);
1359 	}
1360 }
1361 
cs_dsp_ctl_parse_test_common_init(struct kunit * test,struct cs_dsp * dsp,int wmfw_version)1362 static int cs_dsp_ctl_parse_test_common_init(struct kunit *test, struct cs_dsp *dsp,
1363 					     int wmfw_version)
1364 {
1365 	struct cs_dsp_test *priv;
1366 	struct cs_dsp_test_local *local;
1367 	struct device *test_dev;
1368 	int ret;
1369 
1370 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
1371 	if (!priv)
1372 		return -ENOMEM;
1373 
1374 	local = kunit_kzalloc(test, sizeof(struct cs_dsp_test_local), GFP_KERNEL);
1375 	if (!local)
1376 		return -ENOMEM;
1377 
1378 	priv->test = test;
1379 	priv->dsp = dsp;
1380 	test->priv = priv;
1381 	priv->local = local;
1382 	priv->local->wmfw_version = wmfw_version;
1383 
1384 	/* Create dummy struct device */
1385 	test_dev = kunit_device_register(test, "cs_dsp_test_drv");
1386 	if (IS_ERR(test_dev))
1387 		return PTR_ERR(test_dev);
1388 
1389 	dsp->dev = get_device(test_dev);
1390 	if (!dsp->dev)
1391 		return -ENODEV;
1392 
1393 	ret = kunit_add_action_or_reset(test, _put_device_wrapper, dsp->dev);
1394 	if (ret)
1395 		return ret;
1396 
1397 	dev_set_drvdata(dsp->dev, priv);
1398 
1399 	/* Allocate regmap */
1400 	ret = cs_dsp_mock_regmap_init(priv);
1401 	if (ret)
1402 		return ret;
1403 
1404 	/*
1405 	 * There must always be a XM header with at least 1 algorithm, so create
1406 	 * a dummy one that tests can use and extract it to a data blob.
1407 	 */
1408 	local->xm_header = cs_dsp_create_mock_xm_header(priv,
1409 							cs_dsp_ctl_parse_test_algs,
1410 							ARRAY_SIZE(cs_dsp_ctl_parse_test_algs));
1411 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->xm_header);
1412 
1413 	local->wmfw_builder = cs_dsp_mock_wmfw_init(priv, priv->local->wmfw_version);
1414 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->wmfw_builder);
1415 
1416 	/* Add dummy XM header blob to wmfw */
1417 	cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
1418 					WMFW_ADSP2_XM, 0,
1419 					local->xm_header->blob_data,
1420 					local->xm_header->blob_size_bytes);
1421 
1422 	/* Init cs_dsp */
1423 	dsp->client_ops = kunit_kzalloc(test, sizeof(*dsp->client_ops), GFP_KERNEL);
1424 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp->client_ops);
1425 
1426 	switch (dsp->type) {
1427 	case WMFW_ADSP2:
1428 		ret = cs_dsp_adsp2_init(dsp);
1429 		break;
1430 	case WMFW_HALO:
1431 		ret = cs_dsp_halo_init(dsp);
1432 		break;
1433 	default:
1434 		KUNIT_FAIL(test, "Untested DSP type %d\n", dsp->type);
1435 		return -EINVAL;
1436 	}
1437 
1438 	if (ret)
1439 		return ret;
1440 
1441 	/* Automatically call cs_dsp_remove() when test case ends */
1442 	return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
1443 }
1444 
cs_dsp_ctl_parse_test_halo_init(struct kunit * test)1445 static int cs_dsp_ctl_parse_test_halo_init(struct kunit *test)
1446 {
1447 	struct cs_dsp *dsp;
1448 
1449 	/* Fill in cs_dsp and initialize */
1450 	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
1451 	if (!dsp)
1452 		return -ENOMEM;
1453 
1454 	dsp->num = 1;
1455 	dsp->type = WMFW_HALO;
1456 	dsp->mem = cs_dsp_mock_halo_dsp1_regions;
1457 	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_halo_dsp1_region_sizes);
1458 	dsp->base = cs_dsp_mock_halo_core_base;
1459 	dsp->base_sysinfo = cs_dsp_mock_halo_sysinfo_base;
1460 
1461 	return cs_dsp_ctl_parse_test_common_init(test, dsp, 3);
1462 }
1463 
cs_dsp_ctl_parse_test_adsp2_32bit_init(struct kunit * test,int wmfw_ver)1464 static int cs_dsp_ctl_parse_test_adsp2_32bit_init(struct kunit *test, int wmfw_ver)
1465 {
1466 	struct cs_dsp *dsp;
1467 
1468 	/* Fill in cs_dsp and initialize */
1469 	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
1470 	if (!dsp)
1471 		return -ENOMEM;
1472 
1473 	dsp->num = 1;
1474 	dsp->type = WMFW_ADSP2;
1475 	dsp->rev = 1;
1476 	dsp->mem = cs_dsp_mock_adsp2_32bit_dsp1_regions;
1477 	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_32bit_dsp1_region_sizes);
1478 	dsp->base = cs_dsp_mock_adsp2_32bit_sysbase;
1479 
1480 	return cs_dsp_ctl_parse_test_common_init(test, dsp, wmfw_ver);
1481 }
1482 
cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1_init(struct kunit * test)1483 static int cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1_init(struct kunit *test)
1484 {
1485 	return cs_dsp_ctl_parse_test_adsp2_32bit_init(test, 1);
1486 }
1487 
cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2_init(struct kunit * test)1488 static int cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2_init(struct kunit *test)
1489 {
1490 	return cs_dsp_ctl_parse_test_adsp2_32bit_init(test, 2);
1491 }
1492 
cs_dsp_ctl_parse_test_adsp2_16bit_init(struct kunit * test,int wmfw_ver)1493 static int cs_dsp_ctl_parse_test_adsp2_16bit_init(struct kunit *test, int wmfw_ver)
1494 {
1495 	struct cs_dsp *dsp;
1496 
1497 	/* Fill in cs_dsp and initialize */
1498 	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
1499 	if (!dsp)
1500 		return -ENOMEM;
1501 
1502 	dsp->num = 1;
1503 	dsp->type = WMFW_ADSP2;
1504 	dsp->rev = 0;
1505 	dsp->mem = cs_dsp_mock_adsp2_16bit_dsp1_regions;
1506 	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_16bit_dsp1_region_sizes);
1507 	dsp->base = cs_dsp_mock_adsp2_16bit_sysbase;
1508 
1509 	return cs_dsp_ctl_parse_test_common_init(test, dsp, wmfw_ver);
1510 }
1511 
cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1_init(struct kunit * test)1512 static int cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1_init(struct kunit *test)
1513 {
1514 	return cs_dsp_ctl_parse_test_adsp2_16bit_init(test, 1);
1515 }
1516 
cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2_init(struct kunit * test)1517 static int cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2_init(struct kunit *test)
1518 {
1519 	return cs_dsp_ctl_parse_test_adsp2_16bit_init(test, 2);
1520 }
1521 
1522 static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_mem_type_param_cases[] = {
1523 	{ .mem_type = WMFW_ADSP2_XM },
1524 	{ .mem_type = WMFW_ADSP2_YM },
1525 	{ .mem_type = WMFW_ADSP2_ZM },
1526 };
1527 
cs_dsp_ctl_mem_type_desc(const struct cs_dsp_ctl_parse_test_param * param,char * desc)1528 static void cs_dsp_ctl_mem_type_desc(const struct cs_dsp_ctl_parse_test_param *param,
1529 				     char *desc)
1530 {
1531 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s",
1532 		 cs_dsp_mem_region_name(param->mem_type));
1533 }
1534 
1535 KUNIT_ARRAY_PARAM(cs_dsp_ctl_mem_type,
1536 		  cs_dsp_ctl_mem_type_param_cases,
1537 		  cs_dsp_ctl_mem_type_desc);
1538 
1539 static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_alg_id_param_cases[] = {
1540 	{ .alg_id = 0xb },
1541 	{ .alg_id = 0xfafa },
1542 	{ .alg_id = 0x9f1234 },
1543 	{ .alg_id = 0xff00ff },
1544 };
1545 
cs_dsp_ctl_alg_id_desc(const struct cs_dsp_ctl_parse_test_param * param,char * desc)1546 static void cs_dsp_ctl_alg_id_desc(const struct cs_dsp_ctl_parse_test_param *param,
1547 				   char *desc)
1548 {
1549 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "alg_id:%#x", param->alg_id);
1550 }
1551 
1552 KUNIT_ARRAY_PARAM(cs_dsp_ctl_alg_id,
1553 		  cs_dsp_ctl_alg_id_param_cases,
1554 		  cs_dsp_ctl_alg_id_desc);
1555 
1556 static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_offset_param_cases[] = {
1557 	{ .offset = 0x0 },
1558 	{ .offset = 0x1 },
1559 	{ .offset = 0x2 },
1560 	{ .offset = 0x3 },
1561 	{ .offset = 0x4 },
1562 	{ .offset = 0x5 },
1563 	{ .offset = 0x6 },
1564 	{ .offset = 0x7 },
1565 	{ .offset = 0xe0 },
1566 	{ .offset = 0xf1 },
1567 	{ .offset = 0xfffe },
1568 	{ .offset = 0xffff },
1569 };
1570 
cs_dsp_ctl_offset_desc(const struct cs_dsp_ctl_parse_test_param * param,char * desc)1571 static void cs_dsp_ctl_offset_desc(const struct cs_dsp_ctl_parse_test_param *param,
1572 				   char *desc)
1573 {
1574 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "offset:%#x", param->offset);
1575 }
1576 
1577 KUNIT_ARRAY_PARAM(cs_dsp_ctl_offset,
1578 		  cs_dsp_ctl_offset_param_cases,
1579 		  cs_dsp_ctl_offset_desc);
1580 
1581 static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_length_param_cases[] = {
1582 	{ .length = 0x4 },
1583 	{ .length = 0x8 },
1584 	{ .length = 0x18 },
1585 	{ .length = 0xf000 },
1586 };
1587 
cs_dsp_ctl_length_desc(const struct cs_dsp_ctl_parse_test_param * param,char * desc)1588 static void cs_dsp_ctl_length_desc(const struct cs_dsp_ctl_parse_test_param *param,
1589 				   char *desc)
1590 {
1591 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "length:%#x", param->length);
1592 }
1593 
1594 KUNIT_ARRAY_PARAM(cs_dsp_ctl_length,
1595 		  cs_dsp_ctl_length_param_cases,
1596 		  cs_dsp_ctl_length_desc);
1597 
1598 /* Note: some control types mandate specific flags settings */
1599 static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_type_param_cases[] = {
1600 	{ .ctl_type = WMFW_CTL_TYPE_BYTES,
1601 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1602 	{ .ctl_type = WMFW_CTL_TYPE_ACKED,
1603 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1604 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1605 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE |
1606 		   WMFW_CTL_FLAG_SYS },
1607 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1608 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_SYS },
1609 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1610 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE |
1611 		   WMFW_CTL_FLAG_SYS },
1612 };
1613 
cs_dsp_ctl_type_flags_desc(const struct cs_dsp_ctl_parse_test_param * param,char * desc)1614 static void cs_dsp_ctl_type_flags_desc(const struct cs_dsp_ctl_parse_test_param *param,
1615 				       char *desc)
1616 {
1617 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "ctl_type:%#x flags:%#x",
1618 		 param->ctl_type, param->flags);
1619 }
1620 
1621 KUNIT_ARRAY_PARAM(cs_dsp_ctl_type,
1622 		  cs_dsp_ctl_type_param_cases,
1623 		  cs_dsp_ctl_type_flags_desc);
1624 
1625 static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_flags_param_cases[] = {
1626 	{ .flags = 0 },
1627 	{ .flags = WMFW_CTL_FLAG_READABLE },
1628 	{ .flags = WMFW_CTL_FLAG_WRITEABLE },
1629 	{ .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1630 	{ .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1631 	{ .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1632 	{ .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE },
1633 	{ .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE },
1634 	{ .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1635 	{ .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1636 	{ .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE |
1637 		   WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1638 };
1639 
cs_dsp_ctl_flags_desc(const struct cs_dsp_ctl_parse_test_param * param,char * desc)1640 static void cs_dsp_ctl_flags_desc(const struct cs_dsp_ctl_parse_test_param *param,
1641 				  char *desc)
1642 {
1643 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "flags:%#x", param->flags);
1644 }
1645 
1646 KUNIT_ARRAY_PARAM(cs_dsp_ctl_flags,
1647 		  cs_dsp_ctl_flags_param_cases,
1648 		  cs_dsp_ctl_flags_desc);
1649 
1650 static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_illegal_type_flags_param_cases[] = {
1651 	/* ACKED control must be volatile + read + write */
1652 	{ .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = 0 },
1653 	{ .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = WMFW_CTL_FLAG_READABLE },
1654 	{ .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = WMFW_CTL_FLAG_WRITEABLE },
1655 	{ .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = WMFW_CTL_FLAG_VOLATILE },
1656 	{ .ctl_type = WMFW_CTL_TYPE_ACKED,
1657 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1658 	{ .ctl_type = WMFW_CTL_TYPE_ACKED,
1659 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE },
1660 
1661 	/* HOSTEVENT must be system + volatile + read + write */
1662 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = 0 },
1663 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_READABLE },
1664 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_WRITEABLE },
1665 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1666 	  .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1667 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_VOLATILE },
1668 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1669 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1670 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1671 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE },
1672 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1673 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1674 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_SYS },
1675 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1676 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE },
1677 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1678 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE },
1679 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1680 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE },
1681 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1682 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1683 	{ .ctl_type = WMFW_CTL_TYPE_HOSTEVENT,
1684 	  .flags = WMFW_CTL_FLAG_SYS |  WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE },
1685 
1686 	/* FWEVENT rules same as HOSTEVENT */
1687 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = 0 },
1688 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_READABLE },
1689 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_WRITEABLE },
1690 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1691 	  .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1692 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_VOLATILE },
1693 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1694 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1695 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1696 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE },
1697 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1698 	  .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1699 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_SYS },
1700 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1701 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE },
1702 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1703 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE },
1704 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1705 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE },
1706 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1707 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1708 	{ .ctl_type = WMFW_CTL_TYPE_FWEVENT,
1709 	  .flags = WMFW_CTL_FLAG_SYS |  WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE },
1710 
1711 	/*
1712 	 * HOSTBUFFER must be system + volatile + readable or
1713 	 * system + volatile + readable + writeable
1714 	 */
1715 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = 0 },
1716 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_READABLE },
1717 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_WRITEABLE },
1718 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1719 	   .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE},
1720 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_VOLATILE },
1721 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1722 	   .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE },
1723 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1724 	   .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE },
1725 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1726 	   .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1727 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_SYS },
1728 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1729 	   .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE },
1730 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1731 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE },
1732 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1733 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE },
1734 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1735 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE },
1736 	{ .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER,
1737 	  .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE },
1738 };
1739 
1740 KUNIT_ARRAY_PARAM(cs_dsp_ctl_illegal_type_flags,
1741 		  cs_dsp_ctl_illegal_type_flags_param_cases,
1742 		  cs_dsp_ctl_type_flags_desc);
1743 
1744 static struct kunit_case cs_dsp_ctl_parse_test_cases_v1[] = {
1745 	KUNIT_CASE(cs_dsp_ctl_parse_no_coeffs),
1746 	KUNIT_CASE(cs_dsp_ctl_parse_v1_name),
1747 	KUNIT_CASE(cs_dsp_ctl_parse_empty_v1_name),
1748 	KUNIT_CASE(cs_dsp_ctl_parse_max_v1_name),
1749 
1750 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_memory_type, cs_dsp_ctl_mem_type_gen_params),
1751 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_id, cs_dsp_ctl_alg_id_gen_params),
1752 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_mem, cs_dsp_ctl_mem_type_gen_params),
1753 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_offset, cs_dsp_ctl_offset_gen_params),
1754 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_length, cs_dsp_ctl_length_gen_params),
1755 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_ctl_type, cs_dsp_ctl_type_gen_params),
1756 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_flags, cs_dsp_ctl_flags_gen_params),
1757 	KUNIT_CASE(cs_dsp_ctl_parse_fw_name),
1758 
1759 	KUNIT_CASE(cs_dsp_ctl_alg_id_uniqueness),
1760 	KUNIT_CASE(cs_dsp_ctl_mem_uniqueness),
1761 	KUNIT_CASE(cs_dsp_ctl_fw_uniqueness),
1762 	KUNIT_CASE(cs_dsp_ctl_squash_reloaded_controls),
1763 
1764 	{ } /* terminator */
1765 };
1766 
1767 static struct kunit_case cs_dsp_ctl_parse_test_cases_v2_v3[] = {
1768 	KUNIT_CASE(cs_dsp_ctl_parse_no_coeffs),
1769 	KUNIT_CASE(cs_dsp_ctl_parse_short_name),
1770 	KUNIT_CASE(cs_dsp_ctl_parse_min_short_name),
1771 	KUNIT_CASE(cs_dsp_ctl_parse_max_short_name),
1772 	KUNIT_CASE(cs_dsp_ctl_parse_with_min_fullname),
1773 	KUNIT_CASE(cs_dsp_ctl_parse_with_max_fullname),
1774 	KUNIT_CASE(cs_dsp_ctl_parse_with_min_description),
1775 	KUNIT_CASE(cs_dsp_ctl_parse_with_max_description),
1776 	KUNIT_CASE(cs_dsp_ctl_parse_with_max_fullname_and_description),
1777 	KUNIT_CASE(cs_dsp_ctl_shortname_alignment),
1778 	KUNIT_CASE(cs_dsp_ctl_fullname_alignment),
1779 	KUNIT_CASE(cs_dsp_ctl_description_alignment),
1780 	KUNIT_CASE(cs_dsp_get_ctl_test),
1781 	KUNIT_CASE(cs_dsp_get_ctl_test_multiple_wmfw),
1782 
1783 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_memory_type, cs_dsp_ctl_mem_type_gen_params),
1784 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_id, cs_dsp_ctl_alg_id_gen_params),
1785 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_mem, cs_dsp_ctl_mem_type_gen_params),
1786 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_offset, cs_dsp_ctl_offset_gen_params),
1787 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_length, cs_dsp_ctl_length_gen_params),
1788 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_ctl_type, cs_dsp_ctl_type_gen_params),
1789 	KUNIT_CASE_PARAM(cs_dsp_ctl_parse_flags, cs_dsp_ctl_flags_gen_params),
1790 	KUNIT_CASE_PARAM(cs_dsp_ctl_illegal_type_flags,
1791 			 cs_dsp_ctl_illegal_type_flags_gen_params),
1792 	KUNIT_CASE(cs_dsp_ctl_parse_fw_name),
1793 
1794 	KUNIT_CASE(cs_dsp_ctl_alg_id_uniqueness),
1795 	KUNIT_CASE(cs_dsp_ctl_mem_uniqueness),
1796 	KUNIT_CASE(cs_dsp_ctl_fw_uniqueness),
1797 	KUNIT_CASE(cs_dsp_ctl_squash_reloaded_controls),
1798 	KUNIT_CASE(cs_dsp_ctl_v2_squash_reloaded_controls),
1799 	KUNIT_CASE(cs_dsp_ctl_v2_compare_len),
1800 
1801 	{ } /* terminator */
1802 };
1803 
1804 static struct kunit_suite cs_dsp_ctl_parse_test_halo = {
1805 	.name = "cs_dsp_ctl_parse_wmfwV3_halo",
1806 	.init = cs_dsp_ctl_parse_test_halo_init,
1807 	.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
1808 };
1809 
1810 static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1 = {
1811 	.name = "cs_dsp_ctl_parse_wmfwV1_adsp2_32bit",
1812 	.init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1_init,
1813 	.test_cases = cs_dsp_ctl_parse_test_cases_v1,
1814 };
1815 
1816 static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2 = {
1817 	.name = "cs_dsp_ctl_parse_wmfwV2_adsp2_32bit",
1818 	.init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2_init,
1819 	.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
1820 };
1821 
1822 static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1 = {
1823 	.name = "cs_dsp_ctl_parse_wmfwV1_adsp2_16bit",
1824 	.init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1_init,
1825 	.test_cases = cs_dsp_ctl_parse_test_cases_v1,
1826 };
1827 
1828 static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2 = {
1829 	.name = "cs_dsp_ctl_parse_wmfwV2_adsp2_16bit",
1830 	.init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2_init,
1831 	.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
1832 };
1833 
1834 kunit_test_suites(&cs_dsp_ctl_parse_test_halo,
1835 		  &cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1,
1836 		  &cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2,
1837 		  &cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1,
1838 		  &cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2);
1839