Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/firmware/cirrus/test/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 95 kB image not shown  

Quelle  cs_dsp_test_bin.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/firmware.h>
#include <linux/math.h>
#include <linux/random.h>
#include <linux/regmap.h>

/*
 * Test method is:
 *
 * 1) Create a mock regmap in cache-only mode so that all writes will be cached.
 * 2) Create a XM header with an algorithm list in the cached regmap.
 * 3) Create dummy wmfw file to satisfy cs_dsp.
 * 4) Create bin file content.
 * 5) Call cs_dsp_power_up() with the bin file.
 * 6) Readback the cached value of registers that should have been written and
 *    check they have the correct value.
 * 7) All the registers that are expected to have been written are dropped from
 *    the cache (including the XM header). This should leave the cache clean.
 * 8) If the cache is still dirty there have been unexpected writes.
 *
 * There are multiple different schemes used for addressing across
 * ADSP2 and Halo Core DSPs:
 *
 *  dsp words: The addressing scheme used by the DSP, pointers and lengths
 * in DSP memory use this. A memory region (XM, YM, ZM) is
 * also required to create a unique DSP memory address.
 *  registers: Addresses in the register map. Older ADSP2 devices have
 * 16-bit registers with an address stride of 1. Newer ADSP2
 * devices have 32-bit registers with an address stride of 2.
 * Halo Core devices have 32-bit registers with a stride of 4.
 *  unpacked: Registers that have a 1:1 mapping to DSP words
 *  packed: Registers that pack multiple DSP words more efficiently into
 * multiple 32-bit registers. Because of this the relationship
 * between a packed _register_ address and the corresponding
 * _dsp word_ address is different from unpacked registers.
 * Packed registers can only be accessed as a group of
 * multiple registers, therefore can only read/write a group
 * of multiple DSP words.
 * Packed registers only exist on Halo Core DSPs.
 *
 * Addresses can also be relative to the start of an algorithm, and this
 * can be expressed in dsp words, register addresses, or bytes.
 */


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

struct cs_dsp_test_local {
 struct cs_dsp_mock_bin_builder *bin_builder;
 struct cs_dsp_mock_wmfw_builder *wmfw_builder;
 struct firmware *wmfw;
};

struct bin_test_param {
 const char *name;
 int mem_type;
 unsigned int offset_words;
 int alg_idx;
};

static const struct cs_dsp_mock_alg_def bin_test_mock_algs[] = {
 {
  .id = 0xfafa,
  .ver = 0x100000,
  .xm_size_words = 164,
  .ym_size_words = 164,
  .zm_size_words = 164,
 },
 {
  .id = 0xfbfb,
  .ver = 0x100000,
  .xm_size_words = 99,
  .ym_size_words = 99,
  .zm_size_words = 99,
 },
 {
  .id = 0xc321,
  .ver = 0x100000,
  .xm_size_words = 120,
  .ym_size_words = 120,
  .zm_size_words = 120,
 },
 {
  .id = 0xb123,
  .ver = 0x100000,
  .xm_size_words = 96,
  .ym_size_words = 96,
  .zm_size_words = 96,
 },
};

/*
 * Convert number of DSP words to number of packed registers rounded
 * down to the nearest register.
 * There are 3 registers for every 4 packed words.
 */

static unsigned int _num_words_to_num_packed_regs(unsigned int num_dsp_words)
{
 return (num_dsp_words * 3) / 4;
}

/* bin file that patches a single DSP word */
static void bin_patch_one_word(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
 u32 reg_val, payload_data;
 unsigned int alg_base_words, reg_addr;
 struct firmware *fw;

 get_random_bytes(&payload_data, sizeof(payload_data));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);

 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      param->offset_words * reg_inc_per_word,
      &payload_data, sizeof(payload_data));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     ((alg_base_words + param->offset_words) * reg_inc_per_word);
 reg_val = 0;
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr,
     ®_val, sizeof(reg_val)),
   0);
 KUNIT_EXPECT_EQ(test, reg_val, payload_data);

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_regmap_drop_range(priv, reg_addr, reg_addr + reg_inc_per_word - 1);
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);

 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/* bin file with a single payload that patches consecutive words */
