| // 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 <kunit/test-bug.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> |
| |
| #define ADSP2_LOCK_REGION_CTRL 0x7A |
| #define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000 |
| |
| 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_wmfw_builder *wmfw_builder; |
| |
| int num_control_add; |
| int num_control_remove; |
| int num_pre_run; |
| int num_post_run; |
| int num_pre_stop; |
| int num_post_stop; |
| int num_watchdog_expired; |
| |
| struct cs_dsp_coeff_ctl *passed_ctl[16]; |
| struct cs_dsp *passed_dsp; |
| }; |
| |
| struct cs_dsp_callbacks_test_param { |
| const struct cs_dsp_client_ops *ops; |
| const char *case_name; |
| }; |
| |
| static const struct cs_dsp_mock_alg_def cs_dsp_callbacks_test_mock_algs[] = { |
| { |
| .id = 0xfafa, |
| .ver = 0x100000, |
| .xm_size_words = 164, |
| .ym_size_words = 164, |
| .zm_size_words = 164, |
| }, |
| }; |
| |
| 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 int cs_dsp_test_control_add_callback(struct cs_dsp_coeff_ctl *ctl) |
| { |
| struct kunit *test = kunit_get_current_test(); |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| |
| local->passed_ctl[local->num_control_add] = ctl; |
| local->num_control_add++; |
| |
| return 0; |
| } |
| |
| static void cs_dsp_test_control_remove_callback(struct cs_dsp_coeff_ctl *ctl) |
| { |
| struct kunit *test = kunit_get_current_test(); |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| |
| local->passed_ctl[local->num_control_remove] = ctl; |
| local->num_control_remove++; |
| } |
| |
| static int cs_dsp_test_pre_run_callback(struct cs_dsp *dsp) |
| { |
| struct kunit *test = kunit_get_current_test(); |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| |
| local->passed_dsp = dsp; |
| local->num_pre_run++; |
| |
| return 0; |
| } |
| |
| static int cs_dsp_test_post_run_callback(struct cs_dsp *dsp) |
| { |
| struct kunit *test = kunit_get_current_test(); |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| |
| local->passed_dsp = dsp; |
| local->num_post_run++; |
| |
| return 0; |
| } |
| |
| static void cs_dsp_test_pre_stop_callback(struct cs_dsp *dsp) |
| { |
| struct kunit *test = kunit_get_current_test(); |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| |
| local->passed_dsp = dsp; |
| local->num_pre_stop++; |
| } |
| |
| static void cs_dsp_test_post_stop_callback(struct cs_dsp *dsp) |
| { |
| struct kunit *test = kunit_get_current_test(); |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| |
| local->passed_dsp = dsp; |
| local->num_post_stop++; |
| } |
| |
| static void cs_dsp_test_watchdog_expired_callback(struct cs_dsp *dsp) |
| { |
| struct kunit *test = kunit_get_current_test(); |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| |
| local->passed_dsp = dsp; |
| local->num_watchdog_expired++; |
| } |
| |
| static const struct cs_dsp_client_ops cs_dsp_callback_test_client_ops = { |
| .control_add = cs_dsp_test_control_add_callback, |
| .control_remove = cs_dsp_test_control_remove_callback, |
| .pre_run = cs_dsp_test_pre_run_callback, |
| .post_run = cs_dsp_test_post_run_callback, |
| .pre_stop = cs_dsp_test_pre_stop_callback, |
| .post_stop = cs_dsp_test_post_stop_callback, |
| .watchdog_expired = cs_dsp_test_watchdog_expired_callback, |
| }; |
| |
| static const struct cs_dsp_client_ops cs_dsp_callback_test_empty_client_ops = { |
| /* No entries */ |
| }; |
| |
| static void cs_dsp_test_run_stop_callbacks(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0); |
| KUNIT_EXPECT_EQ(test, local->num_pre_run, 1); |
| KUNIT_EXPECT_EQ(test, local->num_post_run, 1); |
| KUNIT_EXPECT_EQ(test, local->num_pre_stop, 0); |
| KUNIT_EXPECT_EQ(test, local->num_post_stop, 0); |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp); |
| local->passed_dsp = NULL; |
| |
| cs_dsp_stop(priv->dsp); |
| KUNIT_EXPECT_EQ(test, local->num_pre_run, 1); |
| KUNIT_EXPECT_EQ(test, local->num_post_run, 1); |
| KUNIT_EXPECT_EQ(test, local->num_pre_stop, 1); |
| KUNIT_EXPECT_EQ(test, local->num_post_stop, 1); |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp); |
| local->passed_dsp = NULL; |
| |
| KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0); |
| KUNIT_EXPECT_EQ(test, local->num_pre_run, 2); |
| KUNIT_EXPECT_EQ(test, local->num_post_run, 2); |
| KUNIT_EXPECT_EQ(test, local->num_pre_stop, 1); |
| KUNIT_EXPECT_EQ(test, local->num_post_stop, 1); |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp); |
| local->passed_dsp = NULL; |
| |
| cs_dsp_stop(priv->dsp); |
| KUNIT_EXPECT_EQ(test, local->num_pre_run, 2); |
| KUNIT_EXPECT_EQ(test, local->num_post_run, 2); |
| KUNIT_EXPECT_EQ(test, local->num_pre_stop, 2); |
| KUNIT_EXPECT_EQ(test, local->num_post_stop, 2); |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp); |
| local->passed_dsp = NULL; |
| } |
| |
| static void cs_dsp_test_ctl_v1_callbacks(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; |
| |
| /* Add a control for each memory */ |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_callbacks_test_mock_algs[0].id, |
| "dummyalg", NULL); |
| def.shortname = "zm"; |
| def.mem_type = WMFW_ADSP2_ZM; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| |
| def.shortname = "ym"; |
| def.mem_type = WMFW_ADSP2_YM; |
| cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); |
| |
| def.shortname = "xm"; |
| def.mem_type = WMFW_ADSP2_XM; |
| 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(local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| /* There should have been an add callback for each control */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), 3); |
| KUNIT_EXPECT_EQ(test, local->num_control_add, 3); |
| KUNIT_EXPECT_EQ(test, local->num_control_remove, 0); |
| |
| i = 0; |
| list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list) |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl); |
| |
| /* |
| * Call cs_dsp_remove() and there should be a remove callback |
| * for each control |
| */ |
| memset(local->passed_ctl, 0, sizeof(local->passed_ctl)); |
| cs_dsp_remove(priv->dsp); |
| |
| /* Prevent double cleanup */ |
| kunit_remove_action(priv->test, _cs_dsp_remove_wrapper, priv->dsp); |
| |
| KUNIT_EXPECT_EQ(test, local->num_control_add, 3); |
| KUNIT_EXPECT_EQ(test, local->num_control_remove, 3); |
| |
| i = 0; |
| list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list) |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl); |
| } |
| |
| static void cs_dsp_test_ctl_v2_callbacks(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; |
| char name[2] = { }; |
| int i; |
| |
| /* Add some controls */ |
| def.shortname = name; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_callbacks_test_mock_algs[0].id, |
| "dummyalg", NULL); |
| for (i = 0; i < ARRAY_SIZE(local->passed_ctl); ++i) { |
| name[0] = 'A' + 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(local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| /* There should have been an add callback for each control */ |
| KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->dsp->ctl_list), |
| ARRAY_SIZE(local->passed_ctl)); |
| KUNIT_EXPECT_EQ(test, local->num_control_add, ARRAY_SIZE(local->passed_ctl)); |
| KUNIT_EXPECT_EQ(test, local->num_control_remove, 0); |
| |
| i = 0; |
| list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list) |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl); |
| |
| /* |
| * Call cs_dsp_remove() and there should be a remove callback |
| * for each control |
| */ |
| memset(local->passed_ctl, 0, sizeof(local->passed_ctl)); |
| cs_dsp_remove(priv->dsp); |
| |
| /* Prevent double cleanup */ |
| kunit_remove_action(priv->test, _cs_dsp_remove_wrapper, priv->dsp); |
| |
| KUNIT_EXPECT_EQ(test, local->num_control_add, ARRAY_SIZE(local->passed_ctl)); |
| KUNIT_EXPECT_EQ(test, local->num_control_remove, ARRAY_SIZE(local->passed_ctl)); |
| |
| i = 0; |
| list_for_each_entry_reverse(ctl, &priv->dsp->ctl_list, list) |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_ctl[i++], ctl); |
| } |
| |
| static void cs_dsp_test_no_callbacks(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 firmware *wmfw; |
| |
| /* Add a controls */ |
| def.shortname = "A"; |
| cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder, |
| cs_dsp_callbacks_test_mock_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(local->wmfw_builder); |
| |
| /* Run a sequence of ops that would invoke callbacks */ |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0); |
| cs_dsp_stop(priv->dsp); |
| cs_dsp_remove(priv->dsp); |
| |
| /* Prevent double cleanup */ |
| kunit_remove_action(priv->test, _cs_dsp_remove_wrapper, priv->dsp); |
| |
| /* Something went very wrong if any of our callbacks were called */ |
| KUNIT_EXPECT_EQ(test, local->num_control_add, 0); |
| KUNIT_EXPECT_EQ(test, local->num_control_remove, 0); |
| KUNIT_EXPECT_EQ(test, local->num_pre_run, 0); |
| KUNIT_EXPECT_EQ(test, local->num_post_run, 0); |
| KUNIT_EXPECT_EQ(test, local->num_pre_stop, 0); |
| KUNIT_EXPECT_EQ(test, local->num_post_stop, 0); |
| } |
| |
| static void cs_dsp_test_adsp2v2_watchdog_callback(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0); |
| |
| /* Set the watchdog timeout bit */ |
| regmap_write(priv->dsp->regmap, priv->dsp->base + ADSP2_LOCK_REGION_CTRL, |
| ADSP2_WDT_TIMEOUT_STS_MASK); |
| |
| /* Notify an interrupt and the watchdog callback should be called */ |
| cs_dsp_adsp2_bus_error(priv->dsp); |
| KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 1); |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp); |
| } |
| |
| static void cs_dsp_test_adsp2v2_watchdog_no_callbacks(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0); |
| |
| /* Set the watchdog timeout bit */ |
| regmap_write(priv->dsp->regmap, priv->dsp->base + ADSP2_LOCK_REGION_CTRL, |
| ADSP2_WDT_TIMEOUT_STS_MASK); |
| |
| /* Notify an interrupt, which will look for a watchdog callback */ |
| cs_dsp_adsp2_bus_error(priv->dsp); |
| KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 0); |
| } |
| |
| static void cs_dsp_test_halo_watchdog_callback(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder); |
| |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| |
| KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0); |
| |
| /* Notify an interrupt and the watchdog callback should be called */ |
| cs_dsp_halo_wdt_expire(priv->dsp); |
| KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 1); |
| KUNIT_EXPECT_PTR_EQ(test, local->passed_dsp, priv->dsp); |
| } |
| |
| static void cs_dsp_test_halo_watchdog_no_callbacks(struct kunit *test) |
| { |
| struct cs_dsp_test *priv = test->priv; |
| struct cs_dsp_test_local *local = priv->local; |
| struct firmware *wmfw; |
| |
| wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder); |
| KUNIT_EXPECT_EQ(test, |
| cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), |
| 0); |
| KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0); |
| |
| /* Notify an interrupt, which will look for a watchdog callback */ |
| cs_dsp_halo_wdt_expire(priv->dsp); |
| KUNIT_EXPECT_EQ(test, local->num_watchdog_expired, 0); |
| } |
| |
| static int cs_dsp_callbacks_test_common_init(struct kunit *test, struct cs_dsp *dsp, |
| int wmfw_version) |
| { |
| const struct cs_dsp_callbacks_test_param *param = test->param_value; |
| struct cs_dsp_test *priv; |
| struct cs_dsp_test_local *local; |
| struct device *test_dev; |
| struct cs_dsp_mock_xm_header *xm_header; |
| 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; |
| |
| /* 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 and pre-populate XM so the wmfw doesn't |
| * have to contain an XM blob. |
| */ |
| xm_header = cs_dsp_create_mock_xm_header(priv, |
| cs_dsp_callbacks_test_mock_algs, |
| ARRAY_SIZE(cs_dsp_callbacks_test_mock_algs)); |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xm_header); |
| cs_dsp_mock_xm_header_write_to_regmap(xm_header); |
| |
| local->wmfw_builder = cs_dsp_mock_wmfw_init(priv, 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, |
| xm_header->blob_data, |
| xm_header->blob_size_bytes); |
| |
| /* Init cs_dsp */ |
| dsp->client_ops = param->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_callbacks_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_callbacks_test_common_init(test, dsp, 3); |
| } |
| |
| static int cs_dsp_callbacks_test_adsp2_32bit_init(struct kunit *test, int rev) |
| { |
| 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 = rev; |
| 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_callbacks_test_common_init(test, dsp, 2); |
| } |
| |
| static int cs_dsp_callbacks_test_adsp2v2_32bit_init(struct kunit *test) |
| { |
| return cs_dsp_callbacks_test_adsp2_32bit_init(test, 2); |
| } |
| |
| static int cs_dsp_callbacks_test_adsp2v1_32bit_init(struct kunit *test) |
| { |
| return cs_dsp_callbacks_test_adsp2_32bit_init(test, 1); |
| } |
| |
| static int cs_dsp_callbacks_test_adsp2_16bit_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_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_callbacks_test_common_init(test, dsp, 1); |
| } |
| |
| static void cs_dsp_callbacks_param_desc(const struct cs_dsp_callbacks_test_param *param, |
| char *desc) |
| { |
| snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", param->case_name); |
| } |
| |
| /* Parameterize on different client callback ops tables */ |
| static const struct cs_dsp_callbacks_test_param cs_dsp_callbacks_ops_cases[] = { |
| { .ops = &cs_dsp_callback_test_client_ops, .case_name = "all ops" }, |
| }; |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_callbacks_ops, |
| cs_dsp_callbacks_ops_cases, |
| cs_dsp_callbacks_param_desc); |
| |
| static const struct cs_dsp_callbacks_test_param cs_dsp_no_callbacks_cases[] = { |
| { .ops = &cs_dsp_callback_test_empty_client_ops, .case_name = "empty ops" }, |
| }; |
| |
| KUNIT_ARRAY_PARAM(cs_dsp_no_callbacks, |
| cs_dsp_no_callbacks_cases, |
| cs_dsp_callbacks_param_desc); |
| |
| static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv1_test_cases[] = { |
| KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_ctl_v1_callbacks, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params), |
| |
| { } /* terminator */ |
| }; |
| |
| static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv2_test_cases[] = { |
| KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_ctl_v2_callbacks, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params), |
| |
| { } /* terminator */ |
| }; |
| |
| static struct kunit_case cs_dsp_callbacks_halo_test_cases[] = { |
| KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_ctl_v2_callbacks, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params), |
| |
| { } /* terminator */ |
| }; |
| |
| static struct kunit_case cs_dsp_watchdog_adsp2v2_test_cases[] = { |
| KUNIT_CASE_PARAM(cs_dsp_test_adsp2v2_watchdog_callback, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_adsp2v2_watchdog_no_callbacks, cs_dsp_no_callbacks_gen_params), |
| |
| { } /* terminator */ |
| }; |
| |
| static struct kunit_case cs_dsp_watchdog_halo_test_cases[] = { |
| KUNIT_CASE_PARAM(cs_dsp_test_halo_watchdog_callback, cs_dsp_callbacks_ops_gen_params), |
| KUNIT_CASE_PARAM(cs_dsp_test_halo_watchdog_no_callbacks, cs_dsp_no_callbacks_gen_params), |
| |
| { } /* terminator */ |
| }; |
| |
| static struct kunit_suite cs_dsp_callbacks_test_halo = { |
| .name = "cs_dsp_callbacks_halo", |
| .init = cs_dsp_callbacks_test_halo_init, |
| .test_cases = cs_dsp_callbacks_halo_test_cases, |
| }; |
| |
| static struct kunit_suite cs_dsp_callbacks_test_adsp2v2_32bit = { |
| .name = "cs_dsp_callbacks_adsp2v2_32bit_wmfwv2", |
| .init = cs_dsp_callbacks_test_adsp2v2_32bit_init, |
| .test_cases = cs_dsp_callbacks_adsp2_wmfwv2_test_cases, |
| }; |
| |
| static struct kunit_suite cs_dsp_callbacks_test_adsp2v1_32bit = { |
| .name = "cs_dsp_callbacks_adsp2v1_32bit_wmfwv2", |
| .init = cs_dsp_callbacks_test_adsp2v1_32bit_init, |
| .test_cases = cs_dsp_callbacks_adsp2_wmfwv2_test_cases, |
| }; |
| |
| static struct kunit_suite cs_dsp_callbacks_test_adsp2_16bit = { |
| .name = "cs_dsp_callbacks_adsp2_16bit_wmfwv1", |
| .init = cs_dsp_callbacks_test_adsp2_16bit_init, |
| .test_cases = cs_dsp_callbacks_adsp2_wmfwv1_test_cases, |
| }; |
| |
| static struct kunit_suite cs_dsp_watchdog_test_adsp2v2_32bit = { |
| .name = "cs_dsp_watchdog_adsp2v2_32bit", |
| .init = cs_dsp_callbacks_test_adsp2v2_32bit_init, |
| .test_cases = cs_dsp_watchdog_adsp2v2_test_cases, |
| }; |
| |
| static struct kunit_suite cs_dsp_watchdog_test_halo_32bit = { |
| .name = "cs_dsp_watchdog_halo", |
| .init = cs_dsp_callbacks_test_halo_init, |
| .test_cases = cs_dsp_watchdog_halo_test_cases, |
| }; |
| |
| kunit_test_suites(&cs_dsp_callbacks_test_halo, |
| &cs_dsp_callbacks_test_adsp2v2_32bit, |
| &cs_dsp_callbacks_test_adsp2v1_32bit, |
| &cs_dsp_callbacks_test_adsp2_16bit, |
| &cs_dsp_watchdog_test_adsp2v2_32bit, |
| &cs_dsp_watchdog_test_halo_32bit); |