| // SPDX-License-Identifier: GPL-2.0-only |
| // |
| // KUnit tests for cs_dsp. |
| // |
| // Copyright (C) 2024 Cirrus Logic, Inc. and |
| // Cirrus Logic International Semiconductor Ltd. |
| // |
| |
| #include <kunit/device.h> |
| #include <kunit/resource.h> |
| #include <kunit/test.h> |
| #include <linux/build_bug.h> |
| #include <linux/firmware/cirrus/cs_dsp.h> |
| #include <linux/firmware/cirrus/cs_dsp_test_utils.h> |
| #include <linux/firmware/cirrus/wmfw.h> |
| #include <linux/random.h> |
| #include <linux/regmap.h> |
| #include <linux/string.h> |
| #include <linux/vmalloc.h> |
| |
| /* |
| * Test method is: |
| * |
| * 1) Create a mock regmap in cache-only mode so that all writes will be cached. |
| * 2) Create dummy wmfw file. |
| * 3) Call cs_dsp_power_up() with the bin file. |
| * 4) Readback the cached value of registers that should have been written and |
| * check they have the correct value. |
| * 5) All the registers that are expected to have been written are dropped from |
| * the cache. This should leave the cache clean. |
| * 6) If the cache is still dirty there have been unexpected writes. |
| */ |
| |
| KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *) |
| KUNIT_DEFINE_ACTION_WRAPPER(_vfree_wrapper, vfree, void *) |
| KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *) |
| |
| struct cs_dsp_test_local { |
| struct cs_dsp_mock_xm_header *xm_header; |
| struct cs_dsp_mock_wmfw_builder *wmfw_builder; |
| int wmfw_version; |
| }; |
| |
| struct cs_dsp_wmfw_test_param { |
| unsigned int num_blocks; |
| int mem_type; |
| }; |
| |
| static const struct cs_dsp_mock_alg_def cs_dsp_wmfw_test_mock_algs[] = { |
| { |
| .id = 0xfafa, |
| .ver = 0x100000, |
| .xm_size_words = 164, |
| .ym_size_words = 164, |
| .zm_size_words = 164, |
| }, |
| }; |
| |
| /* |
| * wmfw that writes the XM header. |
| * cs_dsp always reads this back from unpacked XM. |
| */ |
| static void wmfw_write_xm_header_unpacked(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| unsigned int reg_addr; |
| u8 *readback; |
| |
| /* XM header payload was added to wmfw by test case init function */ |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| /* Read raw so endianness and register width don't matter */ |
| readback = kunit_kzalloc(test, local->xm_header->blob_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| local->xm_header->blob_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, local->xm_header->blob_data, |
| local->xm_header->blob_size_bytes); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* Write one payload of length param->num_blocks */ |
| static void wmfw_write_one_payload(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| u8 *payload_data, *readback; |
| unsigned int mem_offset_dsp_words = 0; |
| unsigned int payload_size_bytes; |
| |
| payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type); |
| |
| /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */ |
| do { |
| payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type); |
| } while (payload_size_bytes % 4); |
| |
| payload_data = kunit_kmalloc(test, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| get_random_bytes(payload_data, payload_size_bytes); |
| |
| readback = kunit_kzalloc(test, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| |
| /* Tests on XM must be after the XM header */ |
| if (param->mem_type == WMFW_ADSP2_XM) |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32); |
| |
| /* Add a single payload */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| param->mem_type, mem_offset_dsp_words, |
| payload_data, payload_size_bytes); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type); |
| reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words; |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes); |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* Write several smallest possible payloads for the given memory type */ |
| static void wmfw_write_multiple_oneblock_payloads(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| u8 *payload_data, *readback; |
| unsigned int mem_offset_dsp_words = 0; |
| unsigned int payload_size_bytes, payload_size_dsp_words; |
| const unsigned int num_payloads = param->num_blocks; |
| int i; |
| |
| /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */ |
| payload_size_dsp_words = 0; |
| payload_size_bytes = 0; |
| do { |
| payload_size_dsp_words += cs_dsp_mock_reg_block_length_dsp_words(priv, |
| param->mem_type); |
| payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type); |
| } while (payload_size_bytes % 4); |
| |
| payload_data = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| |
| readback = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| |
| get_random_bytes(payload_data, num_payloads * payload_size_bytes); |
| |
| /* Tests on XM must be after the XM header */ |
| if (param->mem_type == WMFW_ADSP2_XM) |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / payload_size_bytes; |
| |
| /* Add multiple payloads of one block each */ |
| for (i = 0; i < num_payloads; ++i) { |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| param->mem_type, |
| mem_offset_dsp_words + (i * payload_size_dsp_words), |
| &payload_data[i * payload_size_bytes], |
| payload_size_bytes); |
| } |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type); |
| reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words; |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| num_payloads * payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, payload_data, num_payloads * payload_size_bytes); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, num_payloads * payload_size_bytes); |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write several smallest possible payloads of the given memory type |
| * in reverse address order |
| */ |
| static void wmfw_write_multiple_oneblock_payloads_reverse(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| u8 *payload_data, *readback; |
| unsigned int mem_offset_dsp_words = 0; |
| unsigned int payload_size_bytes, payload_size_dsp_words; |
| const unsigned int num_payloads = param->num_blocks; |
| int i; |
| |
| /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */ |
| payload_size_dsp_words = 0; |
| payload_size_bytes = 0; |
| do { |
| payload_size_dsp_words += cs_dsp_mock_reg_block_length_dsp_words(priv, |
| param->mem_type); |
| payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type); |
| } while (payload_size_bytes % 4); |
| |
| payload_data = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| |
| readback = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| |
| get_random_bytes(payload_data, num_payloads * payload_size_bytes); |
| |
| /* Tests on XM must be after the XM header */ |
| if (param->mem_type == WMFW_ADSP2_XM) |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / payload_size_bytes; |
| |
| /* Add multiple payloads of one block each */ |
| for (i = num_payloads - 1; i >= 0; --i) { |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| param->mem_type, |
| mem_offset_dsp_words + (i * payload_size_dsp_words), |
| &payload_data[i * payload_size_bytes], |
| payload_size_bytes); |
| } |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type); |
| reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words; |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| num_payloads * payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, payload_data, num_payloads * payload_size_bytes); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, num_payloads * payload_size_bytes); |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write multiple payloads of length param->num_blocks. |
| * The payloads are not in address order and collectively do not patch |
| * a contiguous block of memory. |
| */ |
| static void wmfw_write_multiple_payloads_sparse_unordered(struct kunit *test) |
| { |
| static const unsigned int random_offsets[] = { |
| 11, 69, 59, 61, 32, 75, 4, 38, 70, 13, 79, 47, 46, 53, 18, 44, |
| 54, 35, 51, 21, 26, 45, 27, 41, 66, 2, 17, 56, 40, 9, 8, 20, |
| 29, 19, 63, 42, 12, 16, 43, 3, 5, 55, 52, 22 |
| }; |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| u8 *payload_data, *readback; |
| unsigned int mem_offset_dsp_words = 0; |
| unsigned int payload_size_bytes, payload_size_dsp_words; |
| const int num_payloads = ARRAY_SIZE(random_offsets); |
| int i; |
| |
| payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type); |
| payload_size_dsp_words = param->num_blocks * |
| cs_dsp_mock_reg_block_length_dsp_words(priv, param->mem_type); |
| |
| /* payloads must be a multiple of 4 bytes and a whole number of DSP registers */ |
| do { |
| payload_size_dsp_words += cs_dsp_mock_reg_block_length_dsp_words(priv, |
| param->mem_type); |
| payload_size_bytes += cs_dsp_mock_reg_block_length_bytes(priv, param->mem_type); |
| } while (payload_size_bytes % 4); |
| |
| payload_data = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| get_random_bytes(payload_data, payload_size_bytes); |
| |
| readback = kunit_kcalloc(test, num_payloads, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| |
| /* Tests on XM must be after the XM header */ |
| if (param->mem_type == WMFW_ADSP2_XM) |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / payload_size_bytes; |
| |
| /* Add multiple payloads of one block each at "random" locations */ |
| for (i = 0; i < num_payloads; ++i) { |
| unsigned int offset = random_offsets[i] * payload_size_dsp_words; |
| |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| param->mem_type, |
| mem_offset_dsp_words + offset, |
| &payload_data[i * payload_size_bytes], |
| payload_size_bytes); |
| } |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| for (i = 0; i < num_payloads; ++i) { |
| unsigned int offset_num_regs = (random_offsets[i] * payload_size_bytes) / |
| regmap_get_val_bytes(priv->dsp->regmap); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, param->mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| reg_addr += cs_dsp_mock_reg_addr_inc_per_unpacked_word(priv) * mem_offset_dsp_words; |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, |
| &readback[i * payload_size_bytes], |
| payload_size_bytes), |
| 0); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes); |
| } |
| |
| KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* Write the whole of PM in a single unpacked payload */ |
| static void wmfw_write_all_unpacked_pm(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| u8 *payload_data, *readback; |
| unsigned int payload_size_bytes; |
| |
| payload_size_bytes = cs_dsp_mock_size_of_region(priv->dsp, WMFW_ADSP2_PM); |
| payload_data = vmalloc(payload_size_bytes); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| kunit_add_action_or_reset(priv->test, _vfree_wrapper, payload_data); |
| |
| readback = vmalloc(payload_size_bytes); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| kunit_add_action_or_reset(priv->test, _vfree_wrapper, readback); |
| memset(readback, 0, payload_size_bytes); |
| |
| /* Add a single PM payload */ |
| get_random_bytes(payload_data, payload_size_bytes); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| WMFW_ADSP2_PM, 0, |
| payload_data, payload_size_bytes); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_PM); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes); |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* Write the whole of PM in a single packed payload */ |
| static void wmfw_write_all_packed_pm(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| u8 *payload_data, *readback; |
| unsigned int payload_size_bytes; |
| |
| payload_size_bytes = cs_dsp_mock_size_of_region(priv->dsp, WMFW_HALO_PM_PACKED); |
| payload_data = vmalloc(payload_size_bytes); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| kunit_add_action_or_reset(priv->test, _vfree_wrapper, payload_data); |
| |
| readback = vmalloc(payload_size_bytes); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| kunit_add_action_or_reset(priv->test, _vfree_wrapper, readback); |
| memset(readback, 0, payload_size_bytes); |
| |
| /* Add a single PM payload */ |
| get_random_bytes(payload_data, payload_size_bytes); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| WMFW_HALO_PM_PACKED, 0, |
| payload_data, payload_size_bytes); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_HALO_PM_PACKED); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes); |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write a series of payloads to various unpacked memory regions. |
| * The payloads are of various lengths and offsets, driven by the |
| * payload_defs table. The offset and length are both given as a |
| * number of minimum-sized register blocks to keep the maths simpler. |
| * (Where a minimum-sized register block is the smallest number of |
| * registers that contain a whole number of DSP words.) |
| */ |
| static void wmfw_write_multiple_unpacked_mem(struct kunit *test) |
| { |
| static const struct { |
| int mem_type; |
| unsigned int offset_num_blocks; |
| unsigned int num_blocks; |
| } payload_defs[] = { |
| { WMFW_ADSP2_PM, 11, 60 }, |
| { WMFW_ADSP2_ZM, 69, 8 }, |
| { WMFW_ADSP2_YM, 32, 74 }, |
| { WMFW_ADSP2_XM, 70, 38 }, |
| { WMFW_ADSP2_PM, 84, 48 }, |
| { WMFW_ADSP2_XM, 46, 18 }, |
| { WMFW_ADSP2_PM, 0, 8 }, |
| { WMFW_ADSP2_YM, 0, 30 }, |
| { WMFW_ADSP2_PM, 160, 50 }, |
| { WMFW_ADSP2_ZM, 21, 26 }, |
| }; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int payload_size_bytes, offset_num_dsp_words; |
| unsigned int reg_addr, offset_bytes, offset_num_regs; |
| void **payload_data; |
| void *readback; |
| int i, ret; |
| |
| payload_data = kunit_kcalloc(test, ARRAY_SIZE(payload_defs), sizeof(*payload_data), |
| GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| |
| for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) { |
| payload_size_bytes = payload_defs[i].num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, |
| payload_defs[i].mem_type); |
| |
| payload_data[i] = kunit_kmalloc(test, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data[i]); |
| get_random_bytes(payload_data[i], payload_size_bytes); |
| |
| offset_num_dsp_words = payload_defs[i].offset_num_blocks * |
| cs_dsp_mock_reg_block_length_dsp_words(priv, |
| payload_defs[i].mem_type); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| payload_defs[i].mem_type, |
| offset_num_dsp_words, |
| payload_data[i], |
| payload_size_bytes); |
| } |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) { |
| payload_size_bytes = payload_defs[i].num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, |
| payload_defs[i].mem_type); |
| |
| readback = kunit_kzalloc(test, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| |
| offset_bytes = payload_defs[i].offset_num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, payload_defs[i].mem_type); |
| offset_num_regs = offset_bytes / regmap_get_val_bytes(priv->dsp->regmap); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, payload_defs[i].mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| ret = regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes); |
| KUNIT_EXPECT_EQ_MSG(test, ret, 0, "%s @%u num:%u\n", |
| cs_dsp_mem_region_name(payload_defs[i].mem_type), |
| payload_defs[i].offset_num_blocks, payload_defs[i].num_blocks); |
| KUNIT_EXPECT_MEMEQ_MSG(test, readback, payload_data[i], payload_size_bytes, |
| "%s @%u num:%u\n", |
| cs_dsp_mem_region_name(payload_defs[i].mem_type), |
| payload_defs[i].offset_num_blocks, |
| payload_defs[i].num_blocks); |
| |
| kunit_kfree(test, readback); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes); |
| } |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write a series of payloads to various packed and unpacked memory regions. |
| * The payloads are of various lengths and offsets, driven by the |
| * payload_defs table. The offset and length are both given as a |
| * number of minimum-sized register blocks to keep the maths simpler. |
| * (Where a minimum-sized register block is the smallest number of |
| * registers that contain a whole number of DSP words.) |
| */ |
| static void wmfw_write_multiple_packed_unpacked_mem(struct kunit *test) |
| { |
| static const struct { |
| int mem_type; |
| unsigned int offset_num_blocks; |
| unsigned int num_blocks; |
| } payload_defs[] = { |
| { WMFW_HALO_PM_PACKED, 11, 60 }, |
| { WMFW_ADSP2_YM, 69, 8 }, |
| { WMFW_HALO_YM_PACKED, 32, 74 }, |
| { WMFW_HALO_XM_PACKED, 70, 38 }, |
| { WMFW_HALO_PM_PACKED, 84, 48 }, |
| { WMFW_HALO_XM_PACKED, 46, 18 }, |
| { WMFW_HALO_PM_PACKED, 0, 8 }, |
| { WMFW_HALO_YM_PACKED, 0, 30 }, |
| { WMFW_HALO_PM_PACKED, 160, 50 }, |
| { WMFW_ADSP2_XM, 21, 26 }, |
| }; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| unsigned int payload_size_bytes, offset_num_dsp_words; |
| unsigned int reg_addr, offset_bytes, offset_num_regs; |
| void **payload_data; |
| void *readback; |
| int i, ret; |
| |
| payload_data = kunit_kcalloc(test, ARRAY_SIZE(payload_defs), sizeof(*payload_data), |
| GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data); |
| |
| for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) { |
| payload_size_bytes = payload_defs[i].num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, |
| payload_defs[i].mem_type); |
| |
| payload_data[i] = kunit_kmalloc(test, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data[i]); |
| get_random_bytes(payload_data[i], payload_size_bytes); |
| |
| offset_num_dsp_words = payload_defs[i].offset_num_blocks * |
| cs_dsp_mock_reg_block_length_dsp_words(priv, |
| payload_defs[i].mem_type); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| payload_defs[i].mem_type, |
| offset_num_dsp_words, |
| payload_data[i], |
| payload_size_bytes); |
| } |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| for (i = 0; i < ARRAY_SIZE(payload_defs); ++i) { |
| payload_size_bytes = payload_defs[i].num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, |
| payload_defs[i].mem_type); |
| |
| readback = kunit_kzalloc(test, payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback); |
| |
| offset_bytes = payload_defs[i].offset_num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, payload_defs[i].mem_type); |
| offset_num_regs = offset_bytes / regmap_get_val_bytes(priv->dsp->regmap); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, payload_defs[i].mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| ret = regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes); |
| KUNIT_EXPECT_EQ_MSG(test, ret, 0, "%s @%u num:%u\n", |
| cs_dsp_mem_region_name(payload_defs[i].mem_type), |
| payload_defs[i].offset_num_blocks, |
| payload_defs[i].num_blocks); |
| KUNIT_EXPECT_MEMEQ_MSG(test, readback, payload_data[i], payload_size_bytes, |
| "%s @%u num:%u\n", |
| cs_dsp_mem_region_name(payload_defs[i].mem_type), |
| payload_defs[i].offset_num_blocks, |
| payload_defs[i].num_blocks); |
| |
| kunit_kfree(test, readback); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, payload_size_bytes); |
| } |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is one word longer than a packed block multiple, |
| * using one packed payload followed by one unpacked word. |
| */ |
| static void wmfw_write_packed_1_unpacked_trailing(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int mem_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[1]; |
| unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block; |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) { |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32); |
| |
| /* Round up to multiple of packed block length */ |
| mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block); |
| } |
| |
| /* Add a single packed payload */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, mem_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| /* |
| * Add payload of one unpacked word to DSP memory right after |
| * the packed payload words. |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words, |
| unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked word was written correctly and drop |
| * it from the regmap cache. The unpacked payload is offset within |
| * unpacked register space by the number of DSP words that were |
| * written in the packed payload. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is two words longer than a packed block multiple, |
| * using one packed payload followed by one payload of two unpacked words. |
| */ |
| static void wmfw_write_packed_2_unpacked_trailing(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int mem_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[2]; |
| unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block; |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) { |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32); |
| |
| /* Round up to multiple of packed block length */ |
| mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block); |
| } |
| |
| /* Add a single packed payload */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, mem_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| /* |
| * Add payload of two unpacked words to DSP memory right after |
| * the packed payload words. |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words, |
| unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked words were written correctly and drop |
| * them from the regmap cache. The unpacked payload is offset |
| * within unpacked register space by the number of DSP words |
| * that were written in the packed payload. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is three words longer than a packed block multiple, |
| * using one packed payload followed by one payload of three unpacked words. |
| */ |
| static void wmfw_write_packed_3_unpacked_trailing(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int mem_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[3]; |
| unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block; |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) { |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32); |
| |
| /* Round up to multiple of packed block length */ |
| mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block); |
| } |
| |
| /* Add a single packed payload */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, mem_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| /* |
| * Add payload of three unpacked words to DSP memory right after |
| * the packed payload words. |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words, |
| unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked words were written correctly and drop |
| * them from the regmap cache. The unpacked payload is offset |
| * within unpacked register space by the number of DSP words |
| * that were written in the packed payload. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is two words longer than a packed block multiple, |
| * using one packed payload followed by two payloads of one unpacked word each. |
| */ |
| static void wmfw_write_packed_2_single_unpacked_trailing(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int mem_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[2]; |
| unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block; |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) { |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32); |
| |
| /* Round up to multiple of packed block length */ |
| mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block); |
| } |
| |
| /* Add a single packed payload */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, mem_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| /* |
| * Add two unpacked words to DSP memory right after the packed |
| * payload words. Each unpacked word in its own payload. |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words, |
| &unpacked_payload_data[0], |
| sizeof(unpacked_payload_data[0])); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words + 1, |
| &unpacked_payload_data[1], |
| sizeof(unpacked_payload_data[1])); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked words were written correctly and drop |
| * them from the regmap cache. The unpacked words are offset |
| * within unpacked register space by the number of DSP words |
| * that were written in the packed payload. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is three words longer than a packed block multiple, |
| * using one packed payload followed by three payloads of one unpacked word each. |
| */ |
| static void wmfw_write_packed_3_single_unpacked_trailing(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int mem_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[3]; |
| unsigned int packed_payload_size_bytes, packed_payload_size_dsp_words; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| packed_payload_size_dsp_words = param->num_blocks * dsp_words_per_packed_block; |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) { |
| mem_offset_dsp_words += local->xm_header->blob_size_bytes / sizeof(u32); |
| |
| /* Round up to multiple of packed block length */ |
| mem_offset_dsp_words = roundup(mem_offset_dsp_words, dsp_words_per_packed_block); |
| } |
| |
| /* Add a single packed payload */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, mem_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| /* |
| * Add three unpacked words to DSP memory right after the packed |
| * payload words. Each unpacked word in its own payload. |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words, |
| &unpacked_payload_data[0], |
| sizeof(unpacked_payload_data[0])); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words + 1, |
| &unpacked_payload_data[1], |
| sizeof(unpacked_payload_data[1])); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| mem_offset_dsp_words + packed_payload_size_dsp_words + 2, |
| &unpacked_payload_data[2], |
| sizeof(unpacked_payload_data[2])); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked words were written correctly and drop |
| * them from the regmap cache. The unpacked words are offset |
| * within unpacked register space by the number of DSP words |
| * that were written in the packed payload. |
| */ |
| offset_num_regs = (mem_offset_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| offset_num_regs += (packed_payload_size_dsp_words / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is one word longer than a packed block multiple, |
| * and does not start on a packed alignment. Use one unpacked word |
| * followed by a packed payload. |
| */ |
| static void wmfw_write_packed_1_unpacked_leading(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int packed_payload_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[1]; |
| unsigned int packed_payload_size_bytes; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) |
| packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes / |
| sizeof(u32); |
| /* |
| * Leave space for an unaligned word before the packed block and |
| * round the packed block start to multiple of packed block length. |
| */ |
| packed_payload_offset_dsp_words += 1; |
| packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words, |
| dsp_words_per_packed_block); |
| |
| /* Add a single unpacked word right before the first word of packed data */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| packed_payload_offset_dsp_words - 1, |
| unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| /* Add payload of packed data to the DSP memory after the unpacked word. */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, |
| packed_payload_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked word was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = ((packed_payload_offset_dsp_words - 1) / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is two words longer than a packed block multiple, |
| * and does not start on a packed alignment. Use one payload of two unpacked |
| * words followed by a packed payload. |
| */ |
| static void wmfw_write_packed_2_unpacked_leading(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int packed_payload_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[2]; |
| unsigned int packed_payload_size_bytes; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) |
| packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes / |
| sizeof(u32); |
| /* |
| * Leave space for two unaligned words before the packed block and |
| * round the packed block start to multiple of packed block length. |
| */ |
| packed_payload_offset_dsp_words += 2; |
| packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words, |
| dsp_words_per_packed_block); |
| |
| /* |
| * Add two unpacked words as a single payload right before the |
| * first word of packed data |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| packed_payload_offset_dsp_words - 2, |
| unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| /* Add payload of packed data to the DSP memory after the unpacked words. */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, |
| packed_payload_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked words were written correctly and drop |
| * them from the regmap cache. |
| */ |
| offset_num_regs = ((packed_payload_offset_dsp_words - 2) / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is three words longer than a packed block multiple, |
| * and does not start on a packed alignment. Use one payload of three unpacked |
| * words followed by a packed payload. |
| */ |
| static void wmfw_write_packed_3_unpacked_leading(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int packed_payload_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[3]; |
| unsigned int packed_payload_size_bytes; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) |
| packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes / |
| sizeof(u32); |
| /* |
| * Leave space for three unaligned words before the packed block and |
| * round the packed block start to multiple of packed block length. |
| */ |
| packed_payload_offset_dsp_words += 3; |
| packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words, |
| dsp_words_per_packed_block); |
| |
| /* |
| * Add three unpacked words as a single payload right before the |
| * first word of packed data |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| packed_payload_offset_dsp_words - 3, |
| unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| /* Add payload of packed data to the DSP memory after the unpacked words. */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, |
| packed_payload_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked words were written correctly and drop |
| * them from the regmap cache. |
| */ |
| offset_num_regs = ((packed_payload_offset_dsp_words - 3) / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is two words longer than a packed block multiple, |
| * and does not start on a packed alignment. Use two payloads of one unpacked |
| * word each, followed by a packed payload. |
| */ |
| static void wmfw_write_packed_2_single_unpacked_leading(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int packed_payload_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[2]; |
| unsigned int packed_payload_size_bytes; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) |
| packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes / |
| sizeof(u32); |
| /* |
| * Leave space for two unaligned words before the packed block and |
| * round the packed block start to multiple of packed block length. |
| */ |
| packed_payload_offset_dsp_words += 2; |
| packed_payload_offset_dsp_words = roundup(packed_payload_offset_dsp_words, |
| dsp_words_per_packed_block); |
| |
| /* |
| * Add two unpacked words as two payloads each containing a single |
| * unpacked word. |
| */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| packed_payload_offset_dsp_words - 2, |
| &unpacked_payload_data[0], |
| sizeof(unpacked_payload_data[0])); |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| unpacked_mem_type, |
| packed_payload_offset_dsp_words - 1, |
| &unpacked_payload_data[1], |
| sizeof(unpacked_payload_data[1])); |
| |
| /* Add payload of packed data to the DSP memory after the unpacked words. */ |
| cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder, |
| packed_mem_type, |
| packed_payload_offset_dsp_words, |
| packed_payload_data, packed_payload_size_bytes); |
| |
| /* Download the wmfw */ |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), |
| 0); |
| /* |
| * Check that the packed payload was written correctly and drop |
| * it from the regmap cache. |
| */ |
| offset_num_regs = (packed_payload_offset_dsp_words / dsp_words_per_packed_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, packed_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, packed_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| packed_payload_size_bytes), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, packed_payload_data, packed_payload_size_bytes); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, packed_payload_size_bytes); |
| |
| /* |
| * Check that the unpacked words were written correctly and drop |
| * them from the regmap cache. |
| */ |
| offset_num_regs = ((packed_payload_offset_dsp_words - 2) / dsp_words_per_unpacked_block) * |
| cs_dsp_mock_reg_block_length_registers(priv, unpacked_mem_type); |
| reg_addr = cs_dsp_mock_base_addr_for_mem(priv, unpacked_mem_type); |
| reg_addr += offset_num_regs * regmap_get_reg_stride(priv->dsp->regmap); |
| KUNIT_EXPECT_EQ(test, |
| regmap_raw_read(priv->dsp->regmap, reg_addr, readback, |
| sizeof(unpacked_payload_data)), |
| 0); |
| KUNIT_EXPECT_MEMEQ(test, readback, unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| cs_dsp_mock_regmap_drop_bytes(priv, reg_addr, sizeof(unpacked_payload_data)); |
| |
| /* Drop expected writes and the cache should then be clean */ |
| cs_dsp_mock_xm_header_drop_from_regmap_cache(priv); |
| KUNIT_EXPECT_FALSE(test, cs_dsp_mock_regmap_is_dirty(priv, true)); |
| } |
| |
| /* |
| * Write XM/YM data that is three words longer than a packed block multiple, |
| * and does not start on a packed alignment. Use three payloads of one unpacked |
| * word each, followed by a packed payload. |
| */ |
| static void wmfw_write_packed_3_single_unpacked_leading(struct kunit *test) |
| { |
| const struct cs_dsp_wmfw_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| int packed_mem_type = param->mem_type; |
| int unpacked_mem_type = cs_dsp_mock_packed_to_unpacked_mem_type(param->mem_type); |
| unsigned int dsp_words_per_packed_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, packed_mem_type); |
| unsigned int dsp_words_per_unpacked_block = |
| cs_dsp_mock_reg_block_length_dsp_words(priv, unpacked_mem_type); |
| unsigned int packed_payload_offset_dsp_words = 0; |
| struct firmware *wmfw; |
| unsigned int reg_addr; |
| void *packed_payload_data, *readback; |
| u32 unpacked_payload_data[3]; |
| unsigned int packed_payload_size_bytes; |
| unsigned int offset_num_regs; |
| |
| packed_payload_size_bytes = param->num_blocks * |
| cs_dsp_mock_reg_block_length_bytes(priv, packed_mem_type); |
| |
| packed_payload_data = kunit_kmalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, packed_payload_data); |
| get_random_bytes(packed_payload_data, packed_payload_size_bytes); |
| |
| get_random_bytes(unpacked_payload_data, sizeof(unpacked_payload_data)); |
| |
| readback = kunit_kzalloc(test, packed_payload_size_bytes, GFP_KERNEL); |
| |
| /* Tests on XM must be after the XM header */ |
| if (unpacked_mem_type == WMFW_ADSP2_XM) |
| packed_payload_offset_dsp_words += local->xm_header->blob_size_bytes / |
| sizeof(u32); |
| /* |
| * Leave space for two unaligned words before the packed block and |
| * 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); |