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