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 
9 #include <kunit/device.h>
10 #include <kunit/resource.h>
11 #include <kunit/test.h>
12 #include <kunit/test-bug.h>
13 #include <linux/build_bug.h>
14 #include <linux/firmware/cirrus/cs_dsp.h>
15 #include <linux/firmware/cirrus/cs_dsp_test_utils.h>
16 #include <linux/firmware/cirrus/wmfw.h>
17 #include <linux/random.h>
18 #include <linux/regmap.h>
19 #include <linux/string.h>
20 #include <linux/vmalloc.h>
21 
22 #define ADSP2_LOCK_REGION_CTRL               0x7A
23 #define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
24 
25 KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *)
26 KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *)
27 
28 struct cs_dsp_test_local {
29 	struct cs_dsp_mock_wmfw_builder *wmfw_builder;
30 
31 	int num_control_add;
32 	int num_control_remove;
33 	int num_pre_run;
34 	int num_post_run;
35 	int num_pre_stop;
36 	int num_post_stop;
37 	int num_watchdog_expired;
38 
39 	struct cs_dsp_coeff_ctl *passed_ctl[16];
40 	struct cs_dsp *passed_dsp;
41 };
42 
43 struct cs_dsp_callbacks_test_param {
44 	const struct cs_dsp_client_ops *ops;
45 	const char *case_name;
46 };
47 
48 static const struct cs_dsp_mock_alg_def cs_dsp_callbacks_test_mock_algs[] = {
49 	{
50 		.id = 0xfafa,
51 		.ver = 0x100000,
52 		.xm_size_words = 164,
53 		.ym_size_words = 164,
54 		.zm_size_words = 164,
55 	},
56 };
57 
58 static const struct cs_dsp_mock_coeff_def mock_coeff_template = {
59 	.shortname = "Dummy Coeff",
60 	.type = WMFW_CTL_TYPE_BYTES,
61 	.mem_type = WMFW_ADSP2_YM,
62 	.flags = WMFW_CTL_FLAG_VOLATILE,
63 	.length_bytes = 4,
64 };
65 
cs_dsp_test_control_add_callback(struct cs_dsp_coeff_ctl * ctl)66 static int cs_dsp_test_control_add_callback(struct cs_dsp_coeff_ctl *ctl)
67 {
68 	struct kunit *test = kunit_get_current_test();
69 	struct cs_dsp_test *priv = test->priv;
70 	struct cs_dsp_test_local *local = priv->local;
71 
72 	local->passed_ctl[local->num_control_add] = ctl;
73 	local->num_control_add++;
74 
75 	return 0;
76 }
77 
cs_dsp_test_control_remove_callback(struct cs_dsp_coeff_ctl * ctl)78 static void cs_dsp_test_control_remove_callback(struct cs_dsp_coeff_ctl *ctl)
79 {
80 	struct kunit *test = kunit_get_current_test();
81 	struct cs_dsp_test *priv = test->priv;
82 	struct cs_dsp_test_local *local = priv->local;
83 
84 	local->passed_ctl[local->num_control_remove] = ctl;
85 	local->num_control_remove++;
86 }
87 
cs_dsp_test_pre_run_callback(struct cs_dsp * dsp)88 static int cs_dsp_test_pre_run_callback(struct cs_dsp *dsp)
89 {
90 	struct kunit *test = kunit_get_current_test();
91 	struct cs_dsp_test *priv = test->priv;
92 	struct cs_dsp_test_local *local = priv->local;
93 
94 	local->passed_dsp = dsp;
95 	local->num_pre_run++;
96 
97 	return 0;
98 }
99 
cs_dsp_test_post_run_callback(struct cs_dsp * dsp)100 static int cs_dsp_test_post_run_callback(struct cs_dsp *dsp)
101 {
102 	struct kunit *test = kunit_get_current_test();
103 	struct cs_dsp_test *priv = test->priv;
104 	struct cs_dsp_test_local *local = priv->local;
105 
106 	local->passed_dsp = dsp;
107 	local->num_post_run++;
108 
109 	return 0;
110 }
111 
cs_dsp_test_pre_stop_callback(struct cs_dsp * dsp)112 static void cs_dsp_test_pre_stop_callback(struct cs_dsp *dsp)
113 {
114 	struct kunit *test = kunit_get_current_test();
115 	struct cs_dsp_test *priv = test->priv;
116 	struct cs_dsp_test_local *local = priv->local;
117 
118 	local->passed_dsp = dsp;
119 	local->num_pre_stop++;
120 }
121 
cs_dsp_test_post_stop_callback(struct cs_dsp * dsp)122 static void cs_dsp_test_post_stop_callback(struct cs_dsp *dsp)
123 {
124 	struct kunit *test = kunit_get_current_test();
125 	struct cs_dsp_test *priv = test->priv;
126 	struct cs_dsp_test_local *local = priv->local;
127 
128 	local->passed_dsp = dsp;
129 	local->num_post_stop++;
130 }
131 
cs_dsp_test_watchdog_expired_callback(struct cs_dsp * dsp)132 static void cs_dsp_test_watchdog_expired_callback(struct cs_dsp *dsp)
133 {
134 	struct kunit *test = kunit_get_current_test();
135 	struct cs_dsp_test *priv = test->priv;
136 	struct cs_dsp_test_local *local = priv->local;
137 
138 	local->passed_dsp = dsp;
139 	local->num_watchdog_expired++;
140 }
141 
142 static const struct cs_dsp_client_ops cs_dsp_callback_test_client_ops = {
143 	.control_add = cs_dsp_test_control_add_callback,
144 	.control_remove = cs_dsp_test_control_remove_callback,
145 	.pre_run = cs_dsp_test_pre_run_callback,
146 	.post_run = cs_dsp_test_post_run_callback,
147 	.pre_stop = cs_dsp_test_pre_stop_callback,
148 	.post_stop = cs_dsp_test_post_stop_callback,
149 	.watchdog_expired = cs_dsp_test_watchdog_expired_callback,
150 };
151 
152 static const struct cs_dsp_client_ops cs_dsp_callback_test_empty_client_ops = {
153 	/* No entries */
154 };
155 
cs_dsp_test_run_stop_callbacks(struct kunit * test)156 static void cs_dsp_test_run_stop_callbacks(struct kunit *test)
157 {
158 	struct cs_dsp_test *priv = test->priv;
159 	struct cs_dsp_test_local *local = priv->local;
160 	struct firmware *wmfw;
161 
162 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
163 
164 	KUNIT_EXPECT_EQ(test,
165 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
166 			0);
167 
168 	KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
169 	KUNIT_EXPECT_EQ(test, local->num_pre_run, 1);
170 	KUNIT_EXPECT_EQ(test, local->num_post_run, 1);
171 	KUNIT_EXPECT_EQ(test, local->num_pre_stop, 0);
172 	KUNIT_EXPECT_EQ(test, local->num_post_stop, 0);
173 	KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp);
174 	local->passed_dsp = NULL;
175 
176 	cs_dsp_stop(priv->dsp);
177 	KUNIT_EXPECT_EQ(test, local->num_pre_run, 1);
178 	KUNIT_EXPECT_EQ(test, local->num_post_run, 1);
179 	KUNIT_EXPECT_EQ(test, local->num_pre_stop, 1);
180 	KUNIT_EXPECT_EQ(test, local->num_post_stop, 1);
181 	KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp);
182 	local->passed_dsp = NULL;
183 
184 	KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
185 	KUNIT_EXPECT_EQ(test, local->num_pre_run, 2);
186 	KUNIT_EXPECT_EQ(test, local->num_post_run, 2);
187 	KUNIT_EXPECT_EQ(test, local->num_pre_stop, 1);
188 	KUNIT_EXPECT_EQ(test, local->num_post_stop, 1);
189 	KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp);
190 	local->passed_dsp = NULL;
191 
192 	cs_dsp_stop(priv->dsp);
193 	KUNIT_EXPECT_EQ(test, local->num_pre_run, 2);
194 	KUNIT_EXPECT_EQ(test, local->num_post_run, 2);
195 	KUNIT_EXPECT_EQ(test, local->num_pre_stop, 2);
196 	KUNIT_EXPECT_EQ(test, local->num_post_stop, 2);
197 	KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp);
198 	local->passed_dsp = NULL;
199 }
200 
cs_dsp_test_ctl_v1_callbacks(struct kunit * test)201 static void cs_dsp_test_ctl_v1_callbacks(struct kunit *test)
202 {
203 	struct cs_dsp_test *priv = test->priv;
204 	struct cs_dsp_test_local *local = priv->local;
205 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
206 	struct cs_dsp_coeff_ctl *ctl;
207 	struct firmware *wmfw;
208 	int i;
209 
210 	/* Add a control for each memory */
211 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
212 					      cs_dsp_callbacks_test_mock_algs[0].id,
213 					      "dummyalg", NULL);
214 	def.shortname = "zm";
215 	def.mem_type = WMFW_ADSP2_ZM;
216 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
217 
218 	def.shortname = "ym";
219 	def.mem_type = WMFW_ADSP2_YM;
220 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
221 
222 	def.shortname = "xm";
223 	def.mem_type = WMFW_ADSP2_XM;
224 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
225 
226 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
227 
228 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
229 	KUNIT_EXPECT_EQ(test,
230 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
231 			0);
232 
233 	/* There should have been an add callback for each control */
234 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 3);
235 	KUNIT_EXPECT_EQ(test, local->num_control_add, 3);
236 	KUNIT_EXPECT_EQ(test, local->num_control_remove, 0);
237 
238 	i = 0;
239 	list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list)
240 		KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl);
241 
242 	/*
243 	 * Call cs_dsp_remove() and there should be a remove callback
244 	 * for each control
245 	 */
246 	memset(local->passed_ctl, 0, sizeof(local->passed_ctl));
247 	cs_dsp_remove(priv->dsp);
248 
249 	/* Prevent double cleanup */
250 	kunit_remove_action(priv->test, _cs_dsp_remove_wrapper, priv->dsp);
251 
252 	KUNIT_EXPECT_EQ(test, local->num_control_add, 3);
253 	KUNIT_EXPECT_EQ(test, local->num_control_remove, 3);
254 
255 	i = 0;
256 	list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list)
257 		KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl);
258 }
259 
cs_dsp_test_ctl_v2_callbacks(struct kunit * test)260 static void cs_dsp_test_ctl_v2_callbacks(struct kunit *test)
261 {
262 	struct cs_dsp_test *priv = test->priv;
263 	struct cs_dsp_test_local *local = priv->local;
264 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
265 	struct cs_dsp_coeff_ctl *ctl;
266 	struct firmware *wmfw;
267 	char name[2] = { };
268 	int i;
269 
270 	/* Add some controls */
271 	def.shortname = name;
272 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
273 					      cs_dsp_callbacks_test_mock_algs[0].id,
274 					      "dummyalg", NULL);
275 	for (i = 0; i < ARRAY_SIZE(local->passed_ctl); ++i) {
276 		name[0] = 'A' + i;
277 		def.offset_dsp_words = i;
278 		cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
279 	}
280 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
281 
282 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
283 	KUNIT_EXPECT_EQ(test,
284 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
285 			0);
286 
287 	/* There should have been an add callback for each control */
288 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list),
289 			ARRAY_SIZE(local->passed_ctl));
290 	KUNIT_EXPECT_EQ(test, local->num_control_add, ARRAY_SIZE(local->passed_ctl));
291 	KUNIT_EXPECT_EQ(test, local->num_control_remove, 0);
292 
293 	i = 0;
294 	list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list)
295 		KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl);
296 
297 	/*
298 	 * Call cs_dsp_remove() and there should be a remove callback
299 	 * for each control
300 	 */
301 	memset(local->passed_ctl, 0, sizeof(local->passed_ctl));
302 	cs_dsp_remove(priv->dsp);
303 
304 	/* Prevent double cleanup */
305 	kunit_remove_action(priv->test, _cs_dsp_remove_wrapper, priv->dsp);
306 
307 	KUNIT_EXPECT_EQ(test, local->num_control_add, ARRAY_SIZE(local->passed_ctl));
308 	KUNIT_EXPECT_EQ(test, local->num_control_remove, ARRAY_SIZE(local->passed_ctl));
309 
310 	i = 0;
311 	list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list)
312 		KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl);
313 }
314 
cs_dsp_test_no_callbacks(struct kunit * test)315 static void cs_dsp_test_no_callbacks(struct kunit *test)
316 {
317 	struct cs_dsp_test *priv = test->priv;
318 	struct cs_dsp_test_local *local = priv->local;
319 	struct cs_dsp_mock_coeff_def def = mock_coeff_template;
320 	struct firmware *wmfw;
321 
322 	/* Add a controls */
323 	def.shortname = "A";
324 	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
325 					      cs_dsp_callbacks_test_mock_algs[0].id,
326 					      "dummyalg", NULL);
327 	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def);
328 	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
329 
330 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
331 
332 	/* Run a sequence of ops that would invoke callbacks */
333 	KUNIT_EXPECT_EQ(test,
334 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
335 			0);
336 	KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
337 	cs_dsp_stop(priv->dsp);
338 	cs_dsp_remove(priv->dsp);
339 
340 	/* Prevent double cleanup */
341 	kunit_remove_action(priv->test, _cs_dsp_remove_wrapper, priv->dsp);
342 
343 	/* Something went very wrong if any of our callbacks were called */
344 	KUNIT_EXPECT_EQ(test, local->num_control_add, 0);
345 	KUNIT_EXPECT_EQ(test, local->num_control_remove, 0);
346 	KUNIT_EXPECT_EQ(test, local->num_pre_run, 0);
347 	KUNIT_EXPECT_EQ(test, local->num_post_run, 0);
348 	KUNIT_EXPECT_EQ(test, local->num_pre_stop, 0);
349 	KUNIT_EXPECT_EQ(test, local->num_post_stop, 0);
350 }
351 
cs_dsp_test_adsp2v2_watchdog_callback(struct kunit * test)352 static void cs_dsp_test_adsp2v2_watchdog_callback(struct kunit *test)
353 {
354 	struct cs_dsp_test *priv = test->priv;
355 	struct cs_dsp_test_local *local = priv->local;
356 	struct firmware *wmfw;
357 
358 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
359 
360 	KUNIT_EXPECT_EQ(test,
361 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
362 			0);
363 
364 	KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
365 
366 	/* Set the watchdog timeout bit */
367 	regmap_write(priv->dsp->regmap, priv->dsp->base + ADSP2_LOCK_REGION_CTRL,
368 		     ADSP2_WDT_TIMEOUT_STS_MASK);
369 
370 	/* Notify an interrupt and the watchdog callback should be called */
371 	cs_dsp_adsp2_bus_error(priv->dsp);
372 	KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 1);
373 	KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp);
374 }
375 
cs_dsp_test_adsp2v2_watchdog_no_callbacks(struct kunit * test)376 static void cs_dsp_test_adsp2v2_watchdog_no_callbacks(struct kunit *test)
377 {
378 	struct cs_dsp_test *priv = test->priv;
379 	struct cs_dsp_test_local *local = priv->local;
380 	struct firmware *wmfw;
381 
382 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
383 	KUNIT_EXPECT_EQ(test,
384 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
385 			0);
386 	KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
387 
388 	/* Set the watchdog timeout bit */
389 	regmap_write(priv->dsp->regmap, priv->dsp->base + ADSP2_LOCK_REGION_CTRL,
390 		     ADSP2_WDT_TIMEOUT_STS_MASK);
391 
392 	/* Notify an interrupt, which will look for a watchdog callback */
393 	cs_dsp_adsp2_bus_error(priv->dsp);
394 	KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 0);
395 }
396 
cs_dsp_test_halo_watchdog_callback(struct kunit * test)397 static void cs_dsp_test_halo_watchdog_callback(struct kunit *test)
398 {
399 	struct cs_dsp_test *priv = test->priv;
400 	struct cs_dsp_test_local *local = priv->local;
401 	struct firmware *wmfw;
402 
403 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
404 
405 	KUNIT_EXPECT_EQ(test,
406 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
407 			0);
408 
409 	KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
410 
411 	/* Notify an interrupt and the watchdog callback should be called */
412 	cs_dsp_halo_wdt_expire(priv->dsp);
413 	KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 1);
414 	KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp);
415 }
416 
cs_dsp_test_halo_watchdog_no_callbacks(struct kunit * test)417 static void cs_dsp_test_halo_watchdog_no_callbacks(struct kunit *test)
418 {
419 	struct cs_dsp_test *priv = test->priv;
420 	struct cs_dsp_test_local *local = priv->local;
421 	struct firmware *wmfw;
422 
423 	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
424 	KUNIT_EXPECT_EQ(test,
425 			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
426 			0);
427 	KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
428 
429 	/* Notify an interrupt, which will look for a watchdog callback */
430 	cs_dsp_halo_wdt_expire(priv->dsp);
431 	KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 0);
432 }
433 
cs_dsp_callbacks_test_common_init(struct kunit * test,struct cs_dsp * dsp,int wmfw_version)434 static int cs_dsp_callbacks_test_common_init(struct kunit *test, struct cs_dsp *dsp,
435 					     int wmfw_version)
436 {
437 	const struct cs_dsp_callbacks_test_param *param = test->param_value;
438 	struct cs_dsp_test *priv;
439 	struct cs_dsp_test_local *local;
440 	struct device *test_dev;
441 	struct cs_dsp_mock_xm_header *xm_header;
442 	int ret;
443 
444 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
445 	if (!priv)
446 		return -ENOMEM;
447 
448 	local = kunit_kzalloc(test, sizeof(struct cs_dsp_test_local), GFP_KERNEL);
449 	if (!local)
450 		return -ENOMEM;
451 
452 	priv->test = test;
453 	priv->dsp = dsp;
454 	test->priv = priv;
455 	priv->local = local;
456 
457 	/* Create dummy struct device */
458 	test_dev = kunit_device_register(test, "cs_dsp_test_drv");
459 	if (IS_ERR(test_dev))
460 		return PTR_ERR(test_dev);
461 
462 	dsp->dev = get_device(test_dev);
463 	if (!dsp->dev)
464 		return -ENODEV;
465 
466 	ret = kunit_add_action_or_reset(test, _put_device_wrapper, dsp->dev);
467 	if (ret)
468 		return ret;
469 
470 	dev_set_drvdata(dsp->dev, priv);
471 
472 	/* Allocate regmap */
473 	ret = cs_dsp_mock_regmap_init(priv);
474 	if (ret)
475 		return ret;
476 
477 	/*
478 	 * There must always be a XM header with at least 1 algorithm,
479 	 * so create a dummy one and pre-populate XM so the wmfw doesn't
480 	 * have to contain an XM blob.
481 	 */
482 	xm_header = cs_dsp_create_mock_xm_header(priv,
483 						 cs_dsp_callbacks_test_mock_algs,
484 						 ARRAY_SIZE(cs_dsp_callbacks_test_mock_algs));
485 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xm_header);
486 	cs_dsp_mock_xm_header_write_to_regmap(xm_header);
487 
488 	local->wmfw_builder = cs_dsp_mock_wmfw_init(priv, wmfw_version);
489 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->wmfw_builder);
490 
491 	/* Add dummy XM header payload to wmfw */
492 	cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
493 					WMFW_ADSP2_XM, 0,
494 					xm_header->blob_data,
495 					xm_header->blob_size_bytes);
496 
497 	/* Init cs_dsp */
498 	dsp->client_ops = param->ops;
499 
500 	switch (dsp->type) {
501 	case WMFW_ADSP2:
502 		ret = cs_dsp_adsp2_init(dsp);
503 		break;
504 	case WMFW_HALO:
505 		ret = cs_dsp_halo_init(dsp);
506 		break;
507 	default:
508 		KUNIT_FAIL(test, "Untested DSP type %d\n", dsp->type);
509 		return -EINVAL;
510 	}
511 
512 	if (ret)
513 		return ret;
514 
515 	/* Automatically call cs_dsp_remove() when test case ends */
516 	return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
517 }
518 
cs_dsp_callbacks_test_halo_init(struct kunit * test)519 static int cs_dsp_callbacks_test_halo_init(struct kunit *test)
520 {
521 	struct cs_dsp *dsp;
522 
523 	/* Fill in cs_dsp and initialize */
524 	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
525 	if (!dsp)
526 		return -ENOMEM;
527 
528 	dsp->num = 1;
529 	dsp->type = WMFW_HALO;
530 	dsp->mem = cs_dsp_mock_halo_dsp1_regions;
531 	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_halo_dsp1_region_sizes);
532 	dsp->base = cs_dsp_mock_halo_core_base;
533 	dsp->base_sysinfo = cs_dsp_mock_halo_sysinfo_base;
534 
535 	return cs_dsp_callbacks_test_common_init(test, dsp, 3);
536 }
537 
cs_dsp_callbacks_test_adsp2_32bit_init(struct kunit * test,int rev)538 static int cs_dsp_callbacks_test_adsp2_32bit_init(struct kunit *test, int rev)
539 {
540 	struct cs_dsp *dsp;
541 
542 	/* Fill in cs_dsp and initialize */
543 	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
544 	if (!dsp)
545 		return -ENOMEM;
546 
547 	dsp->num = 1;
548 	dsp->type = WMFW_ADSP2;
549 	dsp->rev = rev;
550 	dsp->mem = cs_dsp_mock_adsp2_32bit_dsp1_regions;
551 	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_32bit_dsp1_region_sizes);
552 	dsp->base = cs_dsp_mock_adsp2_32bit_sysbase;
553 
554 	return cs_dsp_callbacks_test_common_init(test, dsp, 2);
555 }
556 
cs_dsp_callbacks_test_adsp2v2_32bit_init(struct kunit * test)557 static int cs_dsp_callbacks_test_adsp2v2_32bit_init(struct kunit *test)
558 {
559 	return cs_dsp_callbacks_test_adsp2_32bit_init(test, 2);
560 }
561 
cs_dsp_callbacks_test_adsp2v1_32bit_init(struct kunit * test)562 static int cs_dsp_callbacks_test_adsp2v1_32bit_init(struct kunit *test)
563 {
564 	return cs_dsp_callbacks_test_adsp2_32bit_init(test, 1);
565 }
566 
cs_dsp_callbacks_test_adsp2_16bit_init(struct kunit * test)567 static int cs_dsp_callbacks_test_adsp2_16bit_init(struct kunit *test)
568 {
569 	struct cs_dsp *dsp;
570 
571 	/* Fill in cs_dsp and initialize */
572 	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
573 	if (!dsp)
574 		return -ENOMEM;
575 
576 	dsp->num = 1;
577 	dsp->type = WMFW_ADSP2;
578 	dsp->rev = 0;
579 	dsp->mem = cs_dsp_mock_adsp2_16bit_dsp1_regions;
580 	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_16bit_dsp1_region_sizes);
581 	dsp->base = cs_dsp_mock_adsp2_16bit_sysbase;
582 
583 	return cs_dsp_callbacks_test_common_init(test, dsp, 1);
584 }
585 
cs_dsp_callbacks_param_desc(const struct cs_dsp_callbacks_test_param * param,char * desc)586 static void cs_dsp_callbacks_param_desc(const struct cs_dsp_callbacks_test_param *param,
587 					char *desc)
588 {
589 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", param->case_name);
590 }
591 
592 /* Parameterize on different client callback ops tables */
593 static const struct cs_dsp_callbacks_test_param cs_dsp_callbacks_ops_cases[] = {
594 	{ .ops =  &cs_dsp_callback_test_client_ops, .case_name = "all ops" },
595 };
596 
597 KUNIT_ARRAY_PARAM(cs_dsp_callbacks_ops,
598 		  cs_dsp_callbacks_ops_cases,
599 		  cs_dsp_callbacks_param_desc);
600 
601 static const struct cs_dsp_callbacks_test_param cs_dsp_no_callbacks_cases[] = {
602 	{ .ops =  &cs_dsp_callback_test_empty_client_ops, .case_name = "empty ops" },
603 };
604 
605 KUNIT_ARRAY_PARAM(cs_dsp_no_callbacks,
606 		  cs_dsp_no_callbacks_cases,
607 		  cs_dsp_callbacks_param_desc);
608 
609 static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv1_test_cases[] = {
610 	KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params),
611 	KUNIT_CASE_PARAM(cs_dsp_test_ctl_v1_callbacks, cs_dsp_callbacks_ops_gen_params),
612 	KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params),
613 
614 	{ } /* terminator */
615 };
616 
617 static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv2_test_cases[] = {
618 	KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params),
619 	KUNIT_CASE_PARAM(cs_dsp_test_ctl_v2_callbacks, cs_dsp_callbacks_ops_gen_params),
620 	KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params),
621 
622 	{ } /* terminator */
623 };
624 
625 static struct kunit_case cs_dsp_callbacks_halo_test_cases[] = {
626 	KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params),
627 	KUNIT_CASE_PARAM(cs_dsp_test_ctl_v2_callbacks, cs_dsp_callbacks_ops_gen_params),
628 	KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params),
629 
630 	{ } /* terminator */
631 };
632 
633 static struct kunit_case cs_dsp_watchdog_adsp2v2_test_cases[] = {
634 	KUNIT_CASE_PARAM(cs_dsp_test_adsp2v2_watchdog_callback, cs_dsp_callbacks_ops_gen_params),
635 	KUNIT_CASE_PARAM(cs_dsp_test_adsp2v2_watchdog_no_callbacks, cs_dsp_no_callbacks_gen_params),
636 
637 	{ } /* terminator */
638 };
639 
640 static struct kunit_case cs_dsp_watchdog_halo_test_cases[] = {
641 	KUNIT_CASE_PARAM(cs_dsp_test_halo_watchdog_callback, cs_dsp_callbacks_ops_gen_params),
642 	KUNIT_CASE_PARAM(cs_dsp_test_halo_watchdog_no_callbacks, cs_dsp_no_callbacks_gen_params),
643 
644 	{ } /* terminator */
645 };
646 
647 static struct kunit_suite cs_dsp_callbacks_test_halo = {
648 	.name = "cs_dsp_callbacks_halo",
649 	.init = cs_dsp_callbacks_test_halo_init,
650 	.test_cases = cs_dsp_callbacks_halo_test_cases,
651 };
652 
653 static struct kunit_suite cs_dsp_callbacks_test_adsp2v2_32bit = {
654 	.name = "cs_dsp_callbacks_adsp2v2_32bit_wmfwv2",
655 	.init = cs_dsp_callbacks_test_adsp2v2_32bit_init,
656 	.test_cases = cs_dsp_callbacks_adsp2_wmfwv2_test_cases,
657 };
658 
659 static struct kunit_suite cs_dsp_callbacks_test_adsp2v1_32bit = {
660 	.name = "cs_dsp_callbacks_adsp2v1_32bit_wmfwv2",
661 	.init = cs_dsp_callbacks_test_adsp2v1_32bit_init,
662 	.test_cases = cs_dsp_callbacks_adsp2_wmfwv2_test_cases,
663 };
664 
665 static struct kunit_suite cs_dsp_callbacks_test_adsp2_16bit = {
666 	.name = "cs_dsp_callbacks_adsp2_16bit_wmfwv1",
667 	.init = cs_dsp_callbacks_test_adsp2_16bit_init,
668 	.test_cases = cs_dsp_callbacks_adsp2_wmfwv1_test_cases,
669 };
670 
671 static struct kunit_suite cs_dsp_watchdog_test_adsp2v2_32bit = {
672 	.name = "cs_dsp_watchdog_adsp2v2_32bit",
673 	.init = cs_dsp_callbacks_test_adsp2v2_32bit_init,
674 	.test_cases = cs_dsp_watchdog_adsp2v2_test_cases,
675 };
676 
677 static struct kunit_suite cs_dsp_watchdog_test_halo_32bit = {
678 	.name = "cs_dsp_watchdog_halo",
679 	.init = cs_dsp_callbacks_test_halo_init,
680 	.test_cases = cs_dsp_watchdog_halo_test_cases,
681 };
682 
683 kunit_test_suites(&cs_dsp_callbacks_test_halo,
684 		  &cs_dsp_callbacks_test_adsp2v2_32bit,
685 		  &cs_dsp_callbacks_test_adsp2v1_32bit,
686 		  &cs_dsp_callbacks_test_adsp2_16bit,
687 		  &cs_dsp_watchdog_test_adsp2v2_32bit,
688 		  &cs_dsp_watchdog_test_halo_32bit);
689