1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // KUnit test for the Cirrus common amplifier library.
4 //
5 // Copyright (C) 2024 Cirrus Logic, Inc. and
6 // Cirrus Logic International Semiconductor Ltd.
7
8 #include <kunit/resource.h>
9 #include <kunit/test.h>
10 #include <kunit/static_stub.h>
11 #include <linux/device/faux.h>
12 #include <linux/firmware/cirrus/cs_dsp.h>
13 #include <linux/firmware/cirrus/wmfw.h>
14 #include <linux/gpio/driver.h>
15 #include <linux/list.h>
16 #include <linux/module.h>
17 #include <linux/overflow.h>
18 #include <linux/platform_device.h>
19 #include <linux/random.h>
20 #include <sound/cs-amp-lib.h>
21
22 KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
23 struct faux_device *)
24
25 struct cs_amp_lib_test_priv {
26 struct faux_device *amp_dev;
27
28 struct cirrus_amp_efi_data *cal_blob;
29 struct list_head ctl_write_list;
30 };
31
32 struct cs_amp_lib_test_ctl_write_entry {
33 struct list_head list;
34 unsigned int value;
35 char name[16];
36 };
37
38 struct cs_amp_lib_test_param {
39 int num_amps;
40 int amp_index;
41 };
42
cs_amp_lib_test_init_dummy_cal_blob(struct kunit * test,int num_amps)43 static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps)
44 {
45 struct cs_amp_lib_test_priv *priv = test->priv;
46 unsigned int blob_size;
47 int i;
48
49 blob_size = struct_size(priv->cal_blob, data, num_amps);
50
51 priv->cal_blob = kunit_kzalloc(test, blob_size, GFP_KERNEL);
52 KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
53
54 priv->cal_blob->size = blob_size;
55 priv->cal_blob->count = num_amps;
56
57 get_random_bytes(priv->cal_blob->data, flex_array_size(priv->cal_blob, data, num_amps));
58
59 /* Ensure all timestamps are non-zero to mark the entry valid. */
60 for (i = 0; i < num_amps; i++)
61 priv->cal_blob->data[i].calTime[0] |= 1;
62
63 /* Ensure that all UIDs are non-zero and unique. */
64 for (i = 0; i < num_amps; i++)
65 *(u8 *)&priv->cal_blob->data[i].calTarget[0] = i + 1;
66 }
67
cs_amp_lib_test_get_target_uid(struct kunit * test)68 static u64 cs_amp_lib_test_get_target_uid(struct kunit *test)
69 {
70 struct cs_amp_lib_test_priv *priv = test->priv;
71 const struct cs_amp_lib_test_param *param = test->param_value;
72 u64 uid;
73
74 uid = priv->cal_blob->data[param->amp_index].calTarget[1];
75 uid <<= 32;
76 uid |= priv->cal_blob->data[param->amp_index].calTarget[0];
77
78 return uid;
79 }
80
81 /* Redirected get_efi_variable to simulate that the file is too short */
cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)82 static efi_status_t cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t *name,
83 efi_guid_t *guid,
84 unsigned long *size,
85 void *buf)
86 {
87 if (!buf) {
88 *size = offsetof(struct cirrus_amp_efi_data, data) - 1;
89 return EFI_BUFFER_TOO_SMALL;
90 }
91
92 return EFI_NOT_FOUND;
93 }
94
95 /* Should return -EOVERFLOW if the header is larger than the EFI data */
cs_amp_lib_test_cal_data_too_short_test(struct kunit * test)96 static void cs_amp_lib_test_cal_data_too_short_test(struct kunit *test)
97 {
98 struct cs_amp_lib_test_priv *priv = test->priv;
99 struct cirrus_amp_cal_data result_data;
100 int ret;
101
102 /* Redirect calls to get EFI data */
103 kunit_activate_static_stub(test,
104 cs_amp_test_hooks->get_efi_variable,
105 cs_amp_lib_test_get_efi_variable_nohead);
106
107 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
108 KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
109
110 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
111 }
112
113 /* Redirected get_efi_variable to simulate that the count is larger than the file */
cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)114 static efi_status_t cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t *name,
115 efi_guid_t *guid,
116 unsigned long *size,
117 void *buf)
118 {
119 struct kunit *test = kunit_get_current_test();
120 struct cs_amp_lib_test_priv *priv = test->priv;
121
122 if (!buf) {
123 /*
124 * Return a size that is shorter than required for the
125 * declared number of entries.
126 */
127 *size = priv->cal_blob->size - 1;
128 return EFI_BUFFER_TOO_SMALL;
129 }
130
131 memcpy(buf, priv->cal_blob, priv->cal_blob->size - 1);
132
133 return EFI_SUCCESS;
134 }
135
136 /* Should return -EOVERFLOW if the entry count is larger than the EFI data */
cs_amp_lib_test_cal_count_too_big_test(struct kunit * test)137 static void cs_amp_lib_test_cal_count_too_big_test(struct kunit *test)
138 {
139 struct cs_amp_lib_test_priv *priv = test->priv;
140 struct cirrus_amp_cal_data result_data;
141 int ret;
142
143 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
144
145 /* Redirect calls to get EFI data */
146 kunit_activate_static_stub(test,
147 cs_amp_test_hooks->get_efi_variable,
148 cs_amp_lib_test_get_efi_variable_bad_count);
149
150 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
151 KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
152
153 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
154 }
155
156 /* Redirected get_efi_variable to simulate that the variable not found */
cs_amp_lib_test_get_efi_variable_none(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)157 static efi_status_t cs_amp_lib_test_get_efi_variable_none(efi_char16_t *name,
158 efi_guid_t *guid,
159 unsigned long *size,
160 void *buf)
161 {
162 return EFI_NOT_FOUND;
163 }
164
165 /* If EFI doesn't contain a cal data variable the result should be -ENOENT */
cs_amp_lib_test_no_cal_data_test(struct kunit * test)166 static void cs_amp_lib_test_no_cal_data_test(struct kunit *test)
167 {
168 struct cs_amp_lib_test_priv *priv = test->priv;
169 struct cirrus_amp_cal_data result_data;
170 int ret;
171
172 /* Redirect calls to get EFI data */
173 kunit_activate_static_stub(test,
174 cs_amp_test_hooks->get_efi_variable,
175 cs_amp_lib_test_get_efi_variable_none);
176
177 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
178 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
179
180 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
181 }
182
183 /* Redirected get_efi_variable to simulate reading a cal data blob */
cs_amp_lib_test_get_efi_variable(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)184 static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name,
185 efi_guid_t *guid,
186 unsigned long *size,
187 void *buf)
188 {
189 static const efi_char16_t expected_name[] = L"CirrusSmartAmpCalibrationData";
190 static const efi_guid_t expected_guid =
191 EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
192 struct kunit *test = kunit_get_current_test();
193 struct cs_amp_lib_test_priv *priv = test->priv;
194
195 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
196 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
197 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size);
198
199 KUNIT_EXPECT_MEMEQ(test, name, expected_name, sizeof(expected_name));
200 KUNIT_EXPECT_MEMEQ(test, guid, &expected_guid, sizeof(expected_guid));
201
202 if (!buf) {
203 *size = priv->cal_blob->size;
204 return EFI_BUFFER_TOO_SMALL;
205 }
206
207 KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small");
208
209 memcpy(buf, priv->cal_blob, priv->cal_blob->size);
210
211 return EFI_SUCCESS;
212 }
213
214 /* Get cal data block for a given amp, matched by target UID. */
cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit * test)215 static void cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit *test)
216 {
217 struct cs_amp_lib_test_priv *priv = test->priv;
218 const struct cs_amp_lib_test_param *param = test->param_value;
219 struct cirrus_amp_cal_data result_data;
220 u64 target_uid;
221 int ret;
222
223 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
224
225 /* Redirect calls to get EFI data */
226 kunit_activate_static_stub(test,
227 cs_amp_test_hooks->get_efi_variable,
228 cs_amp_lib_test_get_efi_variable);
229
230 target_uid = cs_amp_lib_test_get_target_uid(test);
231 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid, -1, &result_data);
232 KUNIT_EXPECT_EQ(test, ret, 0);
233
234 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
235
236 KUNIT_EXPECT_EQ(test, result_data.calTarget[0], target_uid & 0xFFFFFFFFULL);
237 KUNIT_EXPECT_EQ(test, result_data.calTarget[1], target_uid >> 32);
238 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
239 priv->cal_blob->data[param->amp_index].calTime[0]);
240 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
241 priv->cal_blob->data[param->amp_index].calTime[1]);
242 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
243 priv->cal_blob->data[param->amp_index].calAmbient);
244 KUNIT_EXPECT_EQ(test, result_data.calStatus,
245 priv->cal_blob->data[param->amp_index].calStatus);
246 KUNIT_EXPECT_EQ(test, result_data.calR,
247 priv->cal_blob->data[param->amp_index].calR);
248 }
249
250 /* Get cal data block for a given amp index without checking target UID. */
cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit * test)251 static void cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit *test)
252 {
253 struct cs_amp_lib_test_priv *priv = test->priv;
254 const struct cs_amp_lib_test_param *param = test->param_value;
255 struct cirrus_amp_cal_data result_data;
256 int ret;
257
258 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
259
260 /* Redirect calls to get EFI data */
261 kunit_activate_static_stub(test,
262 cs_amp_test_hooks->get_efi_variable,
263 cs_amp_lib_test_get_efi_variable);
264
265 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0,
266 param->amp_index, &result_data);
267 KUNIT_EXPECT_EQ(test, ret, 0);
268
269 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
270
271 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
272 priv->cal_blob->data[param->amp_index].calTime[0]);
273 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
274 priv->cal_blob->data[param->amp_index].calTime[1]);
275 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
276 priv->cal_blob->data[param->amp_index].calAmbient);
277 KUNIT_EXPECT_EQ(test, result_data.calStatus,
278 priv->cal_blob->data[param->amp_index].calStatus);
279 KUNIT_EXPECT_EQ(test, result_data.calR,
280 priv->cal_blob->data[param->amp_index].calR);
281 }
282
283 /* Get cal data block for a given amp index with checked target UID. */
cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit * test)284 static void cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit *test)
285 {
286 struct cs_amp_lib_test_priv *priv = test->priv;
287 const struct cs_amp_lib_test_param *param = test->param_value;
288 struct cirrus_amp_cal_data result_data;
289 u64 target_uid;
290 int ret;
291
292 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
293
294 /* Redirect calls to get EFI data */
295 kunit_activate_static_stub(test,
296 cs_amp_test_hooks->get_efi_variable,
297 cs_amp_lib_test_get_efi_variable);
298
299 target_uid = cs_amp_lib_test_get_target_uid(test);
300 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid,
301 param->amp_index, &result_data);
302 KUNIT_EXPECT_EQ(test, ret, 0);
303
304 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
305
306 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
307 priv->cal_blob->data[param->amp_index].calTime[0]);
308 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
309 priv->cal_blob->data[param->amp_index].calTime[1]);
310 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
311 priv->cal_blob->data[param->amp_index].calAmbient);
312 KUNIT_EXPECT_EQ(test, result_data.calStatus,
313 priv->cal_blob->data[param->amp_index].calStatus);
314 KUNIT_EXPECT_EQ(test, result_data.calR,
315 priv->cal_blob->data[param->amp_index].calR);
316 }
317
318 /*
319 * Get cal data block for a given amp index with checked target UID.
320 * The UID does not match so the result should be -ENOENT.
321 */
cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit * test)322 static void cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit *test)
323 {
324 struct cs_amp_lib_test_priv *priv = test->priv;
325 const struct cs_amp_lib_test_param *param = test->param_value;
326 struct cirrus_amp_cal_data result_data;
327 u64 target_uid;
328 int ret;
329
330 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
331
332 /* Redirect calls to get EFI data */
333 kunit_activate_static_stub(test,
334 cs_amp_test_hooks->get_efi_variable,
335 cs_amp_lib_test_get_efi_variable);
336
337 /* Get a target UID that won't match the entry */
338 target_uid = ~cs_amp_lib_test_get_target_uid(test);
339 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid,
340 param->amp_index, &result_data);
341 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
342
343 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
344 }
345
346 /*
347 * Get cal data block for a given amp, where the cal data does not
348 * specify calTarget so the lookup falls back to using the index
349 */
cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit * test)350 static void cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit *test)
351 {
352 struct cs_amp_lib_test_priv *priv = test->priv;
353 const struct cs_amp_lib_test_param *param = test->param_value;
354 struct cirrus_amp_cal_data result_data;
355 static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
356 int i, ret;
357
358 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
359
360 /* Make all the target values zero so they are ignored */
361 for (i = 0; i < priv->cal_blob->count; ++i) {
362 priv->cal_blob->data[i].calTarget[0] = 0;
363 priv->cal_blob->data[i].calTarget[1] = 0;
364 }
365
366 /* Redirect calls to get EFI data */
367 kunit_activate_static_stub(test,
368 cs_amp_test_hooks->get_efi_variable,
369 cs_amp_lib_test_get_efi_variable);
370
371 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid,
372 param->amp_index, &result_data);
373 KUNIT_EXPECT_EQ(test, ret, 0);
374
375 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
376
377 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
378 priv->cal_blob->data[param->amp_index].calTime[0]);
379 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
380 priv->cal_blob->data[param->amp_index].calTime[1]);
381 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
382 priv->cal_blob->data[param->amp_index].calAmbient);
383 KUNIT_EXPECT_EQ(test, result_data.calStatus,
384 priv->cal_blob->data[param->amp_index].calStatus);
385 KUNIT_EXPECT_EQ(test, result_data.calR,
386 priv->cal_blob->data[param->amp_index].calR);
387 }
388
389 /*
390 * If the target UID isn't present in the cal data, and there isn't an
391 * index to fall back do, the result should be -ENOENT.
392 */
cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit * test)393 static void cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit *test)
394 {
395 struct cs_amp_lib_test_priv *priv = test->priv;
396 struct cirrus_amp_cal_data result_data;
397 static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
398 int i, ret;
399
400 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
401
402 /* Make all the target values != bad_target_uid */
403 for (i = 0; i < priv->cal_blob->count; ++i) {
404 priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
405 priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
406 }
407
408 /* Redirect calls to get EFI data */
409 kunit_activate_static_stub(test,
410 cs_amp_test_hooks->get_efi_variable,
411 cs_amp_lib_test_get_efi_variable);
412
413 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, -1,
414 &result_data);
415 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
416
417 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
418 }
419
420 /*
421 * If the target UID isn't present in the cal data, and the index is
422 * out of range, the result should be -ENOENT.
423 */
cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit * test)424 static void cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit *test)
425 {
426 struct cs_amp_lib_test_priv *priv = test->priv;
427 struct cirrus_amp_cal_data result_data;
428 static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
429 int i, ret;
430
431 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
432
433 /* Make all the target values != bad_target_uid */
434 for (i = 0; i < priv->cal_blob->count; ++i) {
435 priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
436 priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
437 }
438
439 /* Redirect calls to get EFI data */
440 kunit_activate_static_stub(test,
441 cs_amp_test_hooks->get_efi_variable,
442 cs_amp_lib_test_get_efi_variable);
443
444 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, 99,
445 &result_data);
446 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
447
448 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
449 }
450
451 /*
452 * If the target UID isn't given, and the index is out of range, the
453 * result should be -ENOENT.
454 */
cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit * test)455 static void cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit *test)
456 {
457 struct cs_amp_lib_test_priv *priv = test->priv;
458 struct cirrus_amp_cal_data result_data;
459 int ret;
460
461 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
462
463 /* Redirect calls to get EFI data */
464 kunit_activate_static_stub(test,
465 cs_amp_test_hooks->get_efi_variable,
466 cs_amp_lib_test_get_efi_variable);
467
468 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 99, &result_data);
469 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
470
471 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
472 }
473
474 /* If neither the target UID or the index is given the result should be -ENOENT. */
cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit * test)475 static void cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit *test)
476 {
477 struct cs_amp_lib_test_priv *priv = test->priv;
478 struct cirrus_amp_cal_data result_data;
479 int ret;
480
481 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
482
483 /* Redirect calls to get EFI data */
484 kunit_activate_static_stub(test,
485 cs_amp_test_hooks->get_efi_variable,
486 cs_amp_lib_test_get_efi_variable);
487
488 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data);
489 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
490
491 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
492 }
493
494 /*
495 * If the UID is passed as 0 this must not match an entry with an
496 * unpopulated calTarget
497 */
cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit * test)498 static void cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit *test)
499 {
500 struct cs_amp_lib_test_priv *priv = test->priv;
501 struct cirrus_amp_cal_data result_data;
502 int i, ret;
503
504 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
505
506 /* Make all the target values zero so they are ignored */
507 for (i = 0; i < priv->cal_blob->count; ++i) {
508 priv->cal_blob->data[i].calTarget[0] = 0;
509 priv->cal_blob->data[i].calTarget[1] = 0;
510 }
511
512 /* Redirect calls to get EFI data */
513 kunit_activate_static_stub(test,
514 cs_amp_test_hooks->get_efi_variable,
515 cs_amp_lib_test_get_efi_variable);
516
517 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data);
518 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
519
520 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
521 }
522
523 /*
524 * If an entry has a timestamp of 0 it should be ignored even if it has
525 * a matching target UID.
526 */
cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit * test)527 static void cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit *test)
528 {
529 struct cs_amp_lib_test_priv *priv = test->priv;
530 struct cirrus_amp_cal_data result_data;
531 u64 uid;
532
533 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
534
535 /* Mark the 3rd entry invalid by zeroing calTime */
536 priv->cal_blob->data[2].calTime[0] = 0;
537 priv->cal_blob->data[2].calTime[1] = 0;
538
539 /* Get the UID value of the 3rd entry */
540 uid = priv->cal_blob->data[2].calTarget[1];
541 uid <<= 32;
542 uid |= priv->cal_blob->data[2].calTarget[0];
543
544 /* Redirect calls to get EFI data */
545 kunit_activate_static_stub(test,
546 cs_amp_test_hooks->get_efi_variable,
547 cs_amp_lib_test_get_efi_variable);
548
549 /* Lookup by UID should not find it */
550 KUNIT_EXPECT_EQ(test,
551 cs_amp_get_efi_calibration_data(&priv->amp_dev->dev,
552 uid, -1,
553 &result_data),
554 -ENOENT);
555
556 /* Get by index should ignore it */
557 KUNIT_EXPECT_EQ(test,
558 cs_amp_get_efi_calibration_data(&priv->amp_dev->dev,
559 0, 2,
560 &result_data),
561 -ENOENT);
562
563 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
564 }
565
566 static const struct cirrus_amp_cal_controls cs_amp_lib_test_calibration_controls = {
567 .alg_id = 0x9f210,
568 .mem_region = WMFW_ADSP2_YM,
569 .ambient = "CAL_AMBIENT",
570 .calr = "CAL_R",
571 .status = "CAL_STATUS",
572 .checksum = "CAL_CHECKSUM",
573 };
574
cs_amp_lib_test_write_cal_coeff(struct cs_dsp * dsp,const struct cirrus_amp_cal_controls * controls,const char * ctl_name,u32 val)575 static int cs_amp_lib_test_write_cal_coeff(struct cs_dsp *dsp,
576 const struct cirrus_amp_cal_controls *controls,
577 const char *ctl_name, u32 val)
578 {
579 struct kunit *test = kunit_get_current_test();
580 struct cs_amp_lib_test_priv *priv = test->priv;
581 struct cs_amp_lib_test_ctl_write_entry *entry;
582
583 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctl_name);
584 KUNIT_EXPECT_PTR_EQ(test, controls, &cs_amp_lib_test_calibration_controls);
585
586 entry = kunit_kzalloc(test, sizeof(*entry), GFP_KERNEL);
587 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, entry);
588
589 INIT_LIST_HEAD(&entry->list);
590 strscpy(entry->name, ctl_name, sizeof(entry->name));
591 entry->value = val;
592
593 list_add_tail(&entry->list, &priv->ctl_write_list);
594
595 return 0;
596 }
597
cs_amp_lib_test_write_cal_data_test(struct kunit * test)598 static void cs_amp_lib_test_write_cal_data_test(struct kunit *test)
599 {
600 struct cs_amp_lib_test_priv *priv = test->priv;
601 struct cs_amp_lib_test_ctl_write_entry *entry;
602 struct cirrus_amp_cal_data data;
603 struct cs_dsp *dsp;
604 int ret;
605
606 dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
607 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp);
608 dsp->dev = &priv->amp_dev->dev;
609
610 get_random_bytes(&data, sizeof(data));
611
612 /* Redirect calls to write firmware controls */
613 kunit_activate_static_stub(test,
614 cs_amp_test_hooks->write_cal_coeff,
615 cs_amp_lib_test_write_cal_coeff);
616
617 ret = cs_amp_write_cal_coeffs(dsp, &cs_amp_lib_test_calibration_controls, &data);
618 KUNIT_EXPECT_EQ(test, ret, 0);
619
620 kunit_deactivate_static_stub(test, cs_amp_test_hooks->write_cal_coeff);
621
622 KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->ctl_write_list), 4);
623
624 /* Checksum control must be written last */
625 entry = list_last_entry(&priv->ctl_write_list, typeof(*entry), list);
626 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.checksum);
627 KUNIT_EXPECT_EQ(test, entry->value, data.calR + 1);
628 list_del(&entry->list);
629
630 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
631 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.ambient);
632 KUNIT_EXPECT_EQ(test, entry->value, data.calAmbient);
633 list_del(&entry->list);
634
635 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
636 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.calr);
637 KUNIT_EXPECT_EQ(test, entry->value, data.calR);
638 list_del(&entry->list);
639
640 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
641 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.status);
642 KUNIT_EXPECT_EQ(test, entry->value, data.calStatus);
643 }
644
cs_amp_lib_test_case_init(struct kunit * test)645 static int cs_amp_lib_test_case_init(struct kunit *test)
646 {
647 struct cs_amp_lib_test_priv *priv;
648
649 KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks);
650
651 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
652 if (!priv)
653 return -ENOMEM;
654
655 test->priv = priv;
656 INIT_LIST_HEAD(&priv->ctl_write_list);
657
658 /* Create dummy amp driver dev */
659 priv->amp_dev = faux_device_create("cs_amp_lib_test_drv", NULL, NULL);
660 KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev);
661 KUNIT_ASSERT_EQ(test, 0,
662 kunit_add_action_or_reset(test,
663 faux_device_destroy_wrapper,
664 priv->amp_dev));
665
666 return 0;
667 }
668
669 static const struct cs_amp_lib_test_param cs_amp_lib_test_get_cal_param_cases[] = {
670 { .num_amps = 2, .amp_index = 0 },
671 { .num_amps = 2, .amp_index = 1 },
672
673 { .num_amps = 3, .amp_index = 0 },
674 { .num_amps = 3, .amp_index = 1 },
675 { .num_amps = 3, .amp_index = 2 },
676
677 { .num_amps = 4, .amp_index = 0 },
678 { .num_amps = 4, .amp_index = 1 },
679 { .num_amps = 4, .amp_index = 2 },
680 { .num_amps = 4, .amp_index = 3 },
681
682 { .num_amps = 5, .amp_index = 0 },
683 { .num_amps = 5, .amp_index = 1 },
684 { .num_amps = 5, .amp_index = 2 },
685 { .num_amps = 5, .amp_index = 3 },
686 { .num_amps = 5, .amp_index = 4 },
687
688 { .num_amps = 6, .amp_index = 0 },
689 { .num_amps = 6, .amp_index = 1 },
690 { .num_amps = 6, .amp_index = 2 },
691 { .num_amps = 6, .amp_index = 3 },
692 { .num_amps = 6, .amp_index = 4 },
693 { .num_amps = 6, .amp_index = 5 },
694
695 { .num_amps = 8, .amp_index = 0 },
696 { .num_amps = 8, .amp_index = 1 },
697 { .num_amps = 8, .amp_index = 2 },
698 { .num_amps = 8, .amp_index = 3 },
699 { .num_amps = 8, .amp_index = 4 },
700 { .num_amps = 8, .amp_index = 5 },
701 { .num_amps = 8, .amp_index = 6 },
702 { .num_amps = 8, .amp_index = 7 },
703 };
704
cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param * param,char * desc)705 static void cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param *param,
706 char *desc)
707 {
708 snprintf(desc, KUNIT_PARAM_DESC_SIZE, "num_amps:%d amp_index:%d",
709 param->num_amps, param->amp_index);
710 }
711
712 KUNIT_ARRAY_PARAM(cs_amp_lib_test_get_cal, cs_amp_lib_test_get_cal_param_cases,
713 cs_amp_lib_test_get_cal_param_desc);
714
715 static struct kunit_case cs_amp_lib_test_cases[] = {
716 /* Tests for getting calibration data from EFI */
717 KUNIT_CASE(cs_amp_lib_test_cal_data_too_short_test),
718 KUNIT_CASE(cs_amp_lib_test_cal_count_too_big_test),
719 KUNIT_CASE(cs_amp_lib_test_no_cal_data_test),
720 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test),
721 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test),
722 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test),
723 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_no_index_test),
724 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_zero_not_matched_test),
725 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_uid_test,
726 cs_amp_lib_test_get_cal_gen_params),
727 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_unchecked_test,
728 cs_amp_lib_test_get_cal_gen_params),
729 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_checked_test,
730 cs_amp_lib_test_get_cal_gen_params),
731 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test,
732 cs_amp_lib_test_get_cal_gen_params),
733 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_fallback_test,
734 cs_amp_lib_test_get_cal_gen_params),
735 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_empty_entry_test),
736
737 /* Tests for writing calibration data */
738 KUNIT_CASE(cs_amp_lib_test_write_cal_data_test),
739
740 { } /* terminator */
741 };
742
743 static struct kunit_suite cs_amp_lib_test_suite = {
744 .name = "snd-soc-cs-amp-lib-test",
745 .init = cs_amp_lib_test_case_init,
746 .test_cases = cs_amp_lib_test_cases,
747 };
748
749 kunit_test_suite(cs_amp_lib_test_suite);
750
751 MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
752 MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library");
753 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
754 MODULE_LICENSE("GPL");
755