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 #define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker" 23 #define LENOVO_SPEAKER_ID_EFI_GUID \ 24 EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82) 25 26 #define HP_SPEAKER_ID_EFI_NAME L"HPSpeakerID" 27 #define HP_SPEAKER_ID_EFI_GUID \ 28 EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e) 29 30 KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy, 31 struct faux_device *) 32 33 struct cs_amp_lib_test_priv { 34 struct faux_device *amp_dev; 35 36 struct cirrus_amp_efi_data *cal_blob; 37 struct list_head ctl_write_list; 38 }; 39 40 struct cs_amp_lib_test_ctl_write_entry { 41 struct list_head list; 42 unsigned int value; 43 char name[16]; 44 }; 45 46 struct cs_amp_lib_test_param { 47 int num_amps; 48 int amp_index; 49 }; 50 51 static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps) 52 { 53 struct cs_amp_lib_test_priv *priv = test->priv; 54 unsigned int blob_size; 55 int i; 56 57 blob_size = struct_size(priv->cal_blob, data, num_amps); 58 59 priv->cal_blob = kunit_kzalloc(test, blob_size, GFP_KERNEL); 60 KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob); 61 62 priv->cal_blob->size = blob_size; 63 priv->cal_blob->count = num_amps; 64 65 get_random_bytes(priv->cal_blob->data, flex_array_size(priv->cal_blob, data, num_amps)); 66 67 /* Ensure all timestamps are non-zero to mark the entry valid. */ 68 for (i = 0; i < num_amps; i++) 69 priv->cal_blob->data[i].calTime[0] |= 1; 70 71 /* Ensure that all UIDs are non-zero and unique. */ 72 for (i = 0; i < num_amps; i++) 73 *(u8 *)&priv->cal_blob->data[i].calTarget[0] = i + 1; 74 } 75 76 static u64 cs_amp_lib_test_get_target_uid(struct kunit *test) 77 { 78 struct cs_amp_lib_test_priv *priv = test->priv; 79 const struct cs_amp_lib_test_param *param = test->param_value; 80 u64 uid; 81 82 uid = priv->cal_blob->data[param->amp_index].calTarget[1]; 83 uid <<= 32; 84 uid |= priv->cal_blob->data[param->amp_index].calTarget[0]; 85 86 return uid; 87 } 88 89 /* Redirected get_efi_variable to simulate that the file is too short */ 90 static efi_status_t cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t *name, 91 efi_guid_t *guid, 92 unsigned long *size, 93 void *buf) 94 { 95 if (!buf) { 96 *size = offsetof(struct cirrus_amp_efi_data, data) - 1; 97 return EFI_BUFFER_TOO_SMALL; 98 } 99 100 return EFI_NOT_FOUND; 101 } 102 103 /* Should return -EOVERFLOW if the header is larger than the EFI data */ 104 static void cs_amp_lib_test_cal_data_too_short_test(struct kunit *test) 105 { 106 struct cs_amp_lib_test_priv *priv = test->priv; 107 struct cirrus_amp_cal_data result_data; 108 int ret; 109 110 /* Redirect calls to get EFI data */ 111 kunit_activate_static_stub(test, 112 cs_amp_test_hooks->get_efi_variable, 113 cs_amp_lib_test_get_efi_variable_nohead); 114 115 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data); 116 KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW); 117 118 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 119 } 120 121 /* Redirected get_efi_variable to simulate that the count is larger than the file */ 122 static efi_status_t cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t *name, 123 efi_guid_t *guid, 124 unsigned long *size, 125 void *buf) 126 { 127 struct kunit *test = kunit_get_current_test(); 128 struct cs_amp_lib_test_priv *priv = test->priv; 129 130 if (!buf) { 131 /* 132 * Return a size that is shorter than required for the 133 * declared number of entries. 134 */ 135 *size = priv->cal_blob->size - 1; 136 return EFI_BUFFER_TOO_SMALL; 137 } 138 139 memcpy(buf, priv->cal_blob, priv->cal_blob->size - 1); 140 141 return EFI_SUCCESS; 142 } 143 144 /* Should return -EOVERFLOW if the entry count is larger than the EFI data */ 145 static void cs_amp_lib_test_cal_count_too_big_test(struct kunit *test) 146 { 147 struct cs_amp_lib_test_priv *priv = test->priv; 148 struct cirrus_amp_cal_data result_data; 149 int ret; 150 151 cs_amp_lib_test_init_dummy_cal_blob(test, 8); 152 153 /* Redirect calls to get EFI data */ 154 kunit_activate_static_stub(test, 155 cs_amp_test_hooks->get_efi_variable, 156 cs_amp_lib_test_get_efi_variable_bad_count); 157 158 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data); 159 KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW); 160 161 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 162 } 163 164 /* Redirected get_efi_variable to simulate that the variable not found */ 165 static efi_status_t cs_amp_lib_test_get_efi_variable_none(efi_char16_t *name, 166 efi_guid_t *guid, 167 unsigned long *size, 168 void *buf) 169 { 170 return EFI_NOT_FOUND; 171 } 172 173 /* If EFI doesn't contain a cal data variable the result should be -ENOENT */ 174 static void cs_amp_lib_test_no_cal_data_test(struct kunit *test) 175 { 176 struct cs_amp_lib_test_priv *priv = test->priv; 177 struct cirrus_amp_cal_data result_data; 178 int ret; 179 180 /* Redirect calls to get EFI data */ 181 kunit_activate_static_stub(test, 182 cs_amp_test_hooks->get_efi_variable, 183 cs_amp_lib_test_get_efi_variable_none); 184 185 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data); 186 KUNIT_EXPECT_EQ(test, ret, -ENOENT); 187 188 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 189 } 190 191 /* Redirected get_efi_variable to simulate reading a cal data blob */ 192 static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name, 193 efi_guid_t *guid, 194 unsigned long *size, 195 void *buf) 196 { 197 static const efi_char16_t expected_name[] = L"CirrusSmartAmpCalibrationData"; 198 static const efi_guid_t expected_guid = 199 EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3); 200 struct kunit *test = kunit_get_current_test(); 201 struct cs_amp_lib_test_priv *priv = test->priv; 202 203 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name); 204 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid); 205 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size); 206 207 if (memcmp(name, expected_name, sizeof(expected_name)) || 208 efi_guidcmp(*guid, expected_guid)) 209 return -EFI_NOT_FOUND; 210 211 if (!buf) { 212 *size = priv->cal_blob->size; 213 return EFI_BUFFER_TOO_SMALL; 214 } 215 216 KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small"); 217 218 memcpy(buf, priv->cal_blob, priv->cal_blob->size); 219 220 return EFI_SUCCESS; 221 } 222 223 static efi_status_t cs_amp_lib_test_get_hp_cal_efi_variable(efi_char16_t *name, 224 efi_guid_t *guid, 225 unsigned long *size, 226 void *buf) 227 { 228 static const efi_char16_t expected_name[] = L"SmartAmpCalibrationData"; 229 static const efi_guid_t expected_guid = 230 EFI_GUID(0x53559579, 0x8753, 0x4f5c, 0x91, 0x30, 0xe8, 0x2a, 0xcf, 0xb8, 0xd8, 0x93); 231 struct kunit *test = kunit_get_current_test(); 232 struct cs_amp_lib_test_priv *priv = test->priv; 233 234 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name); 235 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid); 236 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size); 237 238 if (memcmp(name, expected_name, sizeof(expected_name)) || 239 efi_guidcmp(*guid, expected_guid)) 240 return -EFI_NOT_FOUND; 241 242 if (!buf) { 243 *size = priv->cal_blob->size; 244 return EFI_BUFFER_TOO_SMALL; 245 } 246 247 KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small"); 248 249 memcpy(buf, priv->cal_blob, priv->cal_blob->size); 250 251 return EFI_SUCCESS; 252 } 253 254 /* Get cal data block from HP variable. */ 255 static void cs_amp_lib_test_get_hp_efi_cal(struct kunit *test) 256 { 257 struct cs_amp_lib_test_priv *priv = test->priv; 258 struct cirrus_amp_cal_data result_data; 259 int ret; 260 261 cs_amp_lib_test_init_dummy_cal_blob(test, 2); 262 263 kunit_activate_static_stub(test, 264 cs_amp_test_hooks->get_efi_variable, 265 cs_amp_lib_test_get_hp_cal_efi_variable); 266 267 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data); 268 KUNIT_EXPECT_EQ(test, ret, 0); 269 270 KUNIT_EXPECT_MEMEQ(test, &result_data, &priv->cal_blob->data[0], sizeof(result_data)); 271 } 272 273 /* Get cal data block for a given amp, matched by target UID. */ 274 static void cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit *test) 275 { 276 struct cs_amp_lib_test_priv *priv = test->priv; 277 const struct cs_amp_lib_test_param *param = test->param_value; 278 struct cirrus_amp_cal_data result_data; 279 u64 target_uid; 280 int ret; 281 282 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps); 283 284 /* Redirect calls to get EFI data */ 285 kunit_activate_static_stub(test, 286 cs_amp_test_hooks->get_efi_variable, 287 cs_amp_lib_test_get_efi_variable); 288 289 target_uid = cs_amp_lib_test_get_target_uid(test); 290 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid, -1, &result_data); 291 KUNIT_EXPECT_EQ(test, ret, 0); 292 293 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 294 295 KUNIT_EXPECT_EQ(test, result_data.calTarget[0], target_uid & 0xFFFFFFFFULL); 296 KUNIT_EXPECT_EQ(test, result_data.calTarget[1], target_uid >> 32); 297 KUNIT_EXPECT_EQ(test, result_data.calTime[0], 298 priv->cal_blob->data[param->amp_index].calTime[0]); 299 KUNIT_EXPECT_EQ(test, result_data.calTime[1], 300 priv->cal_blob->data[param->amp_index].calTime[1]); 301 KUNIT_EXPECT_EQ(test, result_data.calAmbient, 302 priv->cal_blob->data[param->amp_index].calAmbient); 303 KUNIT_EXPECT_EQ(test, result_data.calStatus, 304 priv->cal_blob->data[param->amp_index].calStatus); 305 KUNIT_EXPECT_EQ(test, result_data.calR, 306 priv->cal_blob->data[param->amp_index].calR); 307 } 308 309 /* Get cal data block for a given amp index without checking target UID. */ 310 static void cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit *test) 311 { 312 struct cs_amp_lib_test_priv *priv = test->priv; 313 const struct cs_amp_lib_test_param *param = test->param_value; 314 struct cirrus_amp_cal_data result_data; 315 int ret; 316 317 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps); 318 319 /* Redirect calls to get EFI data */ 320 kunit_activate_static_stub(test, 321 cs_amp_test_hooks->get_efi_variable, 322 cs_amp_lib_test_get_efi_variable); 323 324 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 325 param->amp_index, &result_data); 326 KUNIT_EXPECT_EQ(test, ret, 0); 327 328 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 329 330 KUNIT_EXPECT_EQ(test, result_data.calTime[0], 331 priv->cal_blob->data[param->amp_index].calTime[0]); 332 KUNIT_EXPECT_EQ(test, result_data.calTime[1], 333 priv->cal_blob->data[param->amp_index].calTime[1]); 334 KUNIT_EXPECT_EQ(test, result_data.calAmbient, 335 priv->cal_blob->data[param->amp_index].calAmbient); 336 KUNIT_EXPECT_EQ(test, result_data.calStatus, 337 priv->cal_blob->data[param->amp_index].calStatus); 338 KUNIT_EXPECT_EQ(test, result_data.calR, 339 priv->cal_blob->data[param->amp_index].calR); 340 } 341 342 /* Get cal data block for a given amp index with checked target UID. */ 343 static void cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit *test) 344 { 345 struct cs_amp_lib_test_priv *priv = test->priv; 346 const struct cs_amp_lib_test_param *param = test->param_value; 347 struct cirrus_amp_cal_data result_data; 348 u64 target_uid; 349 int ret; 350 351 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps); 352 353 /* Redirect calls to get EFI data */ 354 kunit_activate_static_stub(test, 355 cs_amp_test_hooks->get_efi_variable, 356 cs_amp_lib_test_get_efi_variable); 357 358 target_uid = cs_amp_lib_test_get_target_uid(test); 359 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid, 360 param->amp_index, &result_data); 361 KUNIT_EXPECT_EQ(test, ret, 0); 362 363 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 364 365 KUNIT_EXPECT_EQ(test, result_data.calTime[0], 366 priv->cal_blob->data[param->amp_index].calTime[0]); 367 KUNIT_EXPECT_EQ(test, result_data.calTime[1], 368 priv->cal_blob->data[param->amp_index].calTime[1]); 369 KUNIT_EXPECT_EQ(test, result_data.calAmbient, 370 priv->cal_blob->data[param->amp_index].calAmbient); 371 KUNIT_EXPECT_EQ(test, result_data.calStatus, 372 priv->cal_blob->data[param->amp_index].calStatus); 373 KUNIT_EXPECT_EQ(test, result_data.calR, 374 priv->cal_blob->data[param->amp_index].calR); 375 } 376 377 /* 378 * Get cal data block for a given amp index with checked target UID. 379 * The UID does not match so the result should be -ENOENT. 380 */ 381 static void cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit *test) 382 { 383 struct cs_amp_lib_test_priv *priv = test->priv; 384 const struct cs_amp_lib_test_param *param = test->param_value; 385 struct cirrus_amp_cal_data result_data; 386 u64 target_uid; 387 int ret; 388 389 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps); 390 391 /* Redirect calls to get EFI data */ 392 kunit_activate_static_stub(test, 393 cs_amp_test_hooks->get_efi_variable, 394 cs_amp_lib_test_get_efi_variable); 395 396 /* Get a target UID that won't match the entry */ 397 target_uid = ~cs_amp_lib_test_get_target_uid(test); 398 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid, 399 param->amp_index, &result_data); 400 KUNIT_EXPECT_EQ(test, ret, -ENOENT); 401 402 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 403 } 404 405 /* 406 * Get cal data block for a given amp, where the cal data does not 407 * specify calTarget so the lookup falls back to using the index 408 */ 409 static void cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit *test) 410 { 411 struct cs_amp_lib_test_priv *priv = test->priv; 412 const struct cs_amp_lib_test_param *param = test->param_value; 413 struct cirrus_amp_cal_data result_data; 414 static const u64 bad_target_uid = 0xBADCA100BABABABAULL; 415 int i, ret; 416 417 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps); 418 419 /* Make all the target values zero so they are ignored */ 420 for (i = 0; i < priv->cal_blob->count; ++i) { 421 priv->cal_blob->data[i].calTarget[0] = 0; 422 priv->cal_blob->data[i].calTarget[1] = 0; 423 } 424 425 /* Redirect calls to get EFI data */ 426 kunit_activate_static_stub(test, 427 cs_amp_test_hooks->get_efi_variable, 428 cs_amp_lib_test_get_efi_variable); 429 430 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, 431 param->amp_index, &result_data); 432 KUNIT_EXPECT_EQ(test, ret, 0); 433 434 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 435 436 KUNIT_EXPECT_EQ(test, result_data.calTime[0], 437 priv->cal_blob->data[param->amp_index].calTime[0]); 438 KUNIT_EXPECT_EQ(test, result_data.calTime[1], 439 priv->cal_blob->data[param->amp_index].calTime[1]); 440 KUNIT_EXPECT_EQ(test, result_data.calAmbient, 441 priv->cal_blob->data[param->amp_index].calAmbient); 442 KUNIT_EXPECT_EQ(test, result_data.calStatus, 443 priv->cal_blob->data[param->amp_index].calStatus); 444 KUNIT_EXPECT_EQ(test, result_data.calR, 445 priv->cal_blob->data[param->amp_index].calR); 446 } 447 448 /* 449 * If the target UID isn't present in the cal data, and there isn't an 450 * index to fall back do, the result should be -ENOENT. 451 */ 452 static void cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit *test) 453 { 454 struct cs_amp_lib_test_priv *priv = test->priv; 455 struct cirrus_amp_cal_data result_data; 456 static const u64 bad_target_uid = 0xBADCA100BABABABAULL; 457 int i, ret; 458 459 cs_amp_lib_test_init_dummy_cal_blob(test, 8); 460 461 /* Make all the target values != bad_target_uid */ 462 for (i = 0; i < priv->cal_blob->count; ++i) { 463 priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL); 464 priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32); 465 } 466 467 /* Redirect calls to get EFI data */ 468 kunit_activate_static_stub(test, 469 cs_amp_test_hooks->get_efi_variable, 470 cs_amp_lib_test_get_efi_variable); 471 472 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, -1, 473 &result_data); 474 KUNIT_EXPECT_EQ(test, ret, -ENOENT); 475 476 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 477 } 478 479 /* 480 * If the target UID isn't present in the cal data, and the index is 481 * out of range, the result should be -ENOENT. 482 */ 483 static void cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit *test) 484 { 485 struct cs_amp_lib_test_priv *priv = test->priv; 486 struct cirrus_amp_cal_data result_data; 487 static const u64 bad_target_uid = 0xBADCA100BABABABAULL; 488 int i, ret; 489 490 cs_amp_lib_test_init_dummy_cal_blob(test, 8); 491 492 /* Make all the target values != bad_target_uid */ 493 for (i = 0; i < priv->cal_blob->count; ++i) { 494 priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL); 495 priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32); 496 } 497 498 /* Redirect calls to get EFI data */ 499 kunit_activate_static_stub(test, 500 cs_amp_test_hooks->get_efi_variable, 501 cs_amp_lib_test_get_efi_variable); 502 503 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, 99, 504 &result_data); 505 KUNIT_EXPECT_EQ(test, ret, -ENOENT); 506 507 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 508 } 509 510 /* 511 * If the target UID isn't given, and the index is out of range, the 512 * result should be -ENOENT. 513 */ 514 static void cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit *test) 515 { 516 struct cs_amp_lib_test_priv *priv = test->priv; 517 struct cirrus_amp_cal_data result_data; 518 int ret; 519 520 cs_amp_lib_test_init_dummy_cal_blob(test, 8); 521 522 /* Redirect calls to get EFI data */ 523 kunit_activate_static_stub(test, 524 cs_amp_test_hooks->get_efi_variable, 525 cs_amp_lib_test_get_efi_variable); 526 527 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 99, &result_data); 528 KUNIT_EXPECT_EQ(test, ret, -ENOENT); 529 530 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 531 } 532 533 /* If neither the target UID or the index is given the result should be -ENOENT. */ 534 static void cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit *test) 535 { 536 struct cs_amp_lib_test_priv *priv = test->priv; 537 struct cirrus_amp_cal_data result_data; 538 int ret; 539 540 cs_amp_lib_test_init_dummy_cal_blob(test, 8); 541 542 /* Redirect calls to get EFI data */ 543 kunit_activate_static_stub(test, 544 cs_amp_test_hooks->get_efi_variable, 545 cs_amp_lib_test_get_efi_variable); 546 547 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data); 548 KUNIT_EXPECT_EQ(test, ret, -ENOENT); 549 550 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 551 } 552 553 /* 554 * If the UID is passed as 0 this must not match an entry with an 555 * unpopulated calTarget 556 */ 557 static void cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit *test) 558 { 559 struct cs_amp_lib_test_priv *priv = test->priv; 560 struct cirrus_amp_cal_data result_data; 561 int i, ret; 562 563 cs_amp_lib_test_init_dummy_cal_blob(test, 8); 564 565 /* Make all the target values zero so they are ignored */ 566 for (i = 0; i < priv->cal_blob->count; ++i) { 567 priv->cal_blob->data[i].calTarget[0] = 0; 568 priv->cal_blob->data[i].calTarget[1] = 0; 569 } 570 571 /* Redirect calls to get EFI data */ 572 kunit_activate_static_stub(test, 573 cs_amp_test_hooks->get_efi_variable, 574 cs_amp_lib_test_get_efi_variable); 575 576 ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data); 577 KUNIT_EXPECT_EQ(test, ret, -ENOENT); 578 579 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 580 } 581 582 /* 583 * If an entry has a timestamp of 0 it should be ignored even if it has 584 * a matching target UID. 585 */ 586 static void cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit *test) 587 { 588 struct cs_amp_lib_test_priv *priv = test->priv; 589 struct cirrus_amp_cal_data result_data; 590 u64 uid; 591 592 cs_amp_lib_test_init_dummy_cal_blob(test, 8); 593 594 /* Mark the 3rd entry invalid by zeroing calTime */ 595 priv->cal_blob->data[2].calTime[0] = 0; 596 priv->cal_blob->data[2].calTime[1] = 0; 597 598 /* Get the UID value of the 3rd entry */ 599 uid = priv->cal_blob->data[2].calTarget[1]; 600 uid <<= 32; 601 uid |= priv->cal_blob->data[2].calTarget[0]; 602 603 /* Redirect calls to get EFI data */ 604 kunit_activate_static_stub(test, 605 cs_amp_test_hooks->get_efi_variable, 606 cs_amp_lib_test_get_efi_variable); 607 608 /* Lookup by UID should not find it */ 609 KUNIT_EXPECT_EQ(test, 610 cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 611 uid, -1, 612 &result_data), 613 -ENOENT); 614 615 /* Get by index should ignore it */ 616 KUNIT_EXPECT_EQ(test, 617 cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 618 0, 2, 619 &result_data), 620 -ENOENT); 621 622 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); 623 } 624 625 static const struct cirrus_amp_cal_controls cs_amp_lib_test_calibration_controls = { 626 .alg_id = 0x9f210, 627 .mem_region = WMFW_ADSP2_YM, 628 .ambient = "CAL_AMBIENT", 629 .calr = "CAL_R", 630 .status = "CAL_STATUS", 631 .checksum = "CAL_CHECKSUM", 632 }; 633 634 static int cs_amp_lib_test_write_cal_coeff(struct cs_dsp *dsp, 635 const struct cirrus_amp_cal_controls *controls, 636 const char *ctl_name, u32 val) 637 { 638 struct kunit *test = kunit_get_current_test(); 639 struct cs_amp_lib_test_priv *priv = test->priv; 640 struct cs_amp_lib_test_ctl_write_entry *entry; 641 642 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctl_name); 643 KUNIT_EXPECT_PTR_EQ(test, controls, &cs_amp_lib_test_calibration_controls); 644 645 entry = kunit_kzalloc(test, sizeof(*entry), GFP_KERNEL); 646 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, entry); 647 648 INIT_LIST_HEAD(&entry->list); 649 strscpy(entry->name, ctl_name, sizeof(entry->name)); 650 entry->value = val; 651 652 list_add_tail(&entry->list, &priv->ctl_write_list); 653 654 return 0; 655 } 656 657 static void cs_amp_lib_test_write_cal_data_test(struct kunit *test) 658 { 659 struct cs_amp_lib_test_priv *priv = test->priv; 660 struct cs_amp_lib_test_ctl_write_entry *entry; 661 struct cirrus_amp_cal_data data; 662 struct cs_dsp *dsp; 663 int ret; 664 665 dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL); 666 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp); 667 dsp->dev = &priv->amp_dev->dev; 668 669 get_random_bytes(&data, sizeof(data)); 670 671 /* Redirect calls to write firmware controls */ 672 kunit_activate_static_stub(test, 673 cs_amp_test_hooks->write_cal_coeff, 674 cs_amp_lib_test_write_cal_coeff); 675 676 ret = cs_amp_write_cal_coeffs(dsp, &cs_amp_lib_test_calibration_controls, &data); 677 KUNIT_EXPECT_EQ(test, ret, 0); 678 679 kunit_deactivate_static_stub(test, cs_amp_test_hooks->write_cal_coeff); 680 681 KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->ctl_write_list), 4); 682 683 /* Checksum control must be written last */ 684 entry = list_last_entry(&priv->ctl_write_list, typeof(*entry), list); 685 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.checksum); 686 KUNIT_EXPECT_EQ(test, entry->value, data.calR + 1); 687 list_del(&entry->list); 688 689 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list); 690 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.ambient); 691 KUNIT_EXPECT_EQ(test, entry->value, data.calAmbient); 692 list_del(&entry->list); 693 694 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list); 695 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.calr); 696 KUNIT_EXPECT_EQ(test, entry->value, data.calR); 697 list_del(&entry->list); 698 699 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list); 700 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.status); 701 KUNIT_EXPECT_EQ(test, entry->value, data.calStatus); 702 } 703 704 static void cs_amp_lib_test_spkid_lenovo_not_present(struct kunit *test) 705 { 706 struct cs_amp_lib_test_priv *priv = test->priv; 707 struct device *dev = &priv->amp_dev->dev; 708 709 kunit_activate_static_stub(test, 710 cs_amp_test_hooks->get_efi_variable, 711 cs_amp_lib_test_get_efi_variable_none); 712 713 KUNIT_EXPECT_EQ(test, -ENOENT, cs_amp_get_vendor_spkid(dev)); 714 } 715 716 static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_d0(efi_char16_t *name, 717 efi_guid_t *guid, 718 unsigned long *size, 719 void *buf) 720 { 721 struct kunit *test = kunit_get_current_test(); 722 723 if (efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID) || 724 memcmp(name, LENOVO_SPEAKER_ID_EFI_NAME, sizeof(LENOVO_SPEAKER_ID_EFI_NAME))) 725 return EFI_NOT_FOUND; 726 727 KUNIT_ASSERT_EQ(test, *size, 1); 728 *size = 1; 729 *(u8 *)buf = 0xd0; 730 731 return EFI_SUCCESS; 732 } 733 734 static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_d1(efi_char16_t *name, 735 efi_guid_t *guid, 736 unsigned long *size, 737 void *buf) 738 { 739 struct kunit *test = kunit_get_current_test(); 740 741 if (efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID) || 742 memcmp(name, LENOVO_SPEAKER_ID_EFI_NAME, sizeof(LENOVO_SPEAKER_ID_EFI_NAME))) 743 return EFI_NOT_FOUND; 744 745 KUNIT_ASSERT_EQ(test, *size, 1); 746 *size = 1; 747 *(u8 *)buf = 0xd1; 748 749 return EFI_SUCCESS; 750 } 751 752 static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_00(efi_char16_t *name, 753 efi_guid_t *guid, 754 unsigned long *size, 755 void *buf) 756 { 757 struct kunit *test = kunit_get_current_test(); 758 759 KUNIT_ASSERT_EQ(test, 0, efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID)); 760 KUNIT_ASSERT_EQ(test, *size, 1); 761 *size = 1; 762 *(u8 *)buf = 0; 763 764 return EFI_SUCCESS; 765 } 766 767 static void cs_amp_lib_test_spkid_lenovo_d0(struct kunit *test) 768 { 769 struct cs_amp_lib_test_priv *priv = test->priv; 770 struct device *dev = &priv->amp_dev->dev; 771 772 kunit_activate_static_stub(test, 773 cs_amp_test_hooks->get_efi_variable, 774 cs_amp_lib_test_get_efi_variable_lenovo_d0); 775 776 KUNIT_EXPECT_EQ(test, 0, cs_amp_get_vendor_spkid(dev)); 777 } 778 779 static void cs_amp_lib_test_spkid_lenovo_d1(struct kunit *test) 780 { 781 struct cs_amp_lib_test_priv *priv = test->priv; 782 struct device *dev = &priv->amp_dev->dev; 783 784 kunit_activate_static_stub(test, 785 cs_amp_test_hooks->get_efi_variable, 786 cs_amp_lib_test_get_efi_variable_lenovo_d1); 787 788 KUNIT_EXPECT_EQ(test, 1, cs_amp_get_vendor_spkid(dev)); 789 } 790 791 static void cs_amp_lib_test_spkid_lenovo_illegal(struct kunit *test) 792 { 793 struct cs_amp_lib_test_priv *priv = test->priv; 794 struct device *dev = &priv->amp_dev->dev; 795 796 kunit_activate_static_stub(test, 797 cs_amp_test_hooks->get_efi_variable, 798 cs_amp_lib_test_get_efi_variable_lenovo_00); 799 800 KUNIT_EXPECT_LT(test, cs_amp_get_vendor_spkid(dev), 0); 801 } 802 803 static efi_status_t cs_amp_lib_test_get_efi_variable_buf_too_small(efi_char16_t *name, 804 efi_guid_t *guid, 805 unsigned long *size, 806 void *buf) 807 { 808 return EFI_BUFFER_TOO_SMALL; 809 } 810 811 static void cs_amp_lib_test_spkid_lenovo_oversize(struct kunit *test) 812 { 813 struct cs_amp_lib_test_priv *priv = test->priv; 814 struct device *dev = &priv->amp_dev->dev; 815 816 kunit_activate_static_stub(test, 817 cs_amp_test_hooks->get_efi_variable, 818 cs_amp_lib_test_get_efi_variable_buf_too_small); 819 820 KUNIT_EXPECT_LT(test, cs_amp_get_vendor_spkid(dev), 0); 821 } 822 823 static efi_status_t cs_amp_lib_test_get_efi_variable_hp_30(efi_char16_t *name, 824 efi_guid_t *guid, 825 unsigned long *size, 826 void *buf) 827 { 828 struct kunit *test = kunit_get_current_test(); 829 830 if (efi_guidcmp(*guid, HP_SPEAKER_ID_EFI_GUID) || 831 memcmp(name, HP_SPEAKER_ID_EFI_NAME, sizeof(HP_SPEAKER_ID_EFI_NAME))) 832 return EFI_NOT_FOUND; 833 834 KUNIT_ASSERT_EQ(test, *size, 1); 835 *size = 1; 836 *(u8 *)buf = 0x30; 837 838 return EFI_SUCCESS; 839 } 840 841 static efi_status_t cs_amp_lib_test_get_efi_variable_hp_31(efi_char16_t *name, 842 efi_guid_t *guid, 843 unsigned long *size, 844 void *buf) 845 { 846 struct kunit *test = kunit_get_current_test(); 847 848 if (efi_guidcmp(*guid, HP_SPEAKER_ID_EFI_GUID) || 849 memcmp(name, HP_SPEAKER_ID_EFI_NAME, sizeof(HP_SPEAKER_ID_EFI_NAME))) 850 return EFI_NOT_FOUND; 851 852 KUNIT_ASSERT_EQ(test, *size, 1); 853 *size = 1; 854 *(u8 *)buf = 0x31; 855 856 return EFI_SUCCESS; 857 } 858 859 static void cs_amp_lib_test_spkid_hp_30(struct kunit *test) 860 { 861 struct cs_amp_lib_test_priv *priv = test->priv; 862 struct device *dev = &priv->amp_dev->dev; 863 864 kunit_activate_static_stub(test, 865 cs_amp_test_hooks->get_efi_variable, 866 cs_amp_lib_test_get_efi_variable_hp_30); 867 868 KUNIT_EXPECT_EQ(test, 0, cs_amp_get_vendor_spkid(dev)); 869 } 870 871 static void cs_amp_lib_test_spkid_hp_31(struct kunit *test) 872 { 873 struct cs_amp_lib_test_priv *priv = test->priv; 874 struct device *dev = &priv->amp_dev->dev; 875 876 kunit_activate_static_stub(test, 877 cs_amp_test_hooks->get_efi_variable, 878 cs_amp_lib_test_get_efi_variable_hp_31); 879 880 KUNIT_EXPECT_EQ(test, 1, cs_amp_get_vendor_spkid(dev)); 881 } 882 883 static int cs_amp_lib_test_case_init(struct kunit *test) 884 { 885 struct cs_amp_lib_test_priv *priv; 886 887 KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks); 888 889 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 890 if (!priv) 891 return -ENOMEM; 892 893 test->priv = priv; 894 INIT_LIST_HEAD(&priv->ctl_write_list); 895 896 /* Create dummy amp driver dev */ 897 priv->amp_dev = faux_device_create("cs_amp_lib_test_drv", NULL, NULL); 898 KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev); 899 KUNIT_ASSERT_EQ(test, 0, 900 kunit_add_action_or_reset(test, 901 faux_device_destroy_wrapper, 902 priv->amp_dev)); 903 904 return 0; 905 } 906 907 static const struct cs_amp_lib_test_param cs_amp_lib_test_get_cal_param_cases[] = { 908 { .num_amps = 2, .amp_index = 0 }, 909 { .num_amps = 2, .amp_index = 1 }, 910 911 { .num_amps = 3, .amp_index = 0 }, 912 { .num_amps = 3, .amp_index = 1 }, 913 { .num_amps = 3, .amp_index = 2 }, 914 915 { .num_amps = 4, .amp_index = 0 }, 916 { .num_amps = 4, .amp_index = 1 }, 917 { .num_amps = 4, .amp_index = 2 }, 918 { .num_amps = 4, .amp_index = 3 }, 919 920 { .num_amps = 5, .amp_index = 0 }, 921 { .num_amps = 5, .amp_index = 1 }, 922 { .num_amps = 5, .amp_index = 2 }, 923 { .num_amps = 5, .amp_index = 3 }, 924 { .num_amps = 5, .amp_index = 4 }, 925 926 { .num_amps = 6, .amp_index = 0 }, 927 { .num_amps = 6, .amp_index = 1 }, 928 { .num_amps = 6, .amp_index = 2 }, 929 { .num_amps = 6, .amp_index = 3 }, 930 { .num_amps = 6, .amp_index = 4 }, 931 { .num_amps = 6, .amp_index = 5 }, 932 933 { .num_amps = 8, .amp_index = 0 }, 934 { .num_amps = 8, .amp_index = 1 }, 935 { .num_amps = 8, .amp_index = 2 }, 936 { .num_amps = 8, .amp_index = 3 }, 937 { .num_amps = 8, .amp_index = 4 }, 938 { .num_amps = 8, .amp_index = 5 }, 939 { .num_amps = 8, .amp_index = 6 }, 940 { .num_amps = 8, .amp_index = 7 }, 941 }; 942 943 static void cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param *param, 944 char *desc) 945 { 946 snprintf(desc, KUNIT_PARAM_DESC_SIZE, "num_amps:%d amp_index:%d", 947 param->num_amps, param->amp_index); 948 } 949 950 KUNIT_ARRAY_PARAM(cs_amp_lib_test_get_cal, cs_amp_lib_test_get_cal_param_cases, 951 cs_amp_lib_test_get_cal_param_desc); 952 953 static struct kunit_case cs_amp_lib_test_cases[] = { 954 /* Tests for getting calibration data from EFI */ 955 KUNIT_CASE(cs_amp_lib_test_cal_data_too_short_test), 956 KUNIT_CASE(cs_amp_lib_test_cal_count_too_big_test), 957 KUNIT_CASE(cs_amp_lib_test_no_cal_data_test), 958 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test), 959 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test), 960 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test), 961 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_no_index_test), 962 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_zero_not_matched_test), 963 KUNIT_CASE(cs_amp_lib_test_get_hp_efi_cal), 964 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_uid_test, 965 cs_amp_lib_test_get_cal_gen_params), 966 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_unchecked_test, 967 cs_amp_lib_test_get_cal_gen_params), 968 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_checked_test, 969 cs_amp_lib_test_get_cal_gen_params), 970 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test, 971 cs_amp_lib_test_get_cal_gen_params), 972 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_fallback_test, 973 cs_amp_lib_test_get_cal_gen_params), 974 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_empty_entry_test), 975 976 /* Tests for writing calibration data */ 977 KUNIT_CASE(cs_amp_lib_test_write_cal_data_test), 978 979 /* Test cases for speaker ID */ 980 KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_not_present), 981 KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_d0), 982 KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_d1), 983 KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_illegal), 984 KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_oversize), 985 KUNIT_CASE(cs_amp_lib_test_spkid_hp_30), 986 KUNIT_CASE(cs_amp_lib_test_spkid_hp_31), 987 988 { } /* terminator */ 989 }; 990 991 static struct kunit_suite cs_amp_lib_test_suite = { 992 .name = "snd-soc-cs-amp-lib-test", 993 .init = cs_amp_lib_test_case_init, 994 .test_cases = cs_amp_lib_test_cases, 995 }; 996 997 kunit_test_suite(cs_amp_lib_test_suite); 998 999 MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); 1000 MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library"); 1001 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); 1002 MODULE_LICENSE("GPL"); 1003