| // 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/list.h> |
| #include <linux/mutex.h> |
| #include <linux/regmap.h> |
| |
| KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); |
| KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *); |
| |
| struct cs_dsp_test_local { |
| struct cs_dsp_mock_xm_header *xm_header; |
| struct cs_dsp_mock_wmfw_builder *wmfw_builder; |
| int wmfw_version; |
| }; |
| |
| struct cs_dsp_ctl_parse_test_param { |
| int mem_type; |
| int alg_id; |
| unsigned int offset; |
| unsigned int length; |
| u16 ctl_type; |
| u16 flags; |
| }; |
| |
| static const struct cs_dsp_mock_alg_def cs_dsp_ctl_parse_test_algs[] = { |
| { |
| .id = 0xfafa, |
| .ver = 0x100000, |
| .xm_size_words = 164, |
| .ym_size_words = 164, |
| .zm_size_words = 164, |
| }, |
| { |
| .id = 0xb, |
| .ver = 0x100001, |
| .xm_size_words = 8, |
| .ym_size_words = 8, |
| .zm_size_words = 8, |
| }, |
| { |
| .id = 0x9f1234, |
| .ver = 0x100500, |
| .xm_size_words = 16, |
| .ym_size_words = 16, |
| .zm_size_words = 16, |
| }, |
| { |
| .id = 0xff00ff, |
| .ver = 0x300113, |
| .xm_size_words = 16, |
| .ym_size_words = 16, |
| .zm_size_words = 16, |
| }, |
| }; |
| |
| static const struct cs_dsp_mock_coeff_def mock_coeff_template = { |
| .shortname = "Dummy Coeff", |
| .type = WMFW_CTL_TYPE_BYTES, |
| .mem_type = WMFW_ADSP2_YM, |
| .flags = WMFW_CTL_FLAG_VOLATILE, |
| .length_bytes = 4, |
| }; |
| |
| static char *cs_dsp_ctl_alloc_test_string(struct kunit *test, char c, size_t len) |
| { |
| char *str; |
| |
| str = kunit_kmalloc(test, len + 1, GFP_KERNEL); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str); |
| memset(str, c, len); |
| str[len] = '\0'; |
| |
| return str; |
| } |
| |
| /* Algorithm info block without controls should load */ |
| static void cs_dsp_ctl_parse_no_coeffs(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_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| } |
| |
| /* |
| * V1 controls do not have names, the name field in the coefficient entry |
| * should be ignored. |
| */ |
| static void cs_dsp_ctl_parse_v1_name(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.fullname = "Dummy"; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, 0); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * V1 controls do not have names, the name field in the coefficient entry |
| * should be ignored. Test with a zero-length name string. |
| */ |
| static void cs_dsp_ctl_parse_empty_v1_name(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.fullname = "\0"; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, 0); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * V1 controls do not have names, the name field in the coefficient entry |
| * should be ignored. Test with a maximum length name string. |
| */ |
| static void cs_dsp_ctl_parse_max_v1_name(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.fullname = cs_dsp_ctl_alloc_test_string(test, 'A', 255); |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, 0); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* Short name from coeff descriptor should be used as control name. */ |
| static void cs_dsp_ctl_parse_short_name(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname)); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Short name from coeff descriptor should be used as control name. |
| * Test with a short name that is a single character. |
| */ |
| static void cs_dsp_ctl_parse_min_short_name(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.shortname = "Q"; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, 1); |
| KUNIT_EXPECT_EQ(test, ctl->subname[0], 'Q'); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Short name from coeff descriptor should be used as control name. |
| * Test with a maximum length name. |
| */ |
| static void cs_dsp_ctl_parse_max_short_name(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.shortname = cs_dsp_ctl_alloc_test_string(test, 'A', 255); |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, 255); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Full name from coeff descriptor should be ignored. It is a variable |
| * length field so affects the position of subsequent fields. |
| * Test with a 1-character full name. |
| */ |
| static void cs_dsp_ctl_parse_with_min_fullname(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.fullname = "Q"; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname)); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Full name from coeff descriptor should be ignored. It is a variable |
| * length field so affects the position of subsequent fields. |
| * Test with a maximum length full name. |
| */ |
| static void cs_dsp_ctl_parse_with_max_fullname(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.fullname = cs_dsp_ctl_alloc_test_string(test, 'A', 255); |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname)); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Description from coeff descriptor should be ignored. It is a variable |
| * length field so affects the position of subsequent fields. |
| * Test with a 1-character description |
| */ |
| static void cs_dsp_ctl_parse_with_min_description(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.description = "Q"; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname)); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Description from coeff descriptor should be ignored. It is a variable |
| * length field so affects the position of subsequent fields. |
| * Test with a maximum length description |
| */ |
| static void cs_dsp_ctl_parse_with_max_description(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.description = cs_dsp_ctl_alloc_test_string(test, 'A', 65535); |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname)); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Full name and description from coeff descriptor are variable length |
| * fields so affects the position of subsequent fields. |
| * Test with a maximum length full name and description |
| */ |
| static void cs_dsp_ctl_parse_with_max_fullname_and_description(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.fullname = cs_dsp_ctl_alloc_test_string(test, 'A', 255); |
| def.description = cs_dsp_ctl_alloc_test_string(test, 'A', 65535); |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(def.shortname)); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, def.shortname, ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| static const char * const cs_dsp_ctl_alignment_test_names[] = { |
| "1", "12", "123", "1234", "12345", "123456", "1234567", |
| "12345678", "123456789", "123456789A", "123456789AB", |
| "123456789ABC", "123456789ABCD", "123456789ABCDE", |
| "123456789ABCDEF", |
| }; |
| |
| /* |
| * Variable-length string fields are padded to a multiple of 4-bytes. |
| * Test this with various lengths of short name. |
| */ |
| static void cs_dsp_ctl_shortname_alignment(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| int i; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) { |
| def.shortname = cs_dsp_ctl_alignment_test_names[i]; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| } |
| |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) { |
| mutex_lock(&priv->dsp->pwr_lock); |
| ctl = cs_dsp_get_ctl(priv->dsp, cs_dsp_ctl_alignment_test_names[i], |
| def.mem_type, cs_dsp_ctl_parse_test_algs[0].id); |
| mutex_unlock(&priv->dsp->pwr_lock); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, i + 1); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, cs_dsp_ctl_alignment_test_names[i], |
| ctl->subname_len); |
| /* Test fields that are parsed after the variable-length fields */ |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| } |
| |
| /* |
| * Variable-length string fields are padded to a multiple of 4-bytes. |
| * Test this with various lengths of full name. |
| */ |
| static void cs_dsp_ctl_fullname_alignment(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| char ctl_name[4]; |
| struct firmware *wmfw; |
| int i; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) { |
| /* |
| * Create a unique control name of 3 characters so that |
| * the shortname field is exactly 4 bytes long including |
| * the length byte. |
| */ |
| snprintf(ctl_name, sizeof(ctl_name), "%03d", i); |
| KUNIT_ASSERT_EQ(test, strlen(ctl_name), 3); |
| def.shortname = ctl_name; |
| |
| def.fullname = cs_dsp_ctl_alignment_test_names[i]; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| } |
| |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) { |
| snprintf(ctl_name, sizeof(ctl_name), "%03d", i); |
| |
| mutex_lock(&priv->dsp->pwr_lock); |
| ctl = cs_dsp_get_ctl(priv->dsp, ctl_name, def.mem_type, |
| cs_dsp_ctl_parse_test_algs[0].id); |
| mutex_unlock(&priv->dsp->pwr_lock); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, 3); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, ctl_name, ctl->subname_len); |
| /* Test fields that are parsed after the variable-length fields */ |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| } |
| |
| /* |
| * Variable-length string fields are padded to a multiple of 4-bytes. |
| * Test this with various lengths of description. |
| */ |
| static void cs_dsp_ctl_description_alignment(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| char ctl_name[4]; |
| struct firmware *wmfw; |
| int i; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) { |
| /* |
| * Create a unique control name of 3 characters so that |
| * the shortname field is exactly 4 bytes long including |
| * the length byte. |
| */ |
| snprintf(ctl_name, sizeof(ctl_name), "%03d", i); |
| KUNIT_ASSERT_EQ(test, strlen(ctl_name), 3); |
| def.shortname = ctl_name; |
| |
| def.description = cs_dsp_ctl_alignment_test_names[i]; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| } |
| |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_alignment_test_names); i++) { |
| snprintf(ctl_name, sizeof(ctl_name), "%03d", i); |
| |
| mutex_lock(&priv->dsp->pwr_lock); |
| ctl = cs_dsp_get_ctl(priv->dsp, ctl_name, def.mem_type, |
| cs_dsp_ctl_parse_test_algs[0].id); |
| mutex_unlock(&priv->dsp->pwr_lock); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, 3); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, ctl_name, ctl->subname_len); |
| /* Test fields that are parsed after the variable-length fields */ |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| } |
| |
| static const char * const cs_dsp_get_ctl_test_names[] = { |
| "Up", "Down", "Switch", "Mute", |
| "Left Up", "Left Down", "Right Up", "Right Down", |
| "Left Mute", "Right Mute", |
| "_trunc_1", "_trunc_2", " trunc", |
| }; |
| |
| /* Test using cs_dsp_get_ctl() to lookup various controls. */ |
| static void cs_dsp_get_ctl_test(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| int i; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_get_ctl_test_names); i++) { |
| def.shortname = cs_dsp_get_ctl_test_names[i]; |
| def.offset_dsp_words = i; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| } |
| |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_get_ctl_test_names); i++) { |
| mutex_lock(&priv->dsp->pwr_lock); |
| ctl = cs_dsp_get_ctl(priv->dsp, cs_dsp_get_ctl_test_names[i], |
| def.mem_type, cs_dsp_ctl_parse_test_algs[0].id); |
| mutex_unlock(&priv->dsp->pwr_lock); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, strlen(cs_dsp_get_ctl_test_names[i])); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, cs_dsp_get_ctl_test_names[i], |
| ctl->subname_len); |
| KUNIT_EXPECT_EQ(test, ctl->offset, i); |
| } |
| } |
| |
| /* |
| * cs_dsp_get_ctl() searches for the control in the currently loaded |
| * firmware, so create identical controls in multiple firmware and |
| * test that the correct one is found. |
| */ |
| static void cs_dsp_get_ctl_test_multiple_wmfw(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct cs_dsp_mock_wmfw_builder *builder2; |
| struct firmware *wmfw; |
| |
| def.shortname = "_A_CONTROL"; |
| |
| /* Create a second mock wmfw builder */ |
| builder2 = cs_dsp_mock_wmfw_init(priv, |
| cs_dsp_mock_wmfw_format_version(local->wmfw_builder)); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, builder2); |
| cs_dsp_mock_wmfw_add_data_block(builder2, |
| WMFW_ADSP2_XM, 0, |
| local->xm_header->blob_data, |
| local->xm_header->blob_size_bytes); |
| |
| /* Load a 'misc' firmware with a control */ |
| def.offset_dsp_words = 1; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* Load a 'mbc/vss' firmware with a control of the same name */ |
| def.offset_dsp_words = 2; |
| cs_dsp_mock_wmfw_start_alg_info_block(builder2, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(builder2, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(builder2); |
| wmfw = cs_dsp_mock_wmfw_get_firmware(builder2); |
| KUNIT_ASSERT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_fw2", NULL, NULL, "mbc/vss"), 0); |
| |
| /* A lookup should return the control for the current firmware */ |
| mutex_lock(&priv->dsp->pwr_lock); |
| ctl = cs_dsp_get_ctl(priv->dsp, def.shortname, |
| def.mem_type, cs_dsp_ctl_parse_test_algs[0].id); |
| mutex_unlock(&priv->dsp->pwr_lock); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->offset, 2); |
| |
| /* Re-load the 'misc' firmware and a lookup should return its control */ |
| cs_dsp_power_down(priv->dsp); |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| mutex_lock(&priv->dsp->pwr_lock); |
| ctl = cs_dsp_get_ctl(priv->dsp, def.shortname, |
| def.mem_type, cs_dsp_ctl_parse_test_algs[0].id); |
| mutex_unlock(&priv->dsp->pwr_lock); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->offset, 1); |
| } |
| |
| /* Test that the value of the memory type field is parsed correctly. */ |
| static void cs_dsp_ctl_parse_memory_type(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| /* kunit_skip() marks the test skipped forever, so just return */ |
| if ((param->mem_type == WMFW_ADSP2_ZM) && !cs_dsp_mock_has_zm(priv)) |
| return; |
| |
| def.mem_type = param->mem_type; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->alg_region.type, param->mem_type); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Test that the algorithm id from the parent alg-info block is |
| * correctly stored in the cs_dsp_coeff_ctl. |
| */ |
| static void cs_dsp_ctl_parse_alg_id(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| param->alg_id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->alg_region.alg, param->alg_id); |
| KUNIT_EXPECT_EQ(test, ctl->alg_region.type, def.mem_type); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* |
| * Test that the values of (alg id, memory type) tuple is parsed correctly. |
| * The alg id is parsed from the alg-info block, but the memory type is |
| * parsed from the coefficient info descriptor. |
| */ |
| static void cs_dsp_ctl_parse_alg_mem(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| /* kunit_skip() marks the test skipped forever, so just return */ |
| if ((param->mem_type == WMFW_ADSP2_ZM) && !cs_dsp_mock_has_zm(priv)) |
| return; |
| |
| def.mem_type = param->mem_type; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| param->alg_id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->alg_region.alg, param->alg_id); |
| KUNIT_EXPECT_EQ(test, ctl->alg_region.type, param->mem_type); |
| } |
| |
| /* Test that the value of the offset field is parsed correctly. */ |
| static void cs_dsp_ctl_parse_offset(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.offset_dsp_words = param->offset; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->offset, param->offset); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* Test that the value of the length field is parsed correctly. */ |
| static void cs_dsp_ctl_parse_length(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.length_bytes = param->length; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->offset, def.offset_dsp_words); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->len, param->length); |
| } |
| |
| /* Test that the value of the control type field is parsed correctly. */ |
| static void cs_dsp_ctl_parse_ctl_type(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| |
| def.type = param->ctl_type; |
| def.flags = param->flags; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->type, param->ctl_type); |
| KUNIT_EXPECT_EQ(test, ctl->flags, def.flags); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* Test that the value of the flags field is parsed correctly. */ |
| static void cs_dsp_ctl_parse_flags(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| u32 reg_val; |
| |
| /* |
| * Non volatile controls will be read to initialize the cache |
| * so the regmap cache must contain something to read. |
| */ |
| reg_val = 0xf11100; |
| regmap_raw_write(priv->dsp->regmap, |
| cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM), |
| ®_val, sizeof(reg_val)); |
| |
| def.flags = param->flags; |
| def.mem_type = WMFW_ADSP2_YM; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->type, def.type); |
| KUNIT_EXPECT_EQ(test, ctl->flags, param->flags); |
| KUNIT_EXPECT_EQ(test, ctl->len, def.length_bytes); |
| } |
| |
| /* Test that invalid combinations of (control type, flags) are rejected. */ |
| static void cs_dsp_ctl_illegal_type_flags(struct kunit *test) |
| { |
| const struct cs_dsp_ctl_parse_test_param *param = test->param_value; |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct firmware *wmfw; |
| u32 reg_val; |
| |
| /* |
| * Non volatile controls will be read to initialize the cache |
| * so the regmap cache must contain something to read. |
| */ |
| reg_val = 0xf11100; |
| regmap_raw_write(priv->dsp->regmap, |
| cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM), |
| ®_val, sizeof(reg_val)); |
| |
| def.type = param->ctl_type; |
| def.flags = param->flags; |
| def.mem_type = WMFW_ADSP2_YM; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_LT(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| } |
| |
| /* Test that the correct firmware name is entered in the cs_dsp_coeff_ctl. */ |
| static void cs_dsp_ctl_parse_fw_name(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *walkctl, *ctl1, *ctl2; |
| struct cs_dsp_mock_wmfw_builder *builder2; |
| struct firmware *wmfw; |
| |
| /* Create a second mock wmfw builder */ |
| builder2 = cs_dsp_mock_wmfw_init(priv, |
| cs_dsp_mock_wmfw_format_version(local->wmfw_builder)); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, builder2); |
| cs_dsp_mock_wmfw_add_data_block(builder2, |
| WMFW_ADSP2_XM, 0, |
| local->xm_header->blob_data, |
| local->xm_header->blob_size_bytes); |
| |
| /* Load a 'misc' firmware with a control */ |
| def.offset_dsp_words = 1; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* Load a 'mbc/vss' firmware with a control */ |
| def.offset_dsp_words = 2; |
| cs_dsp_mock_wmfw_start_alg_info_block(builder2, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(builder2, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(builder2); |
| wmfw = cs_dsp_mock_wmfw_get_firmware(builder2); |
| KUNIT_ASSERT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "mock_fw2", NULL, NULL, "mbc/vss"), 0); |
| |
| /* Both controls should be in the list (order not guaranteed) */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2); |
| ctl1 = NULL; |
| ctl2 = NULL; |
| list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) { |
| if (strcmp(walkctl->fw_name, "misc") == 0) |
| ctl1 = walkctl; |
| else if (strcmp(walkctl->fw_name, "mbc/vss") == 0) |
| ctl2 = walkctl; |
| } |
| |
| KUNIT_EXPECT_NOT_NULL(test, ctl1); |
| KUNIT_EXPECT_NOT_NULL(test, ctl2); |
| KUNIT_EXPECT_EQ(test, ctl1->offset, 1); |
| KUNIT_EXPECT_EQ(test, ctl2->offset, 2); |
| } |
| |
| /* Controls are unique if the algorithm ID is different */ |
| static void cs_dsp_ctl_alg_id_uniqueness(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl1, *ctl2; |
| struct firmware *wmfw; |
| |
| /* Create an algorithm containing the control */ |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| /* Create a different algorithm containing an identical control */ |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[1].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* Both controls should be in the list */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2); |
| ctl1 = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| ctl2 = list_next_entry(ctl1, list); |
| KUNIT_EXPECT_NOT_NULL(test, ctl1); |
| KUNIT_EXPECT_NOT_NULL(test, ctl2); |
| KUNIT_EXPECT_NE(test, ctl1->alg_region.alg, ctl2->alg_region.alg); |
| KUNIT_EXPECT_EQ(test, ctl1->alg_region.type, ctl2->alg_region.type); |
| KUNIT_EXPECT_EQ(test, ctl1->offset, ctl2->offset); |
| KUNIT_EXPECT_EQ(test, ctl1->type, ctl2->type); |
| KUNIT_EXPECT_EQ(test, ctl1->flags, ctl2->flags); |
| KUNIT_EXPECT_EQ(test, ctl1->len, ctl2->len); |
| KUNIT_EXPECT_STREQ(test, ctl1->fw_name, ctl2->fw_name); |
| KUNIT_EXPECT_EQ(test, ctl1->subname_len, ctl2->subname_len); |
| if (ctl1->subname_len) |
| KUNIT_EXPECT_MEMEQ(test, ctl1->subname, ctl2->subname, ctl1->subname_len); |
| } |
| |
| /* Controls are unique if the memory region is different */ |
| static void cs_dsp_ctl_mem_uniqueness(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl1, *ctl2; |
| struct firmware *wmfw; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| /* Create control in XM */ |
| def.mem_type = WMFW_ADSP2_XM; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| |
| /* Create control in YM */ |
| def.mem_type = WMFW_ADSP2_YM; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* Both controls should be in the list */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2); |
| ctl1 = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| ctl2 = list_next_entry(ctl1, list); |
| KUNIT_EXPECT_NOT_NULL(test, ctl1); |
| KUNIT_EXPECT_NOT_NULL(test, ctl2); |
| KUNIT_EXPECT_EQ(test, ctl1->alg_region.alg, ctl2->alg_region.alg); |
| KUNIT_EXPECT_NE(test, ctl1->alg_region.type, ctl2->alg_region.type); |
| KUNIT_EXPECT_EQ(test, ctl1->offset, ctl2->offset); |
| KUNIT_EXPECT_EQ(test, ctl1->type, ctl2->type); |
| KUNIT_EXPECT_EQ(test, ctl1->flags, ctl2->flags); |
| KUNIT_EXPECT_EQ(test, ctl1->len, ctl2->len); |
| KUNIT_EXPECT_STREQ(test, ctl1->fw_name, ctl2->fw_name); |
| KUNIT_EXPECT_EQ(test, ctl1->subname_len, ctl2->subname_len); |
| if (ctl1->subname_len) |
| KUNIT_EXPECT_MEMEQ(test, ctl1->subname, ctl2->subname, ctl1->subname_len); |
| } |
| |
| /* Controls are unique if they are in different firmware */ |
| static void cs_dsp_ctl_fw_uniqueness(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl1, *ctl2; |
| struct cs_dsp_mock_wmfw_builder *builder2; |
| struct firmware *wmfw; |
| |
| /* Create a second mock wmfw builder */ |
| builder2 = cs_dsp_mock_wmfw_init(priv, |
| cs_dsp_mock_wmfw_format_version(local->wmfw_builder)); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, builder2); |
| cs_dsp_mock_wmfw_add_data_block(builder2, |
| WMFW_ADSP2_XM, 0, |
| local->xm_header->blob_data, |
| local->xm_header->blob_size_bytes); |
| |
| /* Load a 'misc' firmware with a control */ |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* Load a 'mbc/vss' firmware with the same control */ |
| cs_dsp_mock_wmfw_start_alg_info_block(builder2, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| cs_dsp_mock_wmfw_add_coeff_desc(builder2, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(builder2); |
| wmfw = cs_dsp_mock_wmfw_get_firmware(builder2); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw2", |
| NULL, NULL, "mbc/vss"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* Both controls should be in the list */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 2); |
| ctl1 = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list); |
| ctl2 = list_next_entry(ctl1, list); |
| KUNIT_EXPECT_NOT_NULL(test, ctl1); |
| KUNIT_EXPECT_NOT_NULL(test, ctl2); |
| KUNIT_EXPECT_EQ(test, ctl1->alg_region.alg, ctl2->alg_region.alg); |
| KUNIT_EXPECT_EQ(test, ctl1->alg_region.type, ctl2->alg_region.type); |
| KUNIT_EXPECT_EQ(test, ctl1->offset, ctl2->offset); |
| KUNIT_EXPECT_EQ(test, ctl1->type, ctl2->type); |
| KUNIT_EXPECT_EQ(test, ctl1->flags, ctl2->flags); |
| KUNIT_EXPECT_EQ(test, ctl1->len, ctl2->len); |
| KUNIT_EXPECT_STRNEQ(test, ctl1->fw_name, ctl2->fw_name); |
| KUNIT_EXPECT_EQ(test, ctl1->subname_len, ctl2->subname_len); |
| if (ctl1->subname_len) |
| KUNIT_EXPECT_MEMEQ(test, ctl1->subname, ctl2->subname, ctl1->subname_len); |
| } |
| |
| /* |
| * Controls from a wmfw are only added to the list once. If the same |
| * wmfw is reloaded the controls are not added again. |
| * This creates multiple algorithms with one control each, which will |
| * work on both V1 format and >=V2 format controls. |
| */ |
| static void cs_dsp_ctl_squash_reloaded_controls(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctls[ARRAY_SIZE(cs_dsp_ctl_parse_test_algs)]; |
| struct cs_dsp_coeff_ctl *walkctl; |
| struct firmware *wmfw; |
| int i; |
| |
| /* Create some algorithms with a control */ |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_parse_test_algs); i++) { |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[i].id, |
| "dummyalg", NULL); |
| def.mem_type = WMFW_ADSP2_YM; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| } |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* All controls should be in the list */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), |
| ARRAY_SIZE(cs_dsp_ctl_parse_test_algs)); |
| |
| /* Take a copy of the pointers to controls to compare against. */ |
| i = 0; |
| list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) { |
| KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls)); |
| ctls[i++] = walkctl; |
| } |
| |
| |
| /* Load the wmfw again */ |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* The number of controls should be the same */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), |
| ARRAY_SIZE(cs_dsp_ctl_parse_test_algs)); |
| |
| /* And they should be the same objects */ |
| i = 0; |
| list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) { |
| KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls)); |
| KUNIT_ASSERT_PTR_EQ(test, walkctl, ctls[i++]); |
| } |
| } |
| |
| /* |
| * Controls from a wmfw are only added to the list once. If the same |
| * wmfw is reloaded the controls are not added again. |
| * This tests >=V2 firmware that can have multiple named controls in |
| * the same algorithm. |
| */ |
| static void cs_dsp_ctl_v2_squash_reloaded_controls(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctls[ARRAY_SIZE(cs_dsp_get_ctl_test_names)]; |
| struct cs_dsp_coeff_ctl *walkctl; |
| struct firmware *wmfw; |
| int i; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| |
| /* Create some controls */ |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_get_ctl_test_names); i++) { |
| def.shortname = cs_dsp_get_ctl_test_names[i]; |
| def.offset_dsp_words = i; |
| if (i & BIT(0)) |
| def.mem_type = WMFW_ADSP2_XM; |
| else |
| def.mem_type = WMFW_ADSP2_YM; |
| |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| } |
| |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* All controls should be in the list */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), |
| ARRAY_SIZE(cs_dsp_get_ctl_test_names)); |
| |
| /* Take a copy of the pointers to controls to compare against. */ |
| i = 0; |
| list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) { |
| KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls)); |
| ctls[i++] = walkctl; |
| } |
| |
| |
| /* Load the wmfw again */ |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| cs_dsp_power_down(priv->dsp); |
| |
| /* The number of controls should be the same */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), |
| ARRAY_SIZE(cs_dsp_get_ctl_test_names)); |
| |
| /* And they should be the same objects */ |
| i = 0; |
| list_for_each_entry(walkctl, &priv->dsp->ctl_list, list) { |
| KUNIT_ASSERT_LT(test, i, ARRAY_SIZE(ctls)); |
| KUNIT_ASSERT_PTR_EQ(test, walkctl, ctls[i++]); |
| } |
| } |
| |
| static const char * const cs_dsp_ctl_v2_compare_len_names[] = { |
| "LEFT", |
| "LEFT_", |
| "LEFT_SPK", |
| "LEFT_SPK_V", |
| "LEFT_SPK_VOL", |
| "LEFT_SPK_MUTE", |
| "LEFT_SPK_1", |
| "LEFT_X", |
| "LEFT2", |
| }; |
| |
| /* |
| * When comparing shortnames the full length of both strings is |
| * considered, not only the characters in of the shortest string. |
| * So that "LEFT" is not the same as "LEFT2". |
| * This is specifically to test for the bug that was fixed by commit: |
| * 7ac1102b227b ("firmware: cs_dsp: Fix new control name check") |
| */ |
| static void cs_dsp_ctl_v2_compare_len(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct cs_dsp_mock_coeff_def def = mock_coeff_template; |
| struct cs_dsp_coeff_ctl *ctl; |
| struct firmware *wmfw; |
| int i; |
| |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_ctl_parse_test_algs[0].id, |
| "dummyalg", NULL); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_v2_compare_len_names); i++) { |
| def.shortname = cs_dsp_ctl_v2_compare_len_names[i]; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| } |
| |
| cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder); |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(priv->local->wmfw_builder); |
| KUNIT_ASSERT_EQ(test, cs_dsp_power_up(priv->dsp, wmfw, "mock_fw", NULL, NULL, "misc"), 0); |
| |
| for (i = 0; i < ARRAY_SIZE(cs_dsp_ctl_v2_compare_len_names); i++) { |
| mutex_lock(&priv->dsp->pwr_lock); |
| ctl = cs_dsp_get_ctl(priv->dsp, cs_dsp_ctl_v2_compare_len_names[i], |
| def.mem_type, cs_dsp_ctl_parse_test_algs[0].id); |
| mutex_unlock(&priv->dsp->pwr_lock); |
| KUNIT_ASSERT_NOT_NULL(test, ctl); |
| KUNIT_EXPECT_EQ(test, ctl->subname_len, |
| strlen(cs_dsp_ctl_v2_compare_len_names[i])); |
| KUNIT_EXPECT_MEMEQ(test, ctl->subname, cs_dsp_ctl_v2_compare_len_names[i], |
| ctl->subname_len); |
| } |
| } |
| |
| static int cs_dsp_ctl_parse_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 blob. |
| */ |
| local->xm_header = cs_dsp_create_mock_xm_header(priv, |
| cs_dsp_ctl_parse_test_algs, |
| ARRAY_SIZE(cs_dsp_ctl_parse_test_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 blob 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_ctl_parse_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_ctl_parse_test_common_init(test, dsp, 3); |
| } |
| |
| static int cs_dsp_ctl_parse_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_ctl_parse_test_common_init(test, dsp, wmfw_ver); |
| } |
| |
| static int cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1_init(struct kunit *test) |
| { |
| return cs_dsp_ctl_parse_test_adsp2_32bit_init(test, 1); |
| } |
| |
| static int cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2_init(struct kunit *test) |
| { |
| return cs_dsp_ctl_parse_test_adsp2_32bit_init(test, 2); |
| } |
| |
| static int cs_dsp_ctl_parse_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_ctl_parse_test_common_init(test, dsp, wmfw_ver); |
| } |
| |
| static int cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1_init(struct kunit *test) |
| { |
| return cs_dsp_ctl_parse_test_adsp2_16bit_init(test, 1); |
| } |
| |
| static int cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2_init(struct kunit *test) |
| { |
| return cs_dsp_ctl_parse_test_adsp2_16bit_init(test, 2); |
| } |
| |
| static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_mem_type_param_cases[] = { |
| { .mem_type = WMFW_ADSP2_XM }, |
| { .mem_type = WMFW_ADSP2_YM }, |
| { .mem_type = WMFW_ADSP2_ZM }, |
| }; |
| |
| static void cs_dsp_ctl_mem_type_desc(const struct cs_dsp_ctl_parse_test_param *param, |
| char *desc) |
| { |
| snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", |
| cs_dsp_mem_region_name(param->mem_type)); |
| } |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_ctl_mem_type, |
| cs_dsp_ctl_mem_type_param_cases, |
| cs_dsp_ctl_mem_type_desc); |
| |
| static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_alg_id_param_cases[] = { |
| { .alg_id = 0xb }, |
| { .alg_id = 0xfafa }, |
| { .alg_id = 0x9f1234 }, |
| { .alg_id = 0xff00ff }, |
| }; |
| |
| static void cs_dsp_ctl_alg_id_desc(const struct cs_dsp_ctl_parse_test_param *param, |
| char *desc) |
| { |
| snprintf(desc, KUNIT_PARAM_DESC_SIZE, "alg_id:%#x", param->alg_id); |
| } |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_ctl_alg_id, |
| cs_dsp_ctl_alg_id_param_cases, |
| cs_dsp_ctl_alg_id_desc); |
| |
| static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_offset_param_cases[] = { |
| { .offset = 0x0 }, |
| { .offset = 0x1 }, |
| { .offset = 0x2 }, |
| { .offset = 0x3 }, |
| { .offset = 0x4 }, |
| { .offset = 0x5 }, |
| { .offset = 0x6 }, |
| { .offset = 0x7 }, |
| { .offset = 0xe0 }, |
| { .offset = 0xf1 }, |
| { .offset = 0xfffe }, |
| { .offset = 0xffff }, |
| }; |
| |
| static void cs_dsp_ctl_offset_desc(const struct cs_dsp_ctl_parse_test_param *param, |
| char *desc) |
| { |
| snprintf(desc, KUNIT_PARAM_DESC_SIZE, "offset:%#x", param->offset); |
| } |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_ctl_offset, |
| cs_dsp_ctl_offset_param_cases, |
| cs_dsp_ctl_offset_desc); |
| |
| static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_length_param_cases[] = { |
| { .length = 0x4 }, |
| { .length = 0x8 }, |
| { .length = 0x18 }, |
| { .length = 0xf000 }, |
| }; |
| |
| static void cs_dsp_ctl_length_desc(const struct cs_dsp_ctl_parse_test_param *param, |
| char *desc) |
| { |
| snprintf(desc, KUNIT_PARAM_DESC_SIZE, "length:%#x", param->length); |
| } |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_ctl_length, |
| cs_dsp_ctl_length_param_cases, |
| cs_dsp_ctl_length_desc); |
| |
| /* Note: some control types mandate specific flags settings */ |
| static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_type_param_cases[] = { |
| { .ctl_type = WMFW_CTL_TYPE_BYTES, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_ACKED, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE | |
| WMFW_CTL_FLAG_SYS }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_SYS }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE | |
| WMFW_CTL_FLAG_SYS }, |
| }; |
| |
| static void cs_dsp_ctl_type_flags_desc(const struct cs_dsp_ctl_parse_test_param *param, |
| char *desc) |
| { |
| snprintf(desc, KUNIT_PARAM_DESC_SIZE, "ctl_type:%#x flags:%#x", |
| param->ctl_type, param->flags); |
| } |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_ctl_type, |
| cs_dsp_ctl_type_param_cases, |
| cs_dsp_ctl_type_flags_desc); |
| |
| static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_flags_param_cases[] = { |
| { .flags = 0 }, |
| { .flags = WMFW_CTL_FLAG_READABLE }, |
| { .flags = WMFW_CTL_FLAG_WRITEABLE }, |
| { .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE }, |
| { .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE }, |
| { .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | |
| WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| }; |
| |
| static void cs_dsp_ctl_flags_desc(const struct cs_dsp_ctl_parse_test_param *param, |
| char *desc) |
| { |
| snprintf(desc, KUNIT_PARAM_DESC_SIZE, "flags:%#x", param->flags); |
| } |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_ctl_flags, |
| cs_dsp_ctl_flags_param_cases, |
| cs_dsp_ctl_flags_desc); |
| |
| static const struct cs_dsp_ctl_parse_test_param cs_dsp_ctl_illegal_type_flags_param_cases[] = { |
| /* ACKED control must be volatile + read + write */ |
| { .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = 0 }, |
| { .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_ACKED, .flags = WMFW_CTL_FLAG_VOLATILE }, |
| { .ctl_type = WMFW_CTL_TYPE_ACKED, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_ACKED, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE }, |
| |
| /* HOSTEVENT must be system + volatile + read + write */ |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = 0 }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_VOLATILE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, .flags = WMFW_CTL_FLAG_SYS }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOSTEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE }, |
| |
| /* FWEVENT rules same as HOSTEVENT */ |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = 0 }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_VOLATILE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, .flags = WMFW_CTL_FLAG_SYS }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_FWEVENT, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE }, |
| |
| /* |
| * HOSTBUFFER must be system + volatile + readable or |
| * system + volatile + readable + writeable |
| */ |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = 0 }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE}, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_VOLATILE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, .flags = WMFW_CTL_FLAG_SYS }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_READABLE | WMFW_CTL_FLAG_WRITEABLE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE }, |
| { .ctl_type = WMFW_CTL_TYPE_HOST_BUFFER, |
| .flags = WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | WMFW_CTL_FLAG_WRITEABLE }, |
| }; |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_ctl_illegal_type_flags, |
| cs_dsp_ctl_illegal_type_flags_param_cases, |
| cs_dsp_ctl_type_flags_desc); |
| |
| static struct kunit_case cs_dsp_ctl_parse_test_cases_v1[] = { |
| KUNIT_CASE(cs_dsp_ctl_parse_no_coeffs), |
| KUNIT_CASE(cs_dsp_ctl_parse_v1_name), |
| KUNIT_CASE(cs_dsp_ctl_parse_empty_v1_name), |
| KUNIT_CASE(cs_dsp_ctl_parse_max_v1_name), |
| |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_memory_type, cs_dsp_ctl_mem_type_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_id, cs_dsp_ctl_alg_id_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_mem, cs_dsp_ctl_mem_type_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_offset, cs_dsp_ctl_offset_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_length, cs_dsp_ctl_length_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_ctl_type, cs_dsp_ctl_type_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_flags, cs_dsp_ctl_flags_gen_params), |
| KUNIT_CASE(cs_dsp_ctl_parse_fw_name), |
| |
| KUNIT_CASE(cs_dsp_ctl_alg_id_uniqueness), |
| KUNIT_CASE(cs_dsp_ctl_mem_uniqueness), |
| KUNIT_CASE(cs_dsp_ctl_fw_uniqueness), |
| KUNIT_CASE(cs_dsp_ctl_squash_reloaded_controls), |
| |
| { } /* terminator */ |
| }; |
| |
| static struct kunit_case cs_dsp_ctl_parse_test_cases_v2_v3[] = { |
| KUNIT_CASE(cs_dsp_ctl_parse_no_coeffs), |
| KUNIT_CASE(cs_dsp_ctl_parse_short_name), |
| KUNIT_CASE(cs_dsp_ctl_parse_min_short_name), |
| KUNIT_CASE(cs_dsp_ctl_parse_max_short_name), |
| KUNIT_CASE(cs_dsp_ctl_parse_with_min_fullname), |
| KUNIT_CASE(cs_dsp_ctl_parse_with_max_fullname), |
| KUNIT_CASE(cs_dsp_ctl_parse_with_min_description), |
| KUNIT_CASE(cs_dsp_ctl_parse_with_max_description), |
| KUNIT_CASE(cs_dsp_ctl_parse_with_max_fullname_and_description), |
| KUNIT_CASE(cs_dsp_ctl_shortname_alignment), |
| KUNIT_CASE(cs_dsp_ctl_fullname_alignment), |
| KUNIT_CASE(cs_dsp_ctl_description_alignment), |
| KUNIT_CASE(cs_dsp_get_ctl_test), |
| KUNIT_CASE(cs_dsp_get_ctl_test_multiple_wmfw), |
| |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_memory_type, cs_dsp_ctl_mem_type_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_id, cs_dsp_ctl_alg_id_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_alg_mem, cs_dsp_ctl_mem_type_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_offset, cs_dsp_ctl_offset_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_length, cs_dsp_ctl_length_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_ctl_type, cs_dsp_ctl_type_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_parse_flags, cs_dsp_ctl_flags_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_ctl_illegal_type_flags, |
| cs_dsp_ctl_illegal_type_flags_gen_params), |
| KUNIT_CASE(cs_dsp_ctl_parse_fw_name), |
| |
| KUNIT_CASE(cs_dsp_ctl_alg_id_uniqueness), |
| KUNIT_CASE(cs_dsp_ctl_mem_uniqueness), |
| KUNIT_CASE(cs_dsp_ctl_fw_uniqueness), |
| KUNIT_CASE(cs_dsp_ctl_squash_reloaded_controls), |
| KUNIT_CASE(cs_dsp_ctl_v2_squash_reloaded_controls), |
| KUNIT_CASE(cs_dsp_ctl_v2_compare_len), |
| |
| { } /* terminator */ |
| }; |
| |
| static struct kunit_suite cs_dsp_ctl_parse_test_halo = { |
| .name = "cs_dsp_ctl_parse_wmfwV3_halo", |
| .init = cs_dsp_ctl_parse_test_halo_init, |
| .test_cases = cs_dsp_ctl_parse_test_cases_v2_v3, |
| }; |
| |
| static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1 = { |
| .name = "cs_dsp_ctl_parse_wmfwV1_adsp2_32bit", |
| .init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1_init, |
| .test_cases = cs_dsp_ctl_parse_test_cases_v1, |
| }; |
| |
| static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2 = { |
| .name = "cs_dsp_ctl_parse_wmfwV2_adsp2_32bit", |
| .init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2_init, |
| .test_cases = cs_dsp_ctl_parse_test_cases_v2_v3, |
| }; |
| |
| static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1 = { |
| .name = "cs_dsp_ctl_parse_wmfwV1_adsp2_16bit", |
| .init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1_init, |
| .test_cases = cs_dsp_ctl_parse_test_cases_v1, |
| }; |
| |
| static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2 = { |
| .name = "cs_dsp_ctl_parse_wmfwV2_adsp2_16bit", |
| .init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2_init, |
| .test_cases = cs_dsp_ctl_parse_test_cases_v2_v3, |
| }; |
| |
| kunit_test_suites(&cs_dsp_ctl_parse_test_halo, |
| &cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1, |
| &cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2, |
| &cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1, |
| &cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2); |