mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-21 06:50:25 +00:00

Test that the cs_dsp_client_ops callbacks are called when expected. pre_run, post_run - when cs_dsp_run() is called. pre_stop, post_stop - when cs_dsp_stop() is called control_add - when a WMFW is loaded control_remove - when cs_dsp_remove() is called Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Link: https://patch.msgid.link/20241212143725.1381013-13-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
688 lines
21 KiB
C
688 lines
21 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
//
|
|
// KUnit tests for cs_dsp.
|
|
//
|
|
// Copyright (C) 2024 Cirrus Logic, Inc. and
|
|
// Cirrus Logic International Semiconductor Ltd.
|
|
//
|
|
|
|
#include <kunit/device.h>
|
|
#include <kunit/resource.h>
|
|
#include <kunit/test.h>
|
|
#include <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);
|