Path: blob/master/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c
26444 views
// SPDX-License-Identifier: GPL-2.0-only1//2// bin file builder for cs_dsp KUnit tests.3//4// Copyright (C) 2024 Cirrus Logic, Inc. and5// Cirrus Logic International Semiconductor Ltd.67#include <kunit/resource.h>8#include <kunit/test.h>9#include <linux/firmware/cirrus/cs_dsp.h>10#include <linux/firmware/cirrus/cs_dsp_test_utils.h>11#include <linux/firmware/cirrus/wmfw.h>12#include <linux/firmware.h>13#include <linux/math.h>14#include <linux/overflow.h>15#include <linux/string.h>16#include <linux/vmalloc.h>1718/* Buffer large enough for bin file content */19#define CS_DSP_MOCK_BIN_BUF_SIZE 327682021KUNIT_DEFINE_ACTION_WRAPPER(vfree_action_wrapper, vfree, void *)2223struct cs_dsp_mock_bin_builder {24struct cs_dsp_test *test_priv;25void *buf;26void *write_p;27size_t bytes_used;28};2930/**31* cs_dsp_mock_bin_get_firmware() - Get struct firmware wrapper for data.32*33* @builder: Pointer to struct cs_dsp_mock_bin_builder.34*35* Return: Pointer to a struct firmware wrapper for the data.36*/37struct firmware *cs_dsp_mock_bin_get_firmware(struct cs_dsp_mock_bin_builder *builder)38{39struct firmware *fw;4041fw = kunit_kzalloc(builder->test_priv->test, sizeof(*fw), GFP_KERNEL);42KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, fw);4344fw->data = builder->buf;45fw->size = builder->bytes_used;4647return fw;48}49EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_get_firmware, "FW_CS_DSP_KUNIT_TEST_UTILS");5051/**52* cs_dsp_mock_bin_add_raw_block() - Add a data block to the bin file.53*54* @builder: Pointer to struct cs_dsp_mock_bin_builder.55* @alg_id: Algorithm ID.56* @alg_ver: Algorithm version.57* @type: Type of the block.58* @offset: Offset.59* @payload_data: Pointer to buffer containing the payload data.60* @payload_len_bytes: Length of payload data in bytes.61*/62void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,63unsigned int alg_id, unsigned int alg_ver,64int type, unsigned int offset,65const void *payload_data, size_t payload_len_bytes)66{67struct wmfw_coeff_item *item;68size_t bytes_needed = struct_size_t(struct wmfw_coeff_item, data, payload_len_bytes);6970KUNIT_ASSERT_TRUE(builder->test_priv->test,71(builder->write_p + bytes_needed) <72(builder->buf + CS_DSP_MOCK_BIN_BUF_SIZE));7374item = builder->write_p;7576item->offset = cpu_to_le16(offset);77item->type = cpu_to_le16(type);78item->id = cpu_to_le32(alg_id);79item->ver = cpu_to_le32(alg_ver << 8);80item->len = cpu_to_le32(payload_len_bytes);8182if (payload_len_bytes)83memcpy(item->data, payload_data, payload_len_bytes);8485builder->write_p += bytes_needed;86builder->bytes_used += bytes_needed;87}88EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_raw_block, "FW_CS_DSP_KUNIT_TEST_UTILS");8990static void cs_dsp_mock_bin_add_name_or_info(struct cs_dsp_mock_bin_builder *builder,91const char *info, int type)92{93size_t info_len = strlen(info);94char *tmp = NULL;9596if (info_len % 4) {97/* Create a padded string with length a multiple of 4 */98size_t copy_len = info_len;99info_len = round_up(info_len, 4);100tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL);101KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp);102memcpy(tmp, info, copy_len);103info = tmp;104}105106cs_dsp_mock_bin_add_raw_block(builder, 0, 0, WMFW_INFO_TEXT, 0, info, info_len);107kunit_kfree(builder->test_priv->test, tmp);108}109110/**111* cs_dsp_mock_bin_add_info() - Add an info block to the bin file.112*113* @builder: Pointer to struct cs_dsp_mock_bin_builder.114* @info: Pointer to info string to be copied into the file.115*116* The string will be padded to a length that is a multiple of 4 bytes.117*/118void cs_dsp_mock_bin_add_info(struct cs_dsp_mock_bin_builder *builder,119const char *info)120{121cs_dsp_mock_bin_add_name_or_info(builder, info, WMFW_INFO_TEXT);122}123EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_info, "FW_CS_DSP_KUNIT_TEST_UTILS");124125/**126* cs_dsp_mock_bin_add_name() - Add a name block to the bin file.127*128* @builder: Pointer to struct cs_dsp_mock_bin_builder.129* @name: Pointer to name string to be copied into the file.130*/131void cs_dsp_mock_bin_add_name(struct cs_dsp_mock_bin_builder *builder,132const char *name)133{134cs_dsp_mock_bin_add_name_or_info(builder, name, WMFW_NAME_TEXT);135}136EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_name, "FW_CS_DSP_KUNIT_TEST_UTILS");137138/**139* cs_dsp_mock_bin_add_patch() - Add a patch data block to the bin file.140*141* @builder: Pointer to struct cs_dsp_mock_bin_builder.142* @alg_id: Algorithm ID for the patch.143* @alg_ver: Algorithm version for the patch.144* @mem_region: Memory region for the patch.145* @reg_addr_offset: Offset to start of data in register addresses.146* @payload_data: Pointer to buffer containing the payload data.147* @payload_len_bytes: Length of payload data in bytes.148*/149void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,150unsigned int alg_id, unsigned int alg_ver,151int mem_region, unsigned int reg_addr_offset,152const void *payload_data, size_t payload_len_bytes)153{154/* Payload length must be a multiple of 4 */155KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);156157cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,158mem_region, reg_addr_offset,159payload_data, payload_len_bytes);160}161EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch, "FW_CS_DSP_KUNIT_TEST_UTILS");162163/**164* cs_dsp_mock_bin_init() - Initialize a struct cs_dsp_mock_bin_builder.165*166* @priv: Pointer to struct cs_dsp_test.167* @format_version: Required bin format version.168* @fw_version: Firmware version to put in bin file.169*170* Return: Pointer to created struct cs_dsp_mock_bin_builder.171*/172struct cs_dsp_mock_bin_builder *cs_dsp_mock_bin_init(struct cs_dsp_test *priv,173int format_version,174unsigned int fw_version)175{176struct cs_dsp_mock_bin_builder *builder;177struct wmfw_coeff_hdr *hdr;178179KUNIT_ASSERT_LE(priv->test, format_version, 0xff);180KUNIT_ASSERT_LE(priv->test, fw_version, 0xffffff);181182builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL);183KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder);184builder->test_priv = priv;185186builder->buf = vmalloc(CS_DSP_MOCK_BIN_BUF_SIZE);187KUNIT_ASSERT_NOT_NULL(priv->test, builder->buf);188kunit_add_action_or_reset(priv->test, vfree_action_wrapper, builder->buf);189190/* Create header */191hdr = builder->buf;192memcpy(hdr->magic, "WMDR", sizeof(hdr->magic));193hdr->len = cpu_to_le32(offsetof(struct wmfw_coeff_hdr, data));194hdr->ver = cpu_to_le32(fw_version | (format_version << 24));195hdr->core_ver = cpu_to_le32(((u32)priv->dsp->type << 24) | priv->dsp->rev);196197builder->write_p = hdr->data;198builder->bytes_used = offsetof(struct wmfw_coeff_hdr, data);199200return builder;201}202EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_init, "FW_CS_DSP_KUNIT_TEST_UTILS");203204205