]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
firmware: cs_dsp: Add mock bin file generator for KUnit testing
authorRichard Fitzgerald <rf@opensource.cirrus.com>
Thu, 12 Dec 2024 14:37:17 +0000 (14:37 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 13 Dec 2024 13:14:40 +0000 (13:14 +0000)
Add a mock firmware file that emulates what the firmware build tools
would normally create. This will be used by KUnit tests to generate a
test bin file.

The data payload in a bin is an opaque blob, so the mock bin only needs
to generate the appropriate file header and description block for each
payload blob.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://patch.msgid.link/20241212143725.1381013-5-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/firmware/cirrus/test/Makefile
drivers/firmware/cirrus/test/cs_dsp_mock_bin.c [new file with mode: 0644]
include/linux/firmware/cirrus/cs_dsp_test_utils.h

index a67010cb6d66290270140eb6fc6b29152037383c..99aa120718f053b5ba1a971e72c38c50383dcaf6 100644 (file)
@@ -3,6 +3,7 @@
 
 cs_dsp_test_utils-objs :=      \
                cs_dsp_mock_mem_maps.o \
+               cs_dsp_mock_bin.o \
                cs_dsp_mock_regmap.o \
                cs_dsp_mock_utils.o \
                cs_dsp_mock_wmfw.o
diff --git a/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c b/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c
new file mode 100644 (file)
index 0000000..1e271cc
--- /dev/null
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// bin file builder for cs_dsp KUnit tests.
+//
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/resource.h>
+#include <kunit/test.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/cs_dsp_test_utils.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include <linux/firmware.h>
+#include <linux/math.h>
+#include <linux/overflow.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+/* Buffer large enough for bin file content */
+#define CS_DSP_MOCK_BIN_BUF_SIZE       32768
+
+KUNIT_DEFINE_ACTION_WRAPPER(vfree_action_wrapper, vfree, void *)
+
+struct cs_dsp_mock_bin_builder {
+       struct cs_dsp_test *test_priv;
+       void *buf;
+       void *write_p;
+       size_t bytes_used;
+};
+
+/**
+ * cs_dsp_mock_bin_get_firmware() - Get struct firmware wrapper for data.
+ *
+ * @builder:   Pointer to struct cs_dsp_mock_bin_builder.
+ *
+ * Return: Pointer to a struct firmware wrapper for the data.
+ */
+struct firmware *cs_dsp_mock_bin_get_firmware(struct cs_dsp_mock_bin_builder *builder)
+{
+       struct firmware *fw;
+
+       fw = kunit_kzalloc(builder->test_priv->test, sizeof(*fw), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, fw);
+
+       fw->data = builder->buf;
+       fw->size = builder->bytes_used;
+
+       return fw;
+}
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_get_firmware, "FW_CS_DSP_KUNIT_TEST_UTILS");
+
+/**
+ * cs_dsp_mock_bin_add_raw_block() - Add a data block to the bin file.
+ *
+ * @builder:           Pointer to struct cs_dsp_mock_bin_builder.
+ * @alg_ig:            Algorithm ID.
+ * @alg_ver:           Algorithm version.
+ * @type:              Type of the block.
+ * @offset:            Offset.
+ * @payload_data:      Pointer to buffer containing the payload data.
+ * @payload_len_bytes: Length of payload data in bytes.
+ */
+void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,
+                                  unsigned int alg_id, unsigned int alg_ver,
+                                  int type, unsigned int offset,
+                                  const void *payload_data, size_t payload_len_bytes)
+{
+       struct wmfw_coeff_item *item;
+       size_t bytes_needed = struct_size_t(struct wmfw_coeff_item, data, payload_len_bytes);
+
+       KUNIT_ASSERT_TRUE(builder->test_priv->test,
+                         (builder->write_p + bytes_needed) <
+                         (builder->buf + CS_DSP_MOCK_BIN_BUF_SIZE));
+
+       item = builder->write_p;
+
+       item->offset = cpu_to_le16(offset);
+       item->type = cpu_to_le16(type);
+       item->id = cpu_to_le32(alg_id);
+       item->ver = cpu_to_le32(alg_ver << 8);
+       item->len = cpu_to_le32(payload_len_bytes);
+
+       if (payload_len_bytes)
+               memcpy(item->data, payload_data, payload_len_bytes);
+
+       builder->write_p += bytes_needed;
+       builder->bytes_used += bytes_needed;
+}
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_raw_block, "FW_CS_DSP_KUNIT_TEST_UTILS");
+
+static void cs_dsp_mock_bin_add_name_or_info(struct cs_dsp_mock_bin_builder *builder,
+                                            const char *info, int type)
+{
+       size_t info_len = strlen(info);
+       char *tmp = NULL;
+
+       if (info_len % 4) {
+               /* Create a padded string with length a multiple of 4 */
+               info_len = round_up(info_len, 4);
+               tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL);
+               KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp);
+               memcpy(tmp, info, info_len);
+               info = tmp;
+       }
+
+       cs_dsp_mock_bin_add_raw_block(builder, 0, 0, WMFW_INFO_TEXT, 0, info, info_len);
+       kunit_kfree(builder->test_priv->test, tmp);
+}
+
+/**
+ * cs_dsp_mock_bin_add_info() - Add an info block to the bin file.
+ *
+ * @builder:   Pointer to struct cs_dsp_mock_bin_builder.
+ * @info:      Pointer to info string to be copied into the file.
+ *
+ * The string will be padded to a length that is a multiple of 4 bytes.
+ */
+void cs_dsp_mock_bin_add_info(struct cs_dsp_mock_bin_builder *builder,
+                             const char *info)
+{
+       cs_dsp_mock_bin_add_name_or_info(builder, info, WMFW_INFO_TEXT);
+}
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_info, "FW_CS_DSP_KUNIT_TEST_UTILS");
+
+/**
+ * cs_dsp_mock_bin_add_name() - Add a name block to the bin file.
+ *
+ * @builder:   Pointer to struct cs_dsp_mock_bin_builder.
+ * @name:      Pointer to name string to be copied into the file.
+ */
+void cs_dsp_mock_bin_add_name(struct cs_dsp_mock_bin_builder *builder,
+                             const char *name)
+{
+       cs_dsp_mock_bin_add_name_or_info(builder, name, WMFW_NAME_TEXT);
+}
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_name, "FW_CS_DSP_KUNIT_TEST_UTILS");
+
+/**
+ * cs_dsp_mock_bin_add_patch() - Add a patch data block to the bin file.
+ *
+ * @builder:           Pointer to struct cs_dsp_mock_bin_builder.
+ * @alg_ig:            Algorithm ID for the patch.
+ * @alg_ver:           Algorithm version for the patch.
+ * @mem_region:                Memory region for the patch.
+ * @reg_addr_offset:   Offset to start of data in register addresses.
+ * @payload_data:      Pointer to buffer containing the payload data.
+ * @payload_len_bytes: Length of payload data in bytes.
+ */
+void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,
+                              unsigned int alg_id, unsigned int alg_ver,
+                              int mem_region, unsigned int reg_addr_offset,
+                              const void *payload_data, size_t payload_len_bytes)
+{
+       /* Payload length must be a multiple of 4 */
+       KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);
+
+       cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,
+                                     mem_region, reg_addr_offset,
+                                     payload_data, payload_len_bytes);
+}
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch, "FW_CS_DSP_KUNIT_TEST_UTILS");
+
+/**
+ * cs_dsp_mock_bin_init() - Initialize a struct cs_dsp_mock_bin_builder.
+ *
+ * @priv:              Pointer to struct cs_dsp_test.
+ * @format_version:    Required bin format version.
+ * @fw_version:                Firmware version to put in bin file.
+ *
+ * Return: Pointer to created struct cs_dsp_mock_bin_builder.
+ */
+struct cs_dsp_mock_bin_builder *cs_dsp_mock_bin_init(struct cs_dsp_test *priv,
+                                                    int format_version,
+                                                    unsigned int fw_version)
+{
+       struct cs_dsp_mock_bin_builder *builder;
+       struct wmfw_coeff_hdr *hdr;
+
+       builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder);
+       builder->test_priv = priv;
+
+       builder->buf = vmalloc(CS_DSP_MOCK_BIN_BUF_SIZE);
+       KUNIT_ASSERT_NOT_NULL(priv->test, builder->buf);
+       kunit_add_action_or_reset(priv->test, vfree_action_wrapper, builder->buf);
+
+       /* Create header */
+       hdr = builder->buf;
+       memcpy(hdr->magic, "WMDR", sizeof(hdr->magic));
+       hdr->len = cpu_to_le32(offsetof(struct wmfw_coeff_hdr, data));
+       hdr->ver = cpu_to_le32(fw_version | (format_version << 24));
+       hdr->core_ver = cpu_to_le32(((u32)priv->dsp->type << 24) | priv->dsp->rev);
+
+       builder->write_p = hdr->data;
+       builder->bytes_used = offsetof(struct wmfw_coeff_hdr, data);
+
+       return builder;
+}
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_init, "FW_CS_DSP_KUNIT_TEST_UTILS");
index fde7e95a33e9abcc9eca61a594ea2644f93e1cf3..4f87a908ab4f6ba752677620e15342e696af12ca 100644 (file)
@@ -78,6 +78,7 @@ struct cs_dsp_mock_xm_header {
 };
 
 struct cs_dsp_mock_wmfw_builder;
