Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cs_dsp_test_wmfw.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
//
// KUnit tests for cs_dsp.
//
// Copyright (C) 2024 Cirrus Logic, Inc. and
//                    Cirrus Logic International Semiconductor Ltd.
//

#include <kunit/device.h>
#include <kunit/resource.h>
#include <kunit/test.h>
#include <linux/build_bug.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/random.h>
#include <linux/regmap.h>
#include <linux/string.h>
#include <linux/vmalloc.h>

/*
 * Test method is:
 *
 * 1) Create a mock regmap in cache-only mode so that all writes will be cached.
 * 2) Create dummy wmfw file.
 * 3) Call cs_dsp_power_up() with the bin file.
 * 4) Readback the cached value of registers that should have been written and
 *    check they have the correct value.
 * 5) All the registers that are expected to have been written are dropped from
 *    the cache. This should leave the cache clean.
 * 6) If the cache is still dirty there have been unexpected writes.
 */


KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *)
KUNIT_DEFINE_ACTION_WRAPPER(_vfree_wrapper, vfree, void *)
KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *)

struct cs_dsp_test_local {
 struct cs_dsp_mock_xm_header *xm_header;
 struct cs_dsp_mock_wmfw_builder *wmfw_builder;
 int wmfw_version;
};

struct cs_dsp_wmfw_test_param {
 unsigned int num_blocks;
 int mem_type;
};

static const struct cs_dsp_mock_alg_def cs_dsp_wmfw_test_mock_algs[] = {
 {
  .id = 0xfafa,
  .ver = 0x100000,
  .xm_size_words = 164,
  .ym_size_words = 164,
  .zm_size_words = 164,
 },
};

/*
 * wmfw that writes the XM header.
 * cs_dsp always reads this back from unpacked XM.
 */

static void wmfw_write_xm_header_unpacked(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 unsigned int reg_addr;
 u8 *readback;

 /* XM header payload was added to wmfw by test case init function */

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 /* Read raw so endianness and register width don't matter */
 readback = kunit_kzalloc(test, local->xm_header->blob_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);

 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     local->xm_header->blob_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, local->xm_header->blob_data,
      local->xm_header->blob_size_bytes);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/* Write one payload of length param->num_blocks */
static void wmfw_write_one_payload(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int reg_addr;
 u8 *payload_data, *readback;
 unsigned int mem_offset_dsp_words = 0;
 unsigned int payload_size_bytes;

 payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type);

 /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */
 do {
  payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type);
 } while (payload_size_bytes % 4);

 payload_data = kunit_kmalloc(test, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);
 get_random_bytes(payload_data, payload_size_bytes);

 readback = kunit_kzalloc(test, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);

 /* Tests on XM must be after the XM header */
 if (param->mem_type == WMFW_ADSP2_XM)
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32);

 /* Add a single payload */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     param->mem_type, mem_offset_dsp_words,
     payload_data, payload_size_bytes);

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type);
 reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words;
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes);
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/* Write several smallest possible payloads for the given memory type */
static void wmfw_write_multiple_oneblock_payloads(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int reg_addr;
 u8 *payload_data, *readback;
 unsigned int mem_offset_dsp_words = 0;
 unsigned int payload_size_bytes, payload_size_dsp_words;
 const unsigned int num_payloads = param->num_blocks;
 int i;

 /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */
 payload_size_dsp_words = 0;
 payload_size_bytes = 0;
 do {
  payload_size_dsp_words += cs_dsp_mock_reg_block_length_dsp_words(priv,
           param->mem_type);
  payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type);
 } while (payload_size_bytes % 4);

 payload_data = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);

 readback = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);

 get_random_bytes(payload_data, num_payloads * payload_size_bytes);

 /* Tests on XM must be after the XM header */
 if (param->mem_type == WMFW_ADSP2_XM)
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / payload_size_bytes;

 /* Add multiple payloads of one block each */
 for (i = 0; i < num_payloads; ++i) {
  cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
      param->mem_type,
      mem_offset_dsp_words + (i * payload_size_dsp_words),
      &payload_data[i * payload_size_bytes],
      payload_size_bytes);
 }

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type);
 reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words;
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     num_payloads * payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, num_payloads * payload_size_bytes);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, num_payloads * payload_size_bytes);
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write several smallest possible payloads of the given memory type
 * in reverse address order
 */

