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