static void bin_patch_one_multiword(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
 u32 payload_data[16], readback[16];
 unsigned int alg_base_words, reg_addr;
 struct firmware *fw;

 static_assert(ARRAY_SIZE(readback) == ARRAY_SIZE(payload_data));

 get_random_bytes(&payload_data, sizeof(payload_data));
 memset(readback, 0, sizeof(readback));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);

 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      param->offset_words * reg_inc_per_word,
      payload_data, sizeof(payload_data));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     ((alg_base_words + param->offset_words) * reg_inc_per_word);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, sizeof(payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_regmap_drop_range(priv, reg_addr,
          reg_addr + (reg_inc_per_word * ARRAY_SIZE(payload_data)));
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/* bin file with a multiple one-word payloads that patch consecutive words */
static void bin_patch_multi_oneword(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
 u32 payload_data[16], readback[16];
 unsigned int alg_base_words, reg_addr;
 struct firmware *fw;
 int i;

 static_assert(ARRAY_SIZE(readback) == ARRAY_SIZE(payload_data));

 get_random_bytes(&payload_data, sizeof(payload_data));
 memset(readback, 0, sizeof(readback));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);

 /* Add one payload per word */
 for (i = 0; i < ARRAY_SIZE(payload_data); ++i) {
  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[param->alg_idx].id,
       bin_test_mock_algs[param->alg_idx].ver,
       param->mem_type,
       (param->offset_words + i) * reg_inc_per_word,
       &payload_data[i], sizeof(payload_data[i]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
    0);

 /* Content of registers should match payload_data */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     ((alg_base_words + param->offset_words) * reg_inc_per_word);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, sizeof(payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 cs_dsp_mock_regmap_drop_range(priv, reg_addr,
          reg_addr + (reg_inc_per_word * ARRAY_SIZE(payload_data)));
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * bin file with a multiple one-word payloads that patch a block of consecutive
 * words but the payloads are not in address order.
 */

static void bin_patch_multi_oneword_unordered(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
 u32 payload_data[16], readback[16];
 static const u8 word_order[] = { 10, 2, 12, 4, 0, 11, 6, 1, 3, 15, 5, 13, 8, 7, 9, 14 };
 unsigned int alg_base_words, reg_addr;
 struct firmware *fw;
 int i;

 static_assert(ARRAY_SIZE(readback) == ARRAY_SIZE(payload_data));
 static_assert(ARRAY_SIZE(word_order) == ARRAY_SIZE(payload_data));

 get_random_bytes(&payload_data, sizeof(payload_data));
 memset(readback, 0, sizeof(readback));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);

 /* Add one payload per word */
 for (i = 0; i < ARRAY_SIZE(word_order); ++i) {
  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[param->alg_idx].id,
       bin_test_mock_algs[param->alg_idx].ver,
       param->mem_type,
       (param->offset_words + word_order[i]) *
       reg_inc_per_word,
       &payload_data[word_order[i]], sizeof(payload_data[0]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     ((alg_base_words + param->offset_words) * reg_inc_per_word);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, payload_data, sizeof(payload_data));

 /* Drop expected writes and the cache should then be clean */
 cs_dsp_mock_xm_header_drop_from_regmap_cache(priv);
 cs_dsp_mock_regmap_drop_range(priv, reg_addr,
          reg_addr + (reg_inc_per_word * ARRAY_SIZE(payload_data)));
 KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true));
}

/*
 * bin file with a multiple one-word payloads. The payloads are not in address
 * order and collectively do not patch a contiguous block of memory.
 */

static void bin_patch_multi_oneword_sparse_unordered(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
 static const u8 word_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
 };
 u32 payload_data[44];
 unsigned int alg_base_words, reg_addr;
 struct firmware *fw;
 u32 reg_val;
 int i;

 static_assert(ARRAY_SIZE(word_offsets) == ARRAY_SIZE(payload_data));

 get_random_bytes(&payload_data, sizeof(payload_data));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);

 /* Add one payload per word */
 for (i = 0; i < ARRAY_SIZE(word_offsets); ++i) {
  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[param->alg_idx].id,
       bin_test_mock_algs[param->alg_idx].ver,
       param->mem_type,
       word_offsets[i] * reg_inc_per_word,
       &payload_data[i], sizeof(payload_data[i]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 for (i = 0; i < ARRAY_SIZE(word_offsets); ++i) {
  reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
      ((alg_base_words + word_offsets[i]) * reg_inc_per_word);
  reg_val = 0;
  KUNIT_EXPECT_EQ(test,
    regmap_raw_read(priv->dsp->regmap, reg_addr, ®_val,
      sizeof(reg_val)),
    0);
  KUNIT_EXPECT_MEMEQ(test, ®_val, &payload_data[i], sizeof(reg_val));

  /* Drop expected writes from the cache */
  cs_dsp_mock_regmap_drop_range(priv, reg_addr, reg_addr + reg_inc_per_word - 1);
 }

 /* 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));
}

/*
 * bin file that patches a single DSP word in each of the memory regions
 * of one algorithm.
 */

static void bin_patch_one_word_multiple_mems(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
 unsigned int alg_xm_base_words, alg_ym_base_words, alg_zm_base_words;
 unsigned int reg_addr;
 u32 payload_data[3];
 struct firmware *fw;
 u32 reg_val;

 get_random_bytes(&payload_data, sizeof(payload_data));

 alg_xm_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       WMFW_ADSP2_XM);
 alg_ym_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       WMFW_ADSP2_YM);

 if (cs_dsp_mock_has_zm(priv)) {
  alg_zm_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       WMFW_ADSP2_ZM);
 } else {
  alg_zm_base_words = 0;
 }

 /* Add words to XM, YM and ZM */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      WMFW_ADSP2_XM,
      param->offset_words * reg_inc_per_word,
      &payload_data[0], sizeof(payload_data[0]));

 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      WMFW_ADSP2_YM,
      param->offset_words * reg_inc_per_word,
      &payload_data[1], sizeof(payload_data[1]));

 if (cs_dsp_mock_has_zm(priv)) {
  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[param->alg_idx].id,
       bin_test_mock_algs[param->alg_idx].ver,
       WMFW_ADSP2_ZM,
       param->offset_words * reg_inc_per_word,
       &payload_data[2], sizeof(payload_data[2]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM) +
     ((alg_xm_base_words + param->offset_words) * reg_inc_per_word);
 reg_val = 0;
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, ®_val, sizeof(reg_val)),
   0);
 KUNIT_EXPECT_EQ(test, reg_val, payload_data[0]);

 cs_dsp_mock_regmap_drop_range(priv, reg_addr, reg_addr + reg_inc_per_word - 1);

 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM) +
     ((alg_ym_base_words + param->offset_words) * reg_inc_per_word);
 reg_val = 0;
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, ®_val, sizeof(reg_val)),
   0);
 KUNIT_EXPECT_EQ(test, reg_val, payload_data[1]);

 cs_dsp_mock_regmap_drop_range(priv, reg_addr, reg_addr + reg_inc_per_word - 1);

 if (cs_dsp_mock_has_zm(priv)) {
  reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_ZM) +
      ((alg_zm_base_words + param->offset_words) * reg_inc_per_word);
  reg_val = 0;
  KUNIT_EXPECT_EQ(test,
    regmap_raw_read(priv->dsp->regmap, reg_addr, ®_val,
      sizeof(reg_val)),
    0);
  KUNIT_EXPECT_EQ(test, reg_val, payload_data[2]);

  /* Drop expected writes from the cache */
  cs_dsp_mock_regmap_drop_range(priv, reg_addr, reg_addr + reg_inc_per_word - 1);
 }

 /* 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));
}

/*
 * bin file that patches a single DSP word in multiple algorithms.
 */