static void wmfw_write_multiple_oneblock_payloads_reverse(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int reg_addr;
 u8 *payload_data, *readback;
 unsigned int mem_offset_dsp_words = 0;
 unsigned int payload_size_bytes, payload_size_dsp_words;
 const unsigned int num_payloads = param->num_blocks;
 int i;

 /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */
 payload_size_dsp_words = 0;
 payload_size_bytes = 0;
 do {
  payload_size_dsp_words += cs_dsp_mock_reg_block_length_dsp_words(priv,
           param->mem_type);
  payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type);
 } while (payload_size_bytes % 4);

 payload_data = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);

 readback = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);

 get_random_bytes(payload_data, num_payloads * payload_size_bytes);

 /* Tests on XM must be after the XM header */
 if (param->mem_type == WMFW_ADSP2_XM)
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / payload_size_bytes;

 /* Add multiple payloads of one block each */
 for (i = num_payloads - 1; i >= 0; --i) {
  cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
      param->mem_type,
      mem_offset_dsp_words + (i * payload_size_dsp_words),
      &payload_data[i * payload_size_bytes],
      payload_size_bytes);
 }

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type);
 reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words;
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     num_payloads * payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, num_payloads * payload_size_bytes);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, num_payloads * payload_size_bytes);
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write multiple payloads of length param->num_blocks.
 * The payloads are not in address order and collectively do not patch
 * a contiguous block of memory.
 */

static void wmfw_write_multiple_payloads_sparse_unordered(struct kunit *test)
{
 static const unsigned int random_offsets[] = {
  11, 69, 59, 61, 32, 75, 4, 38, 70, 13, 79, 47, 46, 53, 18, 44,
  54, 35, 51, 21, 26, 45, 27, 41, 66, 2, 17, 56, 40, 9, 8, 20,
  29, 19, 63, 42, 12, 16, 43, 3, 5, 55, 52, 22
 };
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int reg_addr;
 u8 *payload_data, *readback;
 unsigned int mem_offset_dsp_words = 0;
 unsigned int payload_size_bytes, payload_size_dsp_words;
 const int num_payloads = ARRAY_SIZE(random_offsets);
 int i;

 payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type);
 payload_size_dsp_words = param->num_blocks *
     cs_dsp_mock_reg_block_length_dsp_words(priv, param->mem_type);

 /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */
 do {
  payload_size_dsp_words += cs_dsp_mock_reg_block_length_dsp_words(priv,
           param->mem_type);
  payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type);
 } while (payload_size_bytes % 4);

 payload_data = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);
 get_random_bytes(payload_data, payload_size_bytes);

 readback = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);

 /* Tests on XM must be after the XM header */
 if (param->mem_type == WMFW_ADSP2_XM)
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / payload_size_bytes;

 /* Add multiple payloads of one block each at "random" locations */
 for (i = 0; i < num_payloads; ++i) {
  unsigned int offset = random_offsets[i] * payload_size_dsp_words;

  cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
      param->mem_type,
      mem_offset_dsp_words + offset,
      &payload_data[i * payload_size_bytes],
      payload_size_bytes);
 }

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 for (i = 0; i < num_payloads; ++i) {
  unsigned int offset_num_regs = (random_offsets[i] * payload_size_bytes) /
      regmap_get_val_bytes(priv->dsp->regmap);
  reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type);
  reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
  reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words;
  KUNIT_EXPECT_EQ(test,
    regmap_raw_read(priv->dsp->regmap, reg_addr,
      &readback[i * payload_size_bytes],
      payload_size_bytes),
    0);

  cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes);
 }

 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/* Write the whole of PM in a single unpacked payload */
