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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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. */ 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. */ 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. */ 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 */ 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 */ 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 */ 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 */ 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 */ 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. */ 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 */ 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 */ 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 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 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 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 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