static void bin_patch_one_word_multiple_algs(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 u32 payload_data[ARRAY_SIZE(bin_test_mock_algs)];
 unsigned int alg_base_words;
 unsigned int reg_inc_per_word, reg_addr;
 struct firmware *fw;
 u32 reg_val;
 int i;

 get_random_bytes(&payload_data, sizeof(payload_data));

 /* Add one payload per algorithm */
 for (i = 0; i < ARRAY_SIZE(bin_test_mock_algs); ++i) {
  reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);

  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[i].id,
       bin_test_mock_algs[i].ver,
       param->mem_type,
       param->offset_words * reg_inc_per_word,
       &payload_data[i], sizeof(payload_data[i]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 for (i = 0; i < ARRAY_SIZE(bin_test_mock_algs); ++i) {
  alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
        bin_test_mock_algs[i].id,
        param->mem_type);
  reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
  reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
      ((alg_base_words + param->offset_words) * reg_inc_per_word);
  reg_val = 0;
  KUNIT_EXPECT_EQ(test,
    regmap_raw_read(priv->dsp->regmap, reg_addr, ®_val,
      sizeof(reg_val)),
    0);
  KUNIT_EXPECT_EQ(test, reg_val, payload_data[i]);

  /* Drop expected writes from the cache */
  cs_dsp_mock_regmap_drop_range(priv, reg_addr, reg_addr + reg_inc_per_word - 1);
 }

 /* 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));
}

/*
 * bin file that patches a single DSP word in multiple algorithms.
 * The algorithms are not patched in the same order they appear in the XM header.
 */

static void bin_patch_one_word_multiple_algs_unordered(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 static const u8 alg_order[] = { 3, 0, 2, 1 };
 u32 payload_data[ARRAY_SIZE(bin_test_mock_algs)];
 unsigned int alg_base_words;
 unsigned int reg_inc_per_word, reg_addr;
 struct firmware *fw;
 u32 reg_val;
 int i, alg_idx;

 static_assert(ARRAY_SIZE(alg_order) == ARRAY_SIZE(bin_test_mock_algs));

 get_random_bytes(&payload_data, sizeof(payload_data));

 /* Add one payload per algorithm */
 for (i = 0; i < ARRAY_SIZE(bin_test_mock_algs); ++i) {
  alg_idx = alg_order[i];
  reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);

  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[alg_idx].id,
       bin_test_mock_algs[alg_idx].ver,
       param->mem_type,
       param->offset_words * reg_inc_per_word,
       &payload_data[i], sizeof(payload_data[i]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 for (i = 0; i < ARRAY_SIZE(bin_test_mock_algs); ++i) {
  alg_idx = alg_order[i];
  alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
        bin_test_mock_algs[alg_idx].id,
        param->mem_type);
  reg_inc_per_word = cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv);
  reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
      ((alg_base_words + param->offset_words) * reg_inc_per_word);
  reg_val = 0;
  KUNIT_EXPECT_EQ(test,
    regmap_raw_read(priv->dsp->regmap, reg_addr, ®_val,
      sizeof(reg_val)),
    0);
  KUNIT_EXPECT_EQ(test, reg_val, payload_data[i]);

  /* Drop expected writes from the cache */
  cs_dsp_mock_regmap_drop_range(priv, reg_addr, reg_addr + reg_inc_per_word - 1);
 }

 /* 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));
}

/* bin file that patches a single packed block of DSP words */
static void bin_patch_1_packed(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 u32 packed_payload[3], readback[3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);

 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      packed_payload, sizeof(packed_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of registers should match payload_data */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback,
     sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payload, sizeof(packed_payload));

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

/*
 * Patch data that is one word longer than a packed block using one
 * packed block followed by one unpacked word.
 */

static void bin_patch_1_packed_1_single_trailing(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[1], readback[3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);

 /* Patch packed block */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 /* ... and the unpacked word following that */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 4) - alg_base_words) * 4,
      unpacked_payload, sizeof(unpacked_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

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

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (patch_pos_words + 4) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

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

 /* 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));
}

/*
 * Patch data that is two words longer than a packed block using one
 * packed block followed by two blocks of one unpacked word.
 */

static void bin_patch_1_packed_2_single_trailing(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payloads[2], readback[3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payloads));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payloads, sizeof(unpacked_payloads));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);

 /* Patch packed block */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 /* ... and the unpacked words following that */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 4) - alg_base_words) * 4,
      &unpacked_payloads[0], sizeof(unpacked_payloads[0]));

 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 5) - alg_base_words) * 4,
      &unpacked_payloads[1], sizeof(unpacked_payloads[1]));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payloads */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (patch_pos_words + 4) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payloads)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payloads, sizeof(unpacked_payloads));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payloads));

 /* 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));
}

/*
 * Patch data that is three words longer than a packed block using one
 * packed block followed by three blocks of one unpacked word.
 */