static void wmfw_write_all_unpacked_pm(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int reg_addr;
 u8 *payload_data, *readback;
 unsigned int payload_size_bytes;

 payload_size_bytes = cs_dsp_mock_size_of_region(priv->dsp, WMFW_ADSP2_PM);
 payload_data = vmalloc(payload_size_bytes);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);
 kunit_add_action_or_reset(priv->test, _vfree_wrapper, payload_data);

 readback = vmalloc(payload_size_bytes);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);
 kunit_add_action_or_reset(priv->test, _vfree_wrapper, readback);
 memset(readback, 0, payload_size_bytes);

 /* Add a single PM payload */
 get_random_bytes(payload_data, payload_size_bytes);
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     WMFW_ADSP2_PM, 0,
     payload_data, payload_size_bytes);

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_PM);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes);
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/* Write the whole of PM in a single packed payload */
static void wmfw_write_all_packed_pm(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int reg_addr;
 u8 *payload_data, *readback;
 unsigned int payload_size_bytes;

 payload_size_bytes = cs_dsp_mock_size_of_region(priv->dsp, WMFW_HALO_PM_PACKED);
 payload_data = vmalloc(payload_size_bytes);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);
 kunit_add_action_or_reset(priv->test, _vfree_wrapper, payload_data);

 readback = vmalloc(payload_size_bytes);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);
 kunit_add_action_or_reset(priv->test, _vfree_wrapper, readback);
 memset(readback, 0, payload_size_bytes);

 /* Add a single PM payload */
 get_random_bytes(payload_data, payload_size_bytes);
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     WMFW_HALO_PM_PACKED, 0,
     payload_data, payload_size_bytes);

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_HALO_PM_PACKED);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes);
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write a series of payloads to various unpacked memory regions.
 * The payloads are of various lengths and offsets, driven by the
 * payload_defs table. The offset and length are both given as a
 * number of minimum-sized register blocks to keep the maths simpler.
 * (Where a minimum-sized register block is the smallest number of
 * registers that contain a whole number of DSP words.)
 */

static void wmfw_write_multiple_unpacked_mem(struct kunit *test)
{
 static const struct {
  int mem_type;
  unsigned int offset_num_blocks;
  unsigned int num_blocks;
 } payload_defs[] = {
  { WMFW_ADSP2_PM, 11, 60 },
  { WMFW_ADSP2_ZM, 69, 8 },
  { WMFW_ADSP2_YM, 32, 74 },
  { WMFW_ADSP2_XM, 70, 38 },
  { WMFW_ADSP2_PM, 84, 48 },
  { WMFW_ADSP2_XM, 46, 18 },
  { WMFW_ADSP2_PM, 0,  8 },
  { WMFW_ADSP2_YM, 0, 30 },
  { WMFW_ADSP2_PM, 160, 50 },
  { WMFW_ADSP2_ZM, 21, 26 },
 };
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int payload_size_bytes, offset_num_dsp_words;
 unsigned int reg_addr, offset_bytes, offset_num_regs;
 void **payload_data;
 void *readback;
 int i, ret;

 payload_data = kunit_kcalloc(test, ARRAY_SIZE(payload_defs), sizeof(*payload_data),
         GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);

 for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) {
  payload_size_bytes = payload_defs[i].num_blocks *
         cs_dsp_mock_reg_block_length_bytes(priv,
         payload_defs[i].mem_type);

  payload_data[i] = kunit_kmalloc(test, payload_size_bytes, GFP_KERNEL);
  KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data[i]);
  get_random_bytes(payload_data[i], payload_size_bytes);

  offset_num_dsp_words = payload_defs[i].offset_num_blocks *
           cs_dsp_mock_reg_block_length_dsp_words(priv,
          payload_defs[i].mem_type);
  cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
      payload_defs[i].mem_type,
      offset_num_dsp_words,
      payload_data[i],
      payload_size_bytes);
 }

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) {
  payload_size_bytes = payload_defs[i].num_blocks *
         cs_dsp_mock_reg_block_length_bytes(priv,
         payload_defs[i].mem_type);

  readback = kunit_kzalloc(test, payload_size_bytes, GFP_KERNEL);
  KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);

  offset_bytes = payload_defs[i].offset_num_blocks *
          cs_dsp_mock_reg_block_length_bytes(priv, payload_defs[i].mem_type);
  offset_num_regs = offset_bytes / regmap_get_val_bytes(priv->dsp->regmap);
  reg_addr = cs_dsp_mock_base_addr_for_mem(priv, payload_defs[i].mem_type);
  reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
  ret = regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes);
  KUNIT_EXPECT_EQ_MSG(test, ret, 0, "%s @%u num:%u\n",
        cs_dsp_mem_region_name(payload_defs[i].mem_type),
        payload_defs[i].offset_num_blocks, payload_defs[i].num_blocks);
  KUNIT_EXPECT_MEMEQ_MSG(test, readback, payload_data[i], payload_size_bytes,
           "%s @%u num:%u\n",
           cs_dsp_mem_region_name(payload_defs[i].mem_type),
           payload_defs[i].offset_num_blocks,
           payload_defs[i].num_blocks);

  kunit_kfree(test, readback);

  cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes);
 }

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write a series of payloads to various packed and unpacked memory regions.
 * The payloads are of various lengths and offsets, driven by the
 * payload_defs table. The offset and length are both given as a
 * number of minimum-sized register blocks to keep the maths simpler.
 * (Where a minimum-sized register block is the smallest number of
 * registers that contain a whole number of DSP words.)
 */

