]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: cs-amp-lib-test: Add test cases for cs_amp_set_efi_calibration_data()
authorRichard Fitzgerald <rf@opensource.cirrus.com>
Tue, 21 Oct 2025 10:50:22 +0000 (11:50 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 27 Oct 2025 14:07:51 +0000 (14:07 +0000)
Add a set of test cases for cs_amp_set_efi_calibration_data().

Broadly there are two type of behavior being tested:

How the EFI is updated:
- Create a new EFI
- Overwrite part of existing content
- Overwrite part of zero-filled preallocated content
- Grow the file to append new content

And how the location within the content is chosen:
- Overwrite a specific array entry
- Overwrite an entry with the same calTarget (silicon ID)
- Overwrite a free entry
- Append after existing data

Plus some cases for error conditions.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251021105022.1013685-12-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/cs-amp-lib.h
sound/soc/codecs/cs-amp-lib-test.c
sound/soc/codecs/cs-amp-lib.c

index 240bc53a93075efe45921edadc3424589c43f9c7..61e00017c9aabcafaa9897fe9a03a654ff8524a5 100644 (file)
@@ -71,6 +71,11 @@ struct cs_amp_test_hooks {
                                         u32 *returned_attr,
                                         unsigned long *size,
                                         void *buf);
+       efi_status_t (*set_efi_variable)(efi_char16_t *name,
+                                        efi_guid_t *guid,
+                                        u32 attr,
+                                        unsigned long size,
+                                        void *buf);
 
        int (*write_cal_coeff)(struct cs_dsp *dsp,
                               const struct cirrus_amp_cal_controls *controls,
index b00ba65badd5324168799bd08e095ff31ce52876..51799a9c86a32369fef2629c17ff6c12f2bf5366 100644 (file)
 #include <linux/random.h>
 #include <sound/cs-amp-lib.h>
 
+#define CIRRUS_LOGIC_CALIBRATION_EFI_NAME L"CirrusSmartAmpCalibrationData"
+#define CIRRUS_LOGIC_CALIBRATION_EFI_GUID \
+       EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3)
+
 #define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker"
 #define LENOVO_SPEAKER_ID_EFI_GUID \
        EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82)
 #define HP_SPEAKER_ID_EFI_GUID \
        EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e)
 
+#define HP_CALIBRATION_EFI_NAME L"SmartAmpCalibrationData"
+#define HP_CALIBRATION_EFI_GUID \
+       EFI_GUID(0x53559579, 0x8753, 0x4f5c, 0x91, 0x30, 0xe8, 0x2a, 0xcf, 0xb8, 0xd8, 0x93)
+
 KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
                            struct faux_device *)
 
@@ -35,6 +43,7 @@ struct cs_amp_lib_test_priv {
 
        struct cirrus_amp_efi_data *cal_blob;
        struct list_head ctl_write_list;
+       u32 efi_attr;
 };
 
 struct cs_amp_lib_test_ctl_write_entry {
@@ -48,6 +57,20 @@ struct cs_amp_lib_test_param {
        int amp_index;
 };
 
+static struct cirrus_amp_efi_data *cs_amp_lib_test_cal_blob_dup(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct cirrus_amp_efi_data *temp;
+
+       KUNIT_ASSERT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       temp = kunit_kmalloc(test, priv->cal_blob->size, GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, temp);
+       memcpy(temp, priv->cal_blob, priv->cal_blob->size);
+
+       return temp;
+}
+
 static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps)
 {
        struct cs_amp_lib_test_priv *priv = test->priv;
@@ -68,9 +91,15 @@ static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps
        for (i = 0; i < num_amps; i++)
                priv->cal_blob->data[i].calTime[0] |= 1;
 
-       /* Ensure that all UIDs are non-zero and unique. */
-       for (i = 0; i < num_amps; i++)
+       /*
+        * Ensure that all UIDs are non-zero and unique.
+        * Make both words non-zero and not equal values, so that
+        * tests can verify that both words were checked or changed.
+        */
+       for (i = 0; i < num_amps; i++) {
                *(u8 *)&priv->cal_blob->data[i].calTarget[0] = i + 1;
+               *(u8 *)&priv->cal_blob->data[i].calTarget[1] = i;
+       }
 }
 
 static u64 cs_amp_lib_test_get_target_uid(struct kunit *test)
@@ -198,9 +227,8 @@ static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name,
                                                     unsigned long *size,
                                                     void *buf)
 {
-       static const efi_char16_t expected_name[] = L"CirrusSmartAmpCalibrationData";
-       static const efi_guid_t expected_guid =
-               EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
+       static const efi_char16_t expected_name[] = CIRRUS_LOGIC_CALIBRATION_EFI_NAME;
+       static const efi_guid_t expected_guid = CIRRUS_LOGIC_CALIBRATION_EFI_GUID;
        struct kunit *test = kunit_get_current_test();
        struct cs_amp_lib_test_priv *priv = test->priv;
 
@@ -222,9 +250,56 @@ static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name,
        memcpy(buf, priv->cal_blob, priv->cal_blob->size);
 
        if (returned_attr) {
-               *returned_attr = EFI_VARIABLE_NON_VOLATILE |
-                                EFI_VARIABLE_BOOTSERVICE_ACCESS |
-                                EFI_VARIABLE_RUNTIME_ACCESS;
+               if (priv->efi_attr)
+                       *returned_attr = priv->efi_attr;
+               else
+                       *returned_attr = EFI_VARIABLE_NON_VOLATILE |
+                                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                        EFI_VARIABLE_RUNTIME_ACCESS;
+       }
+
+       return EFI_SUCCESS;
+}
+
+#define CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE \
+       struct_size_t(struct cirrus_amp_efi_data, data, 8)
+
+/* Redirected get_efi_variable to simulate reading a prealloced zero-filled blob */
+static efi_status_t cs_amp_lib_test_get_efi_variable_all_zeros(efi_char16_t *name,
+                                                              efi_guid_t *guid,
+                                                              u32 *returned_attr,
+                                                              unsigned long *size,
+                                                              void *buf)
+{
+       static const efi_char16_t expected_name[] = CIRRUS_LOGIC_CALIBRATION_EFI_NAME;
+       static const efi_guid_t expected_guid = CIRRUS_LOGIC_CALIBRATION_EFI_GUID;
+       struct kunit *test = kunit_get_current_test();
+       struct cs_amp_lib_test_priv *priv = test->priv;
+
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
+
+       if (memcmp(name, expected_name, sizeof(expected_name)) ||
+           efi_guidcmp(*guid, expected_guid))
+               return -EFI_NOT_FOUND;
+
+       if (!buf) {
+               *size = CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE;
+               return EFI_BUFFER_TOO_SMALL;
+       }
+
+       KUNIT_ASSERT_EQ(test, *size, struct_size(priv->cal_blob, data, 8));
+       priv->cal_blob = kunit_kzalloc(test, CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE, GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
+       memset(buf, 0, CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE);
+
+       if (returned_attr) {
+               if (priv->efi_attr)
+                       *returned_attr = priv->efi_attr;
+               else
+                       *returned_attr = EFI_VARIABLE_NON_VOLATILE |
+                                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                        EFI_VARIABLE_RUNTIME_ACCESS;
        }
 
        return EFI_SUCCESS;
@@ -789,6 +864,1292 @@ static void cs_amp_lib_test_write_ambient_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, entry->value, 18);
 }
 
+static efi_status_t cs_amp_lib_test_set_efi_variable(efi_char16_t *name,
+                                                    efi_guid_t *guid,
+                                                    u32 attr,
+                                                    unsigned long size,
+                                                    void *buf)
+{
+       static const efi_char16_t expected_name[] = CIRRUS_LOGIC_CALIBRATION_EFI_NAME;
+       static const efi_guid_t expected_guid = CIRRUS_LOGIC_CALIBRATION_EFI_GUID;
+       struct kunit *test = kunit_get_current_test();
+       struct cs_amp_lib_test_priv *priv = test->priv;
+
+       KUNIT_ASSERT_NOT_NULL(test, name);
+       KUNIT_ASSERT_NOT_NULL(test, guid);
+
+       if (memcmp(name, expected_name, sizeof(expected_name)) ||
+           efi_guidcmp(*guid, expected_guid))
+               return -EFI_NOT_FOUND;
+
+       KUNIT_ASSERT_NOT_NULL(test, buf);
+       KUNIT_ASSERT_NE(test, 0, size);
+
+       kunit_kfree(test, priv->cal_blob);
+       priv->cal_blob = kunit_kmalloc(test, size, GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
+       memcpy(priv->cal_blob, buf, size);
+       priv->efi_attr = attr;
+
+       return EFI_SUCCESS;
+}
+
+static efi_status_t cs_amp_lib_test_set_efi_variable_denied(efi_char16_t *name,
+                                                           efi_guid_t *guid,
+                                                           u32 attr,
+                                                           unsigned long size,
+                                                           void *buf)
+{
+       return EFI_WRITE_PROTECTED;
+}
+
+#define CS_AMP_CAL_DEFAULT_EFI_ATTR                    \
+               (EFI_VARIABLE_NON_VOLATILE |            \
+                EFI_VARIABLE_BOOTSERVICE_ACCESS |      \
+                EFI_VARIABLE_RUNTIME_ACCESS)
+
+static void cs_amp_lib_test_create_new_cal_efi(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable_none);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* For unspecified number of amps */
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, CS_AMP_CAL_DEFAULT_EFI_ATTR, priv->efi_attr);
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+       KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       for (i = 1; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       /* For 2 amps */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 2, &data));
+       KUNIT_EXPECT_EQ(test, CS_AMP_CAL_DEFAULT_EFI_ATTR, priv->efi_attr);
+       KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+
+       /* For 4 amps */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+       KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+       /* For 6 amps */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+}
+
+static void cs_amp_lib_test_create_new_cal_efi_indexed(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable_none);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* In slot 0 */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* In slot 1 */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[0], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* In slot 5 */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 5, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[0], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+}
+
+static void cs_amp_lib_test_create_new_cal_efi_indexed_no_max(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable_none);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* In slot 0 with unspecified number of amps */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+       KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       for (i = 1; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       /* In slot 1 with unspecified number of amps  */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 2);
+       KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[0], sizeof(data)));
+       for (i = 2; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       /* In slot 5 with unspecified number of amps  */
+       priv->cal_blob = NULL;
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 5, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 6);
+       KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       for (i = 0; (i < 5) && (i < priv->cal_blob->count); i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+       for (i = 6; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_append_cal_efi(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* Initially 1 used entry grown to 2 entries */
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 2, &data));
+       KUNIT_EXPECT_EQ(test, CS_AMP_CAL_DEFAULT_EFI_ATTR, priv->efi_attr);
+       KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+
+       /* Initially 1 entry grown to 4 entries */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+       KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+       /* Initially 2 entries grown to 4 entries */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+       KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+       KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+       /* Initially 1 entry grown to 6 entries */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* Initially 4 entries grown to 6 entries */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_append_cal_efi_indexed(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* Initially 1 entry grown to 2 entries using slot 1 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 2, &data));
+       KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+
+       /* Initially 1 entry grown to 6 entries using slot 1 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* Initially 2 entries grown to 6 entries using slot 2 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+       KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* Initially 2 entries grown to 6 entries using slot 4 */
+       kunit_kfree(test, original_blob);
+       kunit_kfree(test, priv->cal_blob);
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+       KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable_all_zeros);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /*
+        * Add an entry. The header should be filled in to match the
+        * original EFI variable size.
+        */
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+       KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       for (i = 1; i < priv->cal_blob->count; i++) {
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+       }
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first_no_shrink(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable_all_zeros);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /*
+        * Add an entry. The header should be filled in to match the
+        * original EFI variable size. A number of amps less than the
+        * available preallocated space does not shrink the EFI variable.
+        */
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+       KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       for (i = 1; i < priv->cal_blob->count; i++) {
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+       }
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable_all_zeros);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /*
+        * Write entry to slot 2. The header should be filled in to match
+        * the original EFI variable size.
+        */
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, -1, &data));
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+       KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+       for (i = 3; i < priv->cal_blob->count; i++) {
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+       }
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed_no_shrink(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable_all_zeros);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /*
+        * Write entry to slot 2. The header should be filled in to match
+        * the original EFI variable size. A number of amps less than the
+        * available preallocated space does not shrink the EFI variable.
+        */
+       get_random_bytes(&data, sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, 4, &data));
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+       KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+       for (i = 3; i < priv->cal_blob->count; i++) {
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+               KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+       }
+}
+
+static void cs_amp_lib_test_grow_append_cal_efi_indexed_no_max(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* Initially 1 entry adding slot 1 */
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 2);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       for (i = 2; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       /* Initially 1 entry adding slot 3 */
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 4);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+       for (i = 4; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       /* Initially 2 entries adding slot 3 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+       KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+       for (i = 4; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       /* Initially 4 entries adding slot 4 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       for (i = 5; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+       /* Initially 4 entries adding slot 6 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 6, -1, &data));
+       KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+                       priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[6], sizeof(data));
+       for (i = 7; i < priv->cal_blob->count; i++)
+               KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_cal_efi_replace_indexed(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* Initially 1 entry grown to 2 entries overwriting slot 0 */
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, 2, &data));
+       KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+
+       /* Initially 2 entries grown to 4 entries overwriting slot 1 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+       KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 4, &data));
+       KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+       /* Initially 4 entries grown to 6 entries overwriting slot 1 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* Initially 4 entries grown to 6 entries overwriting slot 3 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* Initially 6 entries grown to 8 entries overwriting slot 4 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+       KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, 8, &data));
+       KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[6], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[7], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_cal_efi_replace_by_uid(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /* Initially 1 entry grown to 2 entries overwriting slot 0 */
+       cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+       KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[0].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 2, &data));
+       KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+
+       /* Initially 2 entries grown to 4 entries overwriting slot 1 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+       KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[1].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+       KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+       /* Initially 4 entries grown to 6 entries overwriting slot 1 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[1].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* Initially 4 entries grown to 6 entries overwriting slot 3 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[3].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+       /* Initially 6 entries grown to 8 entries overwriting slot 4 */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+       KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[4].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 8, &data));
+       KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[6], sizeof(data)));
+       KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[7], sizeof(data)));
+}
+
+static void cs_amp_lib_test_cal_efi_replace_by_uid(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+       KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+       /* Replace entry matching slot 0 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[0].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Replace entry matching slot 4 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[4].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Replace entry matching slot 3 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[3].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Replace entry matching slot 5 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[5].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+}
+
+static void cs_amp_lib_test_cal_efi_replace_by_index(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+       KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+       /*
+        * Replace entry matching slot 0.
+        * data.calTarget is deliberately set different to current calTarget
+        * of the slot to check that the index forces that slot to be used.
+        */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = ~priv->cal_blob->data[0].calTarget[0];
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Replace entry matching slot 4 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = ~priv->cal_blob->data[4].calTarget[0];
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Replace entry matching slot 3 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = ~priv->cal_blob->data[3].calTarget[0];
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Replace entry matching slot 5 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = ~priv->cal_blob->data[5].calTarget[0];
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 5, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+}
+
+static void cs_amp_lib_test_cal_efi_deduplicate(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+       int i;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       /*
+        * Replace entry matching slot 0.
+        * An active entry in slot 1 for the same UID should be marked empty.
+        * Other entries are unaltered.
+        */
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[1].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, -1, &data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+
+       /*
+        * Replace entry matching slot 1.
+        * An active entry in slot 0 for the same UID should be marked empty.
+        * Other entries are unaltered.
+        */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[0].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+
+       /*
+        * Replace entry matching slot 1.
+        * An active entry in slot 3 for the same UID should be marked empty.
+        * Other entries are unaltered.
+        */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       memcpy(data.calTarget, priv->cal_blob->data[3].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[1]);
+
+       /*
+        * Worst case, all entries have the same UID
+        */
+       priv->cal_blob = NULL;
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       for (i = 0; i < priv->cal_blob->count; i++) {
+               priv->cal_blob->data[i].calTarget[0] = 0xe5e5e5e5;
+               priv->cal_blob->data[i].calTarget[1] = 0xa7a7a7a7;
+       }
+       memcpy(data.calTarget, priv->cal_blob->data[2].calTarget, sizeof(data.calTarget));
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, -1, &data));
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[0]);
+       KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[1]);
+}
+
+static void cs_amp_lib_test_cal_efi_find_free(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+       KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+       /*
+        * Slot 0 is empty.
+        * data.calTarget is set to a value that won't match any existing entry.
+        */
+       memset(&priv->cal_blob->data[0].calTime, 0, sizeof(priv->cal_blob->data[0].calTime));
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa;
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Slot 4 is empty */
+       memset(&priv->cal_blob->data[4].calTime, 0, sizeof(priv->cal_blob->data[4].calTime));
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa;
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Slot 3 is empty */
+       memset(&priv->cal_blob->data[3].calTime, 0, sizeof(priv->cal_blob->data[3].calTime));
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa;
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+       /* Replace entry matching slot 5 */
+       memset(&priv->cal_blob->data[5].calTime, 0, sizeof(priv->cal_blob->data[5].calTime));
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = 0xaaaaaaaa;
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+}
+
+static void cs_amp_lib_test_cal_efi_bad_cal_target(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+
+       /* Zero calTarget is illegal */
+       get_random_bytes(&data, sizeof(data));
+       memset(data.calTarget, 0, sizeof(data.calTarget));
+       KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, -1, -1, &data), 0);
+       KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 0, -1, &data), 0);
+       KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 0, 2, &data), 0);
+}
+
+static void cs_amp_lib_test_cal_efi_write_denied(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable_denied);
+
+       cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+       KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+
+       /* Unspecified slot */
+       KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, -1, -1, &data), 0);
+       KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+
+       /* Unspecified slot with size */
+       KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, -1, 6, &data), 0);
+       KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+
+       /* Specified slot */
+       KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 1, -1, &data), 0);
+       KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+
+       /* Specified slot with size */
+       KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 1, 6, &data), 0);
+       KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+}
+
+static void cs_amp_lib_test_cal_efi_attr_preserved(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_efi_variable);
+
+       cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+       KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+       memset(&priv->cal_blob->data[0], 0, sizeof(priv->cal_blob->data[0]));
+       get_random_bytes(&data, sizeof(data));
+
+       /* Set a non-standard attr to return from get_efi_variable() */
+       priv->efi_attr = EFI_VARIABLE_HARDWARE_ERROR_RECORD;
+
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_EQ(test, priv->efi_attr, EFI_VARIABLE_HARDWARE_ERROR_RECORD);
+}
+
+static efi_status_t cs_amp_lib_test_set_hp_efi_cal_variable(efi_char16_t *name,
+                                                           efi_guid_t *guid,
+                                                           u32 attr,
+                                                           unsigned long size,
+                                                           void *buf)
+{
+       static const efi_char16_t expected_name[] = HP_CALIBRATION_EFI_NAME;
+       static const efi_guid_t expected_guid = HP_CALIBRATION_EFI_GUID;
+       struct kunit *test = kunit_get_current_test();
+       struct cs_amp_lib_test_priv *priv = test->priv;
+
+       KUNIT_ASSERT_NOT_NULL(test, name);
+       KUNIT_ASSERT_NOT_NULL(test, guid);
+
+       if (memcmp(name, expected_name, sizeof(expected_name)) ||
+           efi_guidcmp(*guid, expected_guid))
+               return -EFI_ACCESS_DENIED;
+
+       KUNIT_ASSERT_NOT_NULL(test, buf);
+       KUNIT_ASSERT_NE(test, 0, size);
+
+       kunit_kfree(test, priv->cal_blob);
+       priv->cal_blob = kunit_kmalloc(test, size, GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
+       memcpy(priv->cal_blob, buf, size);
+       priv->efi_attr = attr;
+
+       return EFI_SUCCESS;
+}
+
+/*
+ * If the HP EFI exists it should be the one that is updated.
+ */
+static void cs_amp_lib_test_cal_efi_update_hp(struct kunit *test)
+{
+       struct cs_amp_lib_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       const struct cirrus_amp_efi_data *original_blob;
+       struct cirrus_amp_cal_data data;
+
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->get_efi_variable,
+                                  cs_amp_lib_test_get_hp_cal_efi_variable);
+       kunit_activate_static_stub(test,
+                                  cs_amp_test_hooks->set_efi_variable,
+                                  cs_amp_lib_test_set_hp_efi_cal_variable);
+
+       cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+       KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+       /* Replace entry matching slot 4 */
+       original_blob = cs_amp_lib_test_cal_blob_dup(test);
+       get_random_bytes(&data, sizeof(data));
+       data.calTarget[0] = ~priv->cal_blob->data[4].calTarget[0];
+       KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, -1, &data));
+       KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+       KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+       KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+}
+
 static void cs_amp_lib_test_spkid_lenovo_not_present(struct kunit *test)
 {
        struct cs_amp_lib_test_priv *priv = test->priv;
@@ -1072,6 +2433,28 @@ static struct kunit_case cs_amp_lib_test_cases[] = {
        KUNIT_CASE(cs_amp_lib_test_read_cal_data_test),
        KUNIT_CASE(cs_amp_lib_test_write_ambient_test),
 
+       /* Test cases for writing cal data to UEFI */
+       KUNIT_CASE(cs_amp_lib_test_create_new_cal_efi),
+       KUNIT_CASE(cs_amp_lib_test_create_new_cal_efi_indexed),
+       KUNIT_CASE(cs_amp_lib_test_create_new_cal_efi_indexed_no_max),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first_no_shrink),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed_no_shrink),
+       KUNIT_CASE(cs_amp_lib_test_grow_append_cal_efi),
+       KUNIT_CASE(cs_amp_lib_test_grow_append_cal_efi_indexed),
+       KUNIT_CASE(cs_amp_lib_test_grow_append_cal_efi_indexed_no_max),
+       KUNIT_CASE(cs_amp_lib_test_grow_cal_efi_replace_indexed),
+       KUNIT_CASE(cs_amp_lib_test_grow_cal_efi_replace_by_uid),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_replace_by_uid),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_replace_by_index),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_deduplicate),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_find_free),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_bad_cal_target),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_write_denied),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_attr_preserved),
+       KUNIT_CASE(cs_amp_lib_test_cal_efi_update_hp),
+
        /* Test cases for speaker ID */
        KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_not_present),
        KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_d0),
index 7038574e3f4b62145ca558719387d9877f34939d..d8f8b0259cd15091d0cfae307d5a30584a5d62e6 100644 (file)
@@ -727,6 +727,7 @@ EXPORT_SYMBOL_NS_GPL(cs_amp_create_debugfs, "SND_SOC_CS_AMP_LIB");
 
 static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = {
        .get_efi_variable = cs_amp_get_efi_variable,
+       .set_efi_variable = cs_amp_set_efi_variable,
        .write_cal_coeff = cs_amp_write_cal_coeff,
        .read_cal_coeff = cs_amp_read_cal_coeff,
 };