+struct cs_dsp_mock_bin_builder;
 
 extern const unsigned int cs_dsp_mock_adsp2_32bit_sysbase;
 extern const unsigned int cs_dsp_mock_adsp2_16bit_sysbase;
@@ -121,6 +122,23 @@ void cs_dsp_mock_regmap_drop_bytes(struct cs_dsp_test *priv,
 void cs_dsp_mock_regmap_drop_system_regs(struct cs_dsp_test *priv);
 bool cs_dsp_mock_regmap_is_dirty(struct cs_dsp_test *priv, bool drop_system_regs);
 
+struct cs_dsp_mock_bin_builder *cs_dsp_mock_bin_init(struct cs_dsp_test *priv,
+                                                    int format_version,
+                                                    unsigned int fw_version);
+void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,
+                                  unsigned int alg_id, unsigned int alg_ver,
+                                  int type, unsigned int offset,
+                                  const void *payload_data, size_t payload_len_bytes);
+void cs_dsp_mock_bin_add_info(struct cs_dsp_mock_bin_builder *builder,
+                             const char *info);
+void cs_dsp_mock_bin_add_name(struct cs_dsp_mock_bin_builder *builder,
+                             const char *name);
+void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,
+                              unsigned int alg_id, unsigned int alg_ver,
+                              int mem_region, unsigned int reg_addr_offset,
+                              const void *payload_data, size_t payload_len_bytes);
+struct firmware *cs_dsp_mock_bin_get_firmware(struct cs_dsp_mock_bin_builder *builder);
+
 struct cs_dsp_mock_wmfw_builder *cs_dsp_mock_wmfw_init(struct cs_dsp_test *priv,
                                                       int format_version);
 void cs_dsp_mock_wmfw_add_raw_block(struct cs_dsp_mock_wmfw_builder *builder,