static void wmfw_write_multiple_packed_unpacked_mem(struct kunit *test)
{
 static const struct {
  int mem_type;
  unsigned int offset_num_blocks;
  unsigned int num_blocks;
 } payload_defs[] = {
  { WMFW_HALO_PM_PACKED, 11, 60 },
  { WMFW_ADSP2_YM, 69, 8 },
  { WMFW_HALO_YM_PACKED, 32, 74 },
  { WMFW_HALO_XM_PACKED, 70, 38 },
  { WMFW_HALO_PM_PACKED, 84, 48 },
  { WMFW_HALO_XM_PACKED, 46, 18 },
  { WMFW_HALO_PM_PACKED, 0,  8 },
  { WMFW_HALO_YM_PACKED, 0, 30 },
  { WMFW_HALO_PM_PACKED, 160, 50 },
  { WMFW_ADSP2_XM, 21, 26 },
 };
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 struct firmware *wmfw;
 unsigned int payload_size_bytes, offset_num_dsp_words;
 unsigned int reg_addr, offset_bytes, offset_num_regs;
 void **payload_data;
 void *readback;
 int i, ret;

 payload_data = kunit_kcalloc(test, ARRAY_SIZE(payload_defs), sizeof(*payload_data),
         GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);

 for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) {
  payload_size_bytes = payload_defs[i].num_blocks *
         cs_dsp_mock_reg_block_length_bytes(priv,
         payload_defs[i].mem_type);

  payload_data[i] = kunit_kmalloc(test, payload_size_bytes, GFP_KERNEL);
  KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data[i]);
  get_random_bytes(payload_data[i], payload_size_bytes);

  offset_num_dsp_words = payload_defs[i].offset_num_blocks *
           cs_dsp_mock_reg_block_length_dsp_words(priv,
          payload_defs[i].mem_type);
  cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
      payload_defs[i].mem_type,
      offset_num_dsp_words,
      payload_data[i],
      payload_size_bytes);
 }

 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);

 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) {
  payload_size_bytes = payload_defs[i].num_blocks *
         cs_dsp_mock_reg_block_length_bytes(priv,
         payload_defs[i].mem_type);

  readback = kunit_kzalloc(test, payload_size_bytes, GFP_KERNEL);
  KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);

  offset_bytes = payload_defs[i].offset_num_blocks *
          cs_dsp_mock_reg_block_length_bytes(priv, payload_defs[i].mem_type);
  offset_num_regs = offset_bytes / regmap_get_val_bytes(priv->dsp->regmap);
  reg_addr = cs_dsp_mock_base_addr_for_mem(priv, payload_defs[i].mem_type);
  reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
  ret = regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes);
  KUNIT_EXPECT_EQ_MSG(test, ret, 0, "%s @%u num:%u\n",
        cs_dsp_mem_region_name(payload_defs[i].mem_type),
        payload_defs[i].offset_num_blocks,
        payload_defs[i].num_blocks);
  KUNIT_EXPECT_MEMEQ_MSG(test, readback, payload_data[i], payload_size_bytes,
           "%s @%u num:%u\n",
           cs_dsp_mem_region_name(payload_defs[i].mem_type),
           payload_defs[i].offset_num_blocks,
           payload_defs[i].num_blocks);

  kunit_kfree(test, readback);

  cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes);
 }

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is one word longer than a packed block multiple,
 * using one packed payload followed by one unpacked word.
 */

static void wmfw_write_packed_1_unpacked_trailing(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int mem_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[1];
 unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);
 packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block;

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM) {
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32);

  /* Round up to multiple of packed block length */
  mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block);
 }

 /* Add a single packed payload */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type, mem_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);
 /*
 * Add payload of one unpacked word to DSP memory right after
 * the packed payload words.
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words,
     unpacked_payload_data, sizeof(unpacked_payload_data));

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked word was written correctly and drop
 * it from the regmap cache. The unpacked payload is offset within
 * unpacked register space by the number of DSP words that were
 * written in the packed payload.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) *
      cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is two words longer than a packed block multiple,
 * using one packed payload followed by one payload of two unpacked words.
 */