static void bin_patch_1_packed_3_single_trailing(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payloads[3], readback[3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payloads));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payloads, sizeof(unpacked_payloads));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);

 /* Patch packed block */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 /* ... and the unpacked words following that */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 4) - alg_base_words) * 4,
      &unpacked_payloads[0], sizeof(unpacked_payloads[0]));

 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 5) - alg_base_words) * 4,
      &unpacked_payloads[1], sizeof(unpacked_payloads[1]));

 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 6) - alg_base_words) * 4,
      &unpacked_payloads[2], sizeof(unpacked_payloads[2]));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payloads */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (patch_pos_words + 4) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payloads)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payloads, sizeof(unpacked_payloads));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payloads));

 /* 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));
}

/*
 * Patch data that is two words longer than a packed block using one
 * packed block followed by a block of two unpacked words.
 */

static void bin_patch_1_packed_2_trailing(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[2], readback[3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);

 /* Patch packed block */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 /* ... and the unpacked words following that */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 4) - alg_base_words) * 4,
      unpacked_payload, sizeof(unpacked_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (patch_pos_words + 4) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload));

 /* 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));
}

/*
 * Patch data that is three words longer than a packed block using one
 * packed block followed by a block of three unpacked words.
 */

static void bin_patch_1_packed_3_trailing(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[3], readback[3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);

 /* Patch packed block */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 /* ... and the unpacked words following that */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((patch_pos_words + 4) - alg_base_words) * 4,
      unpacked_payload, sizeof(unpacked_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (patch_pos_words + 4) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload));

 /* 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));
}

/*
 * Patch data that starts one word before a packed boundary using one
 * unpacked word followed by one packed block.
 */

