// 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 #include #include #include #include #include #include #include #include #include #include /* * 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 * 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 three 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 - 3, &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 - 2, &unpacked_payload_data[1], sizeof(unpacked_payload_data[1])); cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, unpacked_mem_type, packed_payload_offset_dsp_words - 1, &unpacked_payload_data[2], sizeof(unpacked_payload_data[2])); /* 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)); } /* Load a wmfw containing multiple info blocks */ static void wmfw_load_with_info(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; char *infobuf; const unsigned int payload_size_bytes = 48; int ret; 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); /* Add a couple of info blocks at the start of the wmfw */ cs_dsp_mock_wmfw_add_info(local->wmfw_builder, "This is a timestamp"); cs_dsp_mock_wmfw_add_info(local->wmfw_builder, "This is some more info"); /* Add a single payload */ cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, WMFW_ADSP2_YM, 0, payload_data, payload_size_bytes); /* Add a bigger info block then another small one*/ infobuf = kunit_kzalloc(test, 512, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, infobuf); for (; strlcat(infobuf, "Waffle{Blah}\n", 512) < 512;) ; cs_dsp_mock_wmfw_add_info(local->wmfw_builder, infobuf); cs_dsp_mock_wmfw_add_info(local->wmfw_builder, "Another block of info"); /* Add another payload */ cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, WMFW_ADSP2_YM, 64, payload_data, payload_size_bytes); wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); ret = cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"); KUNIT_EXPECT_EQ_MSG(test, ret, 0, "cs_dsp_power_up failed: %d\n", ret); /* Check first payload was written */ reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM); 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); /* Check second payload was written */ reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * 64; 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); } static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp, int wmfw_version) { struct cs_dsp_test *priv; struct cs_dsp_test_local *local; struct device *test_dev; int ret; priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; local = kunit_kzalloc(test, sizeof(struct cs_dsp_test_local), GFP_KERNEL); if (!local) return -ENOMEM; priv->test = test; priv->dsp = dsp; test->priv = priv; priv->local = local; priv->local->wmfw_version = wmfw_version; /* Create dummy struct device */ test_dev = kunit_device_register(test, "cs_dsp_test_drv"); if (IS_ERR(test_dev)) return PTR_ERR(test_dev); dsp->dev = get_device(test_dev); if (!dsp->dev) return -ENODEV; ret = kunit_add_action_or_reset(test, _put_device_wrapper, dsp->dev); if (ret) return ret; dev_set_drvdata(dsp->dev, priv); /* Allocate regmap */ ret = cs_dsp_mock_regmap_init(priv); if (ret) return ret; /* * There must always be a XM header with at least 1 algorithm, so create * a dummy one that tests can use and extract it to a data payload. */ local->xm_header = cs_dsp_create_mock_xm_header(priv, cs_dsp_wmfw_test_mock_algs, ARRAY_SIZE(cs_dsp_wmfw_test_mock_algs)); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->xm_header); local->wmfw_builder = cs_dsp_mock_wmfw_init(priv, priv->local->wmfw_version); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->wmfw_builder); /* Add dummy XM header payload to wmfw */ cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, WMFW_ADSP2_XM, 0, local->xm_header->blob_data, local->xm_header->blob_size_bytes); /* Init cs_dsp */ dsp->client_ops = kunit_kzalloc(test, sizeof(*dsp->client_ops), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp->client_ops); switch (dsp->type) { case WMFW_ADSP2: ret = cs_dsp_adsp2_init(dsp); break; case WMFW_HALO: ret = cs_dsp_halo_init(dsp); break; default: KUNIT_FAIL(test, "Untested DSP type %d\n", dsp->type); return -EINVAL; } if (ret) return ret; /* Automatically call cs_dsp_remove() when test case ends */ return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); } static int cs_dsp_wmfw_test_halo_init(struct kunit *test) { struct cs_dsp *dsp; /* Fill in cs_dsp and initialize */ dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL); if (!dsp) return -ENOMEM; dsp->num = 1; dsp->type = WMFW_HALO; dsp->mem = cs_dsp_mock_halo_dsp1_regions; dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_halo_dsp1_region_sizes); dsp->base = cs_dsp_mock_halo_core_base; dsp->base_sysinfo = cs_dsp_mock_halo_sysinfo_base; return cs_dsp_wmfw_test_common_init(test, dsp, 3); } static int cs_dsp_wmfw_test_adsp2_32bit_init(struct kunit *test, int wmfw_ver) { struct cs_dsp *dsp; /* Fill in cs_dsp and initialize */ dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL); if (!dsp) return -ENOMEM; dsp->num = 1; dsp->type = WMFW_ADSP2; dsp->rev = 1; dsp->mem = cs_dsp_mock_adsp2_32bit_dsp1_regions; dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_32bit_dsp1_region_sizes); dsp->base = cs_dsp_mock_adsp2_32bit_sysbase; return cs_dsp_wmfw_test_common_init(test, dsp, wmfw_ver); } static int cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init(struct kunit *test) { return cs_dsp_wmfw_test_adsp2_32bit_init(test, 0); } static int cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init(struct kunit *test) { return cs_dsp_wmfw_test_adsp2_32bit_init(test, 1); } static int cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init(struct kunit *test) { return cs_dsp_wmfw_test_adsp2_32bit_init(test, 2); } static int cs_dsp_wmfw_test_adsp2_16bit_init(struct kunit *test, int wmfw_ver) { struct cs_dsp *dsp; /* Fill in cs_dsp and initialize */ dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL); if (!dsp) return -ENOMEM; dsp->num = 1; dsp->type = WMFW_ADSP2; dsp->rev = 0; dsp->mem = cs_dsp_mock_adsp2_16bit_dsp1_regions; dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_16bit_dsp1_region_sizes); dsp->base = cs_dsp_mock_adsp2_16bit_sysbase; return cs_dsp_wmfw_test_common_init(test, dsp, wmfw_ver); } static int cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init(struct kunit *test) { return cs_dsp_wmfw_test_adsp2_16bit_init(test, 0); } static int cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init(struct kunit *test) { return cs_dsp_wmfw_test_adsp2_16bit_init(test, 1); } static int cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init(struct kunit *test) { return cs_dsp_wmfw_test_adsp2_16bit_init(test, 2); } static void cs_dsp_mem_param_desc(const struct cs_dsp_wmfw_test_param *param, char *desc) { snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s num_blocks:%u", cs_dsp_mem_region_name(param->mem_type), param->num_blocks); } static const struct cs_dsp_wmfw_test_param adsp2_all_num_blocks_param_cases[] = { { .mem_type = WMFW_ADSP2_PM, .num_blocks = 1 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 2 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 3 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 4 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 5 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 6 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 12 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 13 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 14 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 15 }, { .mem_type = WMFW_ADSP2_PM, .num_blocks = 16 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 1 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 2 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 3 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 4 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 5 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 6 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 12 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 13 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 14 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 15 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 16 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 1 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 2 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 3 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 4 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 5 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 6 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 12 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 13 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 14 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 15 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 16 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 1 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 2 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 3 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 4 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 5 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 6 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 12 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 13 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 14 }, { .mem_type = WMFW_ADSP2_ZM, .num_blocks = 15 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 16 }, }; KUNIT_ARRAY_PARAM(adsp2_all_num_blocks, adsp2_all_num_blocks_param_cases, cs_dsp_mem_param_desc); static const struct cs_dsp_wmfw_test_param halo_all_num_blocks_param_cases[] = { { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 1 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 2 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 3 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 4 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 5 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 6 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 12 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 13 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 14 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 15 }, { .mem_type = WMFW_HALO_PM_PACKED, .num_blocks = 16 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 1 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 2 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 3 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 4 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 5 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 6 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 12 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 13 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 14 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 15 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 16 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 1 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 2 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 3 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 4 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 5 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 6 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 12 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 13 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 14 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 15 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 16 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 1 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 2 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 3 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 4 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 5 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 6 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 12 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 13 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 14 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 15 }, { .mem_type = WMFW_ADSP2_XM, .num_blocks = 16 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 1 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 2 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 3 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 4 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 5 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 6 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 12 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 13 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 14 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 15 }, { .mem_type = WMFW_ADSP2_YM, .num_blocks = 16 }, }; KUNIT_ARRAY_PARAM(halo_all_num_blocks, halo_all_num_blocks_param_cases, cs_dsp_mem_param_desc); static const struct cs_dsp_wmfw_test_param packed_xy_num_blocks_param_cases[] = { { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 1 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 2 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 3 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 4 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 5 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 6 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 12 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 13 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 14 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 15 }, { .mem_type = WMFW_HALO_XM_PACKED, .num_blocks = 16 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 1 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 2 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 3 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 4 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 5 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 6 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 12 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 13 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 14 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 15 }, { .mem_type = WMFW_HALO_YM_PACKED, .num_blocks = 16 }, }; KUNIT_ARRAY_PARAM(packed_xy_num_blocks, packed_xy_num_blocks_param_cases, cs_dsp_mem_param_desc); static struct kunit_case cs_dsp_wmfw_test_cases_halo[] = { KUNIT_CASE(wmfw_write_xm_header_unpacked), KUNIT_CASE_PARAM(wmfw_write_one_payload, halo_all_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_multiple_oneblock_payloads, halo_all_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_multiple_oneblock_payloads_reverse, halo_all_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_multiple_payloads_sparse_unordered, halo_all_num_blocks_gen_params), KUNIT_CASE(wmfw_write_all_packed_pm), KUNIT_CASE(wmfw_write_multiple_packed_unpacked_mem), KUNIT_CASE_PARAM(wmfw_write_packed_1_unpacked_trailing, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_2_unpacked_trailing, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_3_unpacked_trailing, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_2_single_unpacked_trailing, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_3_single_unpacked_trailing, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_1_unpacked_leading, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_2_unpacked_leading, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_3_unpacked_leading, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_2_single_unpacked_leading, packed_xy_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_packed_3_single_unpacked_leading, packed_xy_num_blocks_gen_params), KUNIT_CASE(wmfw_load_with_info), { } /* terminator */ }; static struct kunit_case cs_dsp_wmfw_test_cases_adsp2[] = { KUNIT_CASE(wmfw_write_xm_header_unpacked), KUNIT_CASE_PARAM(wmfw_write_one_payload, adsp2_all_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_multiple_oneblock_payloads, adsp2_all_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_multiple_oneblock_payloads_reverse, adsp2_all_num_blocks_gen_params), KUNIT_CASE_PARAM(wmfw_write_multiple_payloads_sparse_unordered, adsp2_all_num_blocks_gen_params), KUNIT_CASE(wmfw_write_all_unpacked_pm), KUNIT_CASE(wmfw_write_multiple_unpacked_mem), KUNIT_CASE(wmfw_load_with_info), { } /* terminator */ }; static struct kunit_suite cs_dsp_wmfw_test_halo = { .name = "cs_dsp_wmfwV3_halo", .init = cs_dsp_wmfw_test_halo_init, .test_cases = cs_dsp_wmfw_test_cases_halo, }; static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = { .name = "cs_dsp_wmfwV0_adsp2_32bit", .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init, .test_cases = cs_dsp_wmfw_test_cases_adsp2, }; static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = { .name = "cs_dsp_wmfwV1_adsp2_32bit", .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init, .test_cases = cs_dsp_wmfw_test_cases_adsp2, }; static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = { .name = "cs_dsp_wmfwV2_adsp2_32bit", .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init, .test_cases = cs_dsp_wmfw_test_cases_adsp2, }; static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = { .name = "cs_dsp_wmfwV0_adsp2_16bit", .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init, .test_cases = cs_dsp_wmfw_test_cases_adsp2, }; static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = { .name = "cs_dsp_wmfwV1_adsp2_16bit", .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init, .test_cases = cs_dsp_wmfw_test_cases_adsp2, }; static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = { .name = "cs_dsp_wmfwV2_adsp2_16bit", .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init, .test_cases = cs_dsp_wmfw_test_cases_adsp2, }; kunit_test_suites(&cs_dsp_wmfw_test_halo, &cs_dsp_wmfw_test_adsp2_32bit_wmfw0, &cs_dsp_wmfw_test_adsp2_32bit_wmfw1, &cs_dsp_wmfw_test_adsp2_32bit_wmfw2, &cs_dsp_wmfw_test_adsp2_16bit_wmfw0, &cs_dsp_wmfw_test_adsp2_16bit_wmfw1, &cs_dsp_wmfw_test_adsp2_16bit_wmfw2);