static void wmfw_write_packed_2_unpacked_trailing(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int mem_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[2];
 unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);
 packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block;

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM) {
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32);

  /* Round up to multiple of packed block length */
  mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block);
 }

 /* Add a single packed payload */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type, mem_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);
 /*
 * Add payload of two unpacked words to DSP memory right after
 * the packed payload words.
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words,
     unpacked_payload_data, sizeof(unpacked_payload_data));

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked words were written correctly and drop
 * them from the regmap cache. The unpacked payload is offset
 * within unpacked register space by the number of DSP words
 * that were written in the packed payload.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) *
      cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is three words longer than a packed block multiple,
 * using one packed payload followed by one payload of three unpacked words.
 */

static void wmfw_write_packed_3_unpacked_trailing(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int mem_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[3];
 unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);
 packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block;

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM) {
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32);

  /* Round up to multiple of packed block length */
  mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block);
 }

 /* Add a single packed payload */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type, mem_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);
 /*
 * Add payload of three unpacked words to DSP memory right after
 * the packed payload words.
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words,
     unpacked_payload_data, sizeof(unpacked_payload_data));

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked words were written correctly and drop
 * them from the regmap cache. The unpacked payload is offset
 * within unpacked register space by the number of DSP words
 * that were written in the packed payload.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) *
      cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is two words longer than a packed block multiple,
 * using one packed payload followed by two payloads of one unpacked word each.
 */

static void wmfw_write_packed_2_single_unpacked_trailing(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int mem_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[2];
 unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);
 packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block;

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM) {
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32);

  /* Round up to multiple of packed block length */
  mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block);
 }

 /* Add a single packed payload */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type, mem_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);
 /*
 * Add two unpacked words to DSP memory right after the packed
 * payload words. Each unpacked word in its own payload.
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words,
     &unpacked_payload_data[0],
     sizeof(unpacked_payload_data[0]));
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words + 1,
     &unpacked_payload_data[1],
     sizeof(unpacked_payload_data[1]));

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);

 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked words were written correctly and drop
 * them from the regmap cache. The unpacked words are offset
 * within unpacked register space by the number of DSP words
 * that were written in the packed payload.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) *
      cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is three words longer than a packed block multiple,
 * using one packed payload followed by three payloads of one unpacked word each.
 */

static void wmfw_write_packed_3_single_unpacked_trailing(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int mem_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[3];
 unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
     cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);
 packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block;

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM) {
  mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32);

  /* Round up to multiple of packed block length */
  mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block);
 }

 /* Add a single packed payload */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type, mem_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);
 /*
 * Add three unpacked words to DSP memory right after the packed
 * payload words. Each unpacked word in its own payload.
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words,
     &unpacked_payload_data[0],
     sizeof(unpacked_payload_data[0]));
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words + 1,
     &unpacked_payload_data[1],
     sizeof(unpacked_payload_data[1]));
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     mem_offset_dsp_words + packed_payload_size_dsp_words + 2,
     &unpacked_payload_data[2],
     sizeof(unpacked_payload_data[2]));

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);
 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked words were written correctly and drop
 * them from the regmap cache. The unpacked words are offset
 * within unpacked register space by the number of DSP words
 * that were written in the packed payload.
 */

 offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) *
      cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is one word longer than a packed block multiple,
 * and does not start on a packed alignment. Use one unpacked word
 * followed by a packed payload.
 */