static void bin_patch_1_single_leading_1_packed(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[1], readback[3];
 unsigned int alg_base_words, packed_patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));
 memset(readback, 0, sizeof(readback));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round packed start word up to a packed boundary and move to the next boundary */
 packed_patch_pos_words = round_up(alg_base_words + param->offset_words, 4) + 4;

 /* Patch the leading unpacked word */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 1) - alg_base_words) * 4,
      unpacked_payload, sizeof(unpacked_payload));
 /* ... then the packed block */
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(packed_patch_pos_words);
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (packed_patch_pos_words - 1) * 4;
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload));

 /* 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));
}

/*
 * Patch data that starts two words before a packed boundary using two
 * unpacked words followed by one packed block.
 */

static void bin_patch_2_single_leading_1_packed(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[2], readback[3];
 unsigned int alg_base_words, packed_patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round packed start word up to a packed boundary and move to the next boundary */
 packed_patch_pos_words = round_up(alg_base_words + param->offset_words, 4) + 4;

 /* Patch the leading unpacked words */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 2) - alg_base_words) * 4,
      &unpacked_payload[0], sizeof(unpacked_payload[0]));
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 1) - alg_base_words) * 4,
      &unpacked_payload[1], sizeof(unpacked_payload[1]));
 /* ... then the packed block */
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(packed_patch_pos_words);
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (packed_patch_pos_words - 2) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload));

 /* 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));
}

/*
 * Patch data that starts two words before a packed boundary using one
 * block of two unpacked words followed by one packed block.
 */

static void bin_patch_2_leading_1_packed(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[2], readback[3];
 unsigned int alg_base_words, packed_patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round packed start word up to a packed boundary and move to the next boundary */
 packed_patch_pos_words = round_up(alg_base_words + param->offset_words, 4) + 4;

 /* Patch the leading unpacked words */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 2) - alg_base_words) * 4,
      unpacked_payload, sizeof(unpacked_payload));
 /* ... then the packed block */
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(packed_patch_pos_words);
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (packed_patch_pos_words - 2) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload));

 /* 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));
}

/*
 * Patch data that starts three words before a packed boundary using three
 * unpacked words followed by one packed block.
 */

static void bin_patch_3_single_leading_1_packed(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[3], readback[3];
 unsigned int alg_base_words, packed_patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round packed start word up to a packed boundary and move to the next boundary */
 packed_patch_pos_words = round_up(alg_base_words + param->offset_words, 4) + 4;

 /* Patch the leading unpacked words */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 3) - alg_base_words) * 4,
      &unpacked_payload[0], sizeof(unpacked_payload[0]));
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 2) - alg_base_words) * 4,
      &unpacked_payload[1], sizeof(unpacked_payload[1]));
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 1) - alg_base_words) * 4,
      &unpacked_payload[2], sizeof(unpacked_payload[2]));
 /* ... then the packed block */
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(packed_patch_pos_words);
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (packed_patch_pos_words - 3) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload));

 /* 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));
}

/*
 * Patch data that starts three words before a packed boundary using one
 * block of three unpacked words followed by one packed block.
 */

static void bin_patch_3_leading_1_packed(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 unsigned int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type);
 u32 packed_payload[3], unpacked_payload[3], readback[3];
 unsigned int alg_base_words, packed_patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int reg_addr;
 struct firmware *fw;

 static_assert(sizeof(readback) == sizeof(packed_payload));
 static_assert(sizeof(readback) >= sizeof(unpacked_payload));

 get_random_bytes(packed_payload, sizeof(packed_payload));
 get_random_bytes(unpacked_payload, sizeof(unpacked_payload));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round packed start word up to a packed boundary and move to the next boundary */
 packed_patch_pos_words = round_up(alg_base_words + param->offset_words, 4) + 4;

 /* Patch the leading unpacked words */
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      unpacked_mem_type,
      ((packed_patch_pos_words - 3) - alg_base_words) * 4,
      unpacked_payload, sizeof(unpacked_payload));
 /* ... then the packed block */
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(packed_patch_pos_words);
 cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
      bin_test_mock_algs[param->alg_idx].id,
      bin_test_mock_algs[param->alg_idx].ver,
      param->mem_type,
      (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4,
      &packed_payload, sizeof(packed_payload));

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, &packed_payload, sizeof(packed_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(packed_payload));

 /* Content of unpacked registers should match unpacked_payload */
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type) +
     (packed_patch_pos_words - 3) * 4;
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, &readback,
     sizeof(unpacked_payload)),
   0);
 KUNIT_EXPECT_MEMEQ(test, &readback, unpacked_payload, sizeof(unpacked_payload));

 /* Drop expected writes from the cache */
 cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload));

 /* 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));
}

/* bin file with a multiple payloads that each patch one packed block. */
static void bin_patch_multi_onepacked(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 u32 packed_payloads[8][3], readback[8][3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int payload_offset;
 unsigned int reg_addr;
 struct firmware *fw;
 int i;

 static_assert(sizeof(readback) == sizeof(packed_payloads));

 get_random_bytes(packed_payloads, sizeof(packed_payloads));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);

 /* Add one payload per packed block */
 for (i = 0; i < ARRAY_SIZE(packed_payloads); ++i) {
  patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words + (i * 4));
  payload_offset = (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4;
  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[param->alg_idx].id,
       bin_test_mock_algs[param->alg_idx].ver,
       param->mem_type,
       payload_offset,
       &packed_payloads[i], sizeof(packed_payloads[i]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payloads */
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payloads, sizeof(packed_payloads));

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

/*
 * bin file with a multiple payloads that each patch one packed block.
 * The payloads are not in address order.
 */

static void bin_patch_multi_onepacked_unordered(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 static const u8 payload_order[] = { 4, 3, 6, 1, 0, 7, 5, 2 };
 u32 packed_payloads[8][3], readback[8][3];
 unsigned int alg_base_words, patch_pos_words;
 unsigned int alg_base_in_packed_regs, patch_pos_in_packed_regs;
 unsigned int payload_offset;
 unsigned int reg_addr;
 struct firmware *fw;
 int i;

 static_assert(ARRAY_SIZE(payload_order) == ARRAY_SIZE(packed_payloads));
 static_assert(sizeof(readback) == sizeof(packed_payloads));

 get_random_bytes(packed_payloads, sizeof(packed_payloads));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Round patch start word up to a packed boundary */
 patch_pos_words = round_up(alg_base_words + param->offset_words, 4);

 /* Add one payload per packed block */
 for (i = 0; i < ARRAY_SIZE(payload_order); ++i) {
  patch_pos_in_packed_regs =
   _num_words_to_num_packed_regs(patch_pos_words + (payload_order[i] * 4));
  payload_offset = (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4;
  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[param->alg_idx].id,
       bin_test_mock_algs[param->alg_idx].ver,
       param->mem_type,
       payload_offset,
       &packed_payloads[payload_order[i]],
       sizeof(packed_payloads[0]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content in registers should match the order of data in packed_payloads */
 patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);
 reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type) +
     (patch_pos_in_packed_regs * 4);
 memset(readback, 0, sizeof(readback));
 KUNIT_EXPECT_EQ(test,
   regmap_raw_read(priv->dsp->regmap, reg_addr, readback, sizeof(readback)),
   0);
 KUNIT_EXPECT_MEMEQ(test, readback, packed_payloads, sizeof(packed_payloads));

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

/*
 * bin file with a multiple payloads that each patch one packed block.
 * The payloads are not in address order. The patched memory is not contiguous.
 */

static void bin_patch_multi_onepacked_sparse_unordered(struct kunit *test)
{
 struct cs_dsp_test *priv = test->priv;
 const struct bin_test_param *param = test->param_value;
 static const u8 word_offsets[] = { 60, 24, 76, 4, 40, 52, 48, 36, 12 };
 u32 packed_payloads[9][3], readback[3];
 unsigned int alg_base_words, alg_base_in_packed_regs;
 unsigned int patch_pos_words, patch_pos_in_packed_regs, payload_offset;
 unsigned int reg_addr;
 struct firmware *fw;
 int i;

 static_assert(ARRAY_SIZE(word_offsets) == ARRAY_SIZE(packed_payloads));
 static_assert(sizeof(readback) == sizeof(packed_payloads[0]));

 get_random_bytes(packed_payloads, sizeof(packed_payloads));

 alg_base_words = cs_dsp_mock_xm_header_get_alg_base_in_words(priv,
       bin_test_mock_algs[param->alg_idx].id,
       param->mem_type);
 alg_base_in_packed_regs = _num_words_to_num_packed_regs(alg_base_words);

 /* Add one payload per packed block */
 for (i = 0; i < ARRAY_SIZE(word_offsets); ++i) {
  /* Round patch start word up to a packed boundary */
  patch_pos_words = round_up(alg_base_words + word_offsets[i], 4);
  patch_pos_in_packed_regs = _num_words_to_num_packed_regs(patch_pos_words);
  payload_offset = (patch_pos_in_packed_regs - alg_base_in_packed_regs) * 4;
  cs_dsp_mock_bin_add_patch(priv->local->bin_builder,
       bin_test_mock_algs[param->alg_idx].id,
       bin_test_mock_algs[param->alg_idx].ver,
       param->mem_type,
       payload_offset,
       &packed_payloads[i],
       sizeof(packed_payloads[0]));
 }

 fw = cs_dsp_mock_bin_get_firmware(priv->local->bin_builder);
 KUNIT_ASSERT_EQ(test,
   cs_dsp_power_up(priv->dsp, priv->local->wmfw, "mock_wmfw",
     fw, "mock_bin""misc"),
   0);

 /* Content of packed registers should match packed_payloads */
 for (i = 0; i < ARRAY_SIZE(word_offsets); ++i) {
--> --------------------

--> maximum size reached

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

Messung V0.5
C=95 H=90 G=92

¤ Dauer der Verarbeitung: 0.14 Sekunden  ¤

*© 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.