lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251016104242.157325-12-rf@opensource.cirrus.com>
Date: Thu, 16 Oct 2025 11:42:42 +0100
From: Richard Fitzgerald <rf@...nsource.cirrus.com>
To: broonie@...nel.org, tiwai@...e.com
Cc: linux-sound@...r.kernel.org, linux-kernel@...r.kernel.org,
        patches@...nsource.cirrus.com
Subject: [PATCH 11/11] ASoC: cs-amp-lib-test: Add test cases for cs_amp_set_efi_calibration_data()

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@...nsource.cirrus.com>
---
 include/sound/cs-amp-lib.h         |    5 +
 sound/soc/codecs/cs-amp-lib-test.c | 1399 +++++++++++++++++++++++++++-
 sound/soc/codecs/cs-amp-lib.c      |    1 +
 3 files changed, 1397 insertions(+), 8 deletions(-)

diff --git a/include/sound/cs-amp-lib.h b/include/sound/cs-amp-lib.h
index 4c8b84ee087e..8eee4ce9eefe 100644
--- a/include/sound/cs-amp-lib.h
+++ b/include/sound/cs-amp-lib.h
@@ -70,6 +70,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,
diff --git a/sound/soc/codecs/cs-amp-lib-test.c b/sound/soc/codecs/cs-amp-lib-test.c
index d3419f48297e..7fa6aabc746a 100644
--- a/sound/soc/codecs/cs-amp-lib-test.c
+++ b/sound/soc/codecs/cs-amp-lib-test.c
@@ -20,6 +20,10 @@
 #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)
@@ -28,6 +32,10 @@
 #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 *)
 
@@ -36,6 +44,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 {
@@ -49,6 +58,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;
@@ -69,9 +92,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)
@@ -199,9 +228,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;
 
@@ -223,9 +251,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;
@@ -790,6 +865,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;
@@ -1073,6 +2434,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),
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index 3f352ecad3e0..1c53328d7165 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -701,6 +701,7 @@ EXPORT_SYMBOL_NS_GPL(cs_amp_get_vendor_spkid, "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,
 };
-- 
2.47.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