static void wmfw_write_packed_1_unpacked_leading(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int packed_payload_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[1];
 unsigned int packed_payload_size_bytes;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM)
  packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes /
         sizeof(u32);
 /*
 * Leave space for an unaligned word before the packed block and
 * round the packed block start to multiple of packed block length.
 */

 packed_payload_offset_dsp_words += 1;
 packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words,
        dsp_words_per_packed_block);

 /* Add a single unpacked word right before the first word of packed data */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     packed_payload_offset_dsp_words - 1,
     unpacked_payload_data, sizeof(unpacked_payload_data));

 /* Add payload of packed data to the DSP memory after the unpacked word. */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type,
     packed_payload_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);
 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked word was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = ((packed_payload_offset_dsp_words - 1) / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is two words longer than a packed block multiple,
 * and does not start on a packed alignment. Use one payload of two unpacked
 * words followed by a packed payload.
 */

static void wmfw_write_packed_2_unpacked_leading(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int packed_payload_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[2];
 unsigned int packed_payload_size_bytes;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM)
  packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes /
         sizeof(u32);
 /*
 * Leave space for two unaligned words before the packed block and
 * round the packed block start to multiple of packed block length.
 */

 packed_payload_offset_dsp_words += 2;
 packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words,
        dsp_words_per_packed_block);

 /*
 * Add two unpacked words as a single payload right before the
 * first word of packed data
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     packed_payload_offset_dsp_words - 2,
     unpacked_payload_data, sizeof(unpacked_payload_data));

 /* Add payload of packed data to the DSP memory after the unpacked words. */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type,
     packed_payload_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);
 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked words were written correctly and drop
 * them from the regmap cache.
 */

 offset_num_regs = ((packed_payload_offset_dsp_words - 2) / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is three words longer than a packed block multiple,
 * and does not start on a packed alignment. Use one payload of three unpacked
 * words followed by a packed payload.
 */

static void wmfw_write_packed_3_unpacked_leading(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int packed_payload_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[3];
 unsigned int packed_payload_size_bytes;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM)
  packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes /
         sizeof(u32);
 /*
 * Leave space for three unaligned words before the packed block and
 * round the packed block start to multiple of packed block length.
 */

 packed_payload_offset_dsp_words += 3;
 packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words,
        dsp_words_per_packed_block);

 /*
 * Add three unpacked words as a single payload right before the
 * first word of packed data
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     packed_payload_offset_dsp_words - 3,
     unpacked_payload_data, sizeof(unpacked_payload_data));

 /* Add payload of packed data to the DSP memory after the unpacked words. */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type,
     packed_payload_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);
 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked words were written correctly and drop
 * them from the regmap cache.
 */

 offset_num_regs = ((packed_payload_offset_dsp_words - 3) / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is two words longer than a packed block multiple,
 * and does not start on a packed alignment. Use two payloads of one unpacked
 * word each, followed by a packed payload.
 */

static void wmfw_write_packed_2_single_unpacked_leading(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int packed_payload_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[2];
 unsigned int packed_payload_size_bytes;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM)
  packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes /
         sizeof(u32);
 /*
 * Leave space for two unaligned words before the packed block and
 * round the packed block start to multiple of packed block length.
 */

 packed_payload_offset_dsp_words += 2;
 packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words,
        dsp_words_per_packed_block);

 /*
 * Add two unpacked words as two payloads each containing a single
 * unpacked word.
 */

 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     packed_payload_offset_dsp_words - 2,
     &unpacked_payload_data[0],
     sizeof(unpacked_payload_data[0]));
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     unpacked_mem_type,
     packed_payload_offset_dsp_words - 1,
     &unpacked_payload_data[1],
     sizeof(unpacked_payload_data[1]));

 /* Add payload of packed data to the DSP memory after the unpacked words. */
 cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
     packed_mem_type,
     packed_payload_offset_dsp_words,
     packed_payload_data, packed_payload_size_bytes);

 /* Download the wmfw */
 wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder);
 KUNIT_EXPECT_EQ(test,
   cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
   0);
 /*
 * Check that the packed payload was written correctly and drop
 * it from the regmap cache.
 */

 offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) *
     cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     packed_payload_size_bytes),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes);

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes);

 /*
 * Check that the unpacked words were written correctly and drop
 * them from the regmap cache.
 */

 offset_num_regs = ((packed_payload_offset_dsp_words - 2) / dsp_words_per_unpacked_block) *
     cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type);
 reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(unpacked_payload_data)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data));

 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * Write XM/YM data that is three words longer than a packed block multiple,
 * and does not start on a packed alignment. Use three payloads of one unpacked
 * word each, followed by a packed payload.
 */

static void wmfw_write_packed_3_single_unpacked_leading(struct kunit *test)
{
 const struct cs_dsp_wmfw_test_param *param = test->param_value;
 struct cs_dsp_test *priv = test->priv;
 struct cs_dsp_test_local *local = priv->local;
 int packed_mem_type = param->mem_type;
 int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 unsigned int dsp_words_per_packed_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type);
 unsigned int dsp_words_per_unpacked_block =
  cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type);
 unsigned int packed_payload_offset_dsp_words = 0;
 struct firmware *wmfw;
 unsigned int reg_addr;
 void *packed_payload_data, *readback;
 u32 unpacked_payload_data[3];
 unsigned int packed_payload_size_bytes;
 unsigned int offset_num_regs;

 packed_payload_size_bytes = param->num_blocks *
        cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type);

 packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL);
 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data);
 get_random_bytes(packed_payload_data, packed_payload_size_bytes);

 get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data));

 readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL);

 /* Tests on XM must be after the XM header */
 if (unpacked_mem_type == WMFW_ADSP2_XM)
  packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes /
         sizeof(u32);
 /*
 * Leave space for two unaligned words before the packed block and
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=94 G=93

¤ Dauer der Verarbeitung: 0.8 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge