From 1eadb7791ee5699ca58920ef705ce0934c814ece Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:08 +0000 Subject: ASoC: wm_adsp: Remove unused argument to wm_adsp_release_firmware_files() The dsp argument to wm_adsp_release_firmware_files() isn't used so remove it. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 2e23848e1dce..b3cead2cd758 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -704,8 +704,7 @@ int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); -static void wm_adsp_release_firmware_files(struct wm_adsp *dsp, - const struct firmware *wmfw_firmware, +static void wm_adsp_release_firmware_files(const struct firmware *wmfw_firmware, char *wmfw_filename, const struct firmware *coeff_firmware, char *coeff_filename) @@ -908,8 +907,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, coeff_firmware, coeff_filename, wm_adsp_fw_text[dsp->fw]); - wm_adsp_release_firmware_files(dsp, - wmfw_firmware, wmfw_filename, + wm_adsp_release_firmware_files(wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename); break; case SND_SOC_DAPM_PRE_PMD: @@ -1011,8 +1009,7 @@ int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware) wm_adsp_fw_text[dsp->fw]); err: - wm_adsp_release_firmware_files(dsp, - wmfw_firmware, wmfw_filename, + wm_adsp_release_firmware_files(wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename); return ret; -- cgit v1.2.3 From 70057cfe492d600c2b83598e8b8b64780b2ca147 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:09 +0000 Subject: ASoC: wm_adsp: Add KUnit redirection stubs for firmware file search Make some of the firmware file search functions redirectable for KUnit testing. - The call to firmware_request_nowarn() is factored out into a wrapper function so that it can be redirected. - wm_adsp_request_firmware_files() and wm_adsp_release_firmware_files() are made visible and exported if KUNIT is enabled. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 38 ++++++++++++++++++++++++++++---------- sound/soc/codecs/wm_adsp.h | 15 +++++++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b3cead2cd758..e32da6949d1f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -7,6 +7,8 @@ * Author: Mark Brown */ +#include +#include #include #include #include @@ -704,17 +706,32 @@ int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); -static void wm_adsp_release_firmware_files(const struct firmware *wmfw_firmware, - char *wmfw_filename, - const struct firmware *coeff_firmware, - char *coeff_filename) +VISIBLE_IF_KUNIT void wm_adsp_release_firmware_files(const struct firmware *wmfw_firmware, + char *wmfw_filename, + const struct firmware *coeff_firmware, + char *coeff_filename) { + KUNIT_STATIC_STUB_REDIRECT(wm_adsp_release_firmware_files, + wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename); + release_firmware(wmfw_firmware); kfree(wmfw_filename); release_firmware(coeff_firmware); kfree(coeff_filename); } +EXPORT_SYMBOL_IF_KUNIT(wm_adsp_release_firmware_files); + +VISIBLE_IF_KUNIT int wm_adsp_firmware_request(const struct firmware **firmware, + const char *filename, + struct device *dev) +{ + KUNIT_STATIC_STUB_REDIRECT(wm_adsp_firmware_request, firmware, filename, dev); + + return firmware_request_nowarn(firmware, filename, dev); +} +EXPORT_SYMBOL_IF_KUNIT(wm_adsp_firmware_request); static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, const struct firmware **firmware, char **filename, @@ -762,7 +779,7 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, s++; } - ret = firmware_request_nowarn(firmware, *filename, cs_dsp->dev); + ret = wm_adsp_firmware_request(firmware, *filename, cs_dsp->dev); if (ret != 0) { adsp_dbg(dsp, "Failed to request '%s'\n", *filename); kfree(*filename); @@ -775,11 +792,11 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, } static const char * const cirrus_dir = "cirrus/"; -static int wm_adsp_request_firmware_files(struct wm_adsp *dsp, - const struct firmware **wmfw_firmware, - char **wmfw_filename, - const struct firmware **coeff_firmware, - char **coeff_filename) +VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, + const struct firmware **wmfw_firmware, + char **wmfw_filename, + const struct firmware **coeff_firmware, + char **coeff_filename) { const char *system_name = dsp->system_name; const char *suffix = dsp->component->name_prefix; @@ -856,6 +873,7 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp, return -ENOENT; } +EXPORT_SYMBOL_IF_KUNIT(wm_adsp_request_firmware_files); static int wm_adsp_common_init(struct wm_adsp *dsp) { diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 8035fda71f8d..7c667123758b 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -142,4 +142,19 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len); +#if IS_ENABLED(CONFIG_KUNIT) +void wm_adsp_release_firmware_files(const struct firmware *wmfw_firmware, + char *wmfw_filename, + const struct firmware *coeff_firmware, + char *coeff_filename); +int wm_adsp_firmware_request(const struct firmware **firmware, + const char *filename, + struct device *dev); +int wm_adsp_request_firmware_files(struct wm_adsp *dsp, + const struct firmware **wmfw_firmware, + char **wmfw_filename, + const struct firmware **coeff_firmware, + char **coeff_filename); +#endif + #endif -- cgit v1.2.3 From b4e6b01191afb9516570437a7aff61019134fd59 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:10 +0000 Subject: ASoC: wm_adsp: Export function for KUnit test to get firmware filenames Export a function that KUnit tests can use to get the firmware filenames from the wm_adsp_fw[] array. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 11 +++++++++++ sound/soc/codecs/wm_adsp.h | 1 + 2 files changed, 12 insertions(+) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index e32da6949d1f..346ede149a9e 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -318,6 +318,17 @@ struct wm_coeff_ctl { struct work_struct work; }; +#if IS_ENABLED(CONFIG_KUNIT) +const char *wm_adsp_get_fwf_name_by_index(int index) +{ + if (index < ARRAY_SIZE(wm_adsp_fw)) + return wm_adsp_fw[index].file; + + return NULL; +} +EXPORT_SYMBOL_IF_KUNIT(wm_adsp_get_fwf_name_by_index); +#endif + int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 7c667123758b..6560dfc8c08d 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -143,6 +143,7 @@ int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len); #if IS_ENABLED(CONFIG_KUNIT) +const char *wm_adsp_get_fwf_name_by_index(int index); void wm_adsp_release_firmware_files(const struct firmware *wmfw_firmware, char *wmfw_filename, const struct firmware *coeff_firmware, -- cgit v1.2.3 From bf2d44d07de726b0393439cb4d4defc5cf89a4fc Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:11 +0000 Subject: ASoC: wm_adsp: Add kunit test for firmware file search Add KUnit testing of the wm_adsp code that searches for firmware files. Also make the SND_SOC_WM_ADSP Kconfig symbol visible if KUNIT is enabled so that wm_adsp can be manually included for KUnit testing. The firmware filename is composed of several fields, some of which are optional, and there is a search algorithm to fallback from specific to generic versions of firmware for a device. This KUnit test verifies that wm_adsp is searching for the correct sequence of filenames. The are two ways of testing this, and both are used in this KUnit test. 1. Trap the calls to firmware_request_nowarn() and test that the sequence of filenames request is correct. This is the most thorough test because it proves that exactly the expected filenames are requested, in the correct order. But it doesn't fully cover regression testing. If a change to the search algorithm changes the expected sequence of requested files, the test must also be changed to expect that new sequence. If the expectation is wrong, the tests can pass (because the search order is as expected) while picking a different file in some cases from what it did before the change. 2. Test which file is picked from a simulated directory of files. This is better for regression testing because it is independent of the search algorithm. It does not need to change if the search algorithm changes. It is not testing exactly which files the algorithm searches for, only which file it eventually picks from a given set of available files. In other words, the regression test is: does it still pick the same file from the same directory of files? But it is impractical for thorough testing. It doesn't prove that exactly the correct files were searched for, unless it was to test with every possible combination of file names and directory content that could ever exist. Clearly this is impossible to implement, since the number of combations of possible valid filenames in a directory and number of files in a directory is astronomically large. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 14 +- sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm_adsp_fw_find_test.c | 1223 +++++++++++++++++++++++++++++++ 3 files changed, 1238 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/wm_adsp_fw_find_test.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index adb3fb923be3..f9e6a83e55c6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -398,7 +398,7 @@ config SND_SOC_WM_HUBS default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m config SND_SOC_WM_ADSP - tristate + tristate "Cirrus Logic wm_adsp driver" if KUNIT select FW_CS_DSP select SND_SOC_COMPRESS default y if SND_SOC_MADERA=y @@ -424,6 +424,18 @@ config SND_SOC_WM_ADSP default m if SND_SOC_CS35L56=m default m if SND_SOC_CS48L32=m +config SND_SOC_WM_ADSP_TEST + tristate "KUnit tests for Cirrus Logic wm_adsp" if !KUNIT_ALL_TESTS + depends on KUNIT + depends on SND_SOC_WM_ADSP + default KUNIT_ALL_TESTS + help + This builds KUnit tests for the Cirrus Logic wm_adsp library. + For more information on KUnit and unit tests in general, + please refer to the KUnit documentation in + Documentation/dev-tools/kunit/. + If in doubt, say "N". + config SND_SOC_AB8500_CODEC tristate depends on ABX500_CORE diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3ddee5298721..172861d17cfd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -361,6 +361,7 @@ snd-soc-wcd938x-sdw-y := wcd938x-sdw.o snd-soc-wcd939x-y := wcd939x.o snd-soc-wcd939x-sdw-y := wcd939x-sdw.o snd-soc-wm-adsp-y := wm_adsp.o +snd-soc-wm-adsp-test-y := wm_adsp_fw_find_test.o snd-soc-wm0010-y := wm0010.o snd-soc-wm1250-ev1-y := wm1250-ev1.o snd-soc-wm2000-y := wm2000.o @@ -862,6 +863,7 @@ obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o +obj-$(CONFIG_SND_SOC_WM_ADSP_TEST) += snd-soc-wm-adsp-test.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o diff --git a/sound/soc/codecs/wm_adsp_fw_find_test.c b/sound/soc/codecs/wm_adsp_fw_find_test.c new file mode 100644 index 000000000000..556221d38a50 --- /dev/null +++ b/sound/soc/codecs/wm_adsp_fw_find_test.c @@ -0,0 +1,1223 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Test cases for wm_adsp library. +// +// Copyright (C) 2025 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include "wm_adsp.h" + +KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); + +struct wm_adsp_fw_find_test { + struct wm_adsp dsp; + + const struct firmware *found_wmfw_firmware; + const struct firmware *found_bin_firmware; + char *found_wmfw_filename; + char *found_bin_filename; + char searched_fw_files[768]; +}; + +struct wm_adsp_fw_find_test_params { + const char *part; + const char *dsp_name; + const char *fwf_name; + const char *system_name; + const char *alsa_name; + bool wmfw_optional; + bool bin_mandatory; + + /* If non-NULL this file should be returned as "found" */ + const char *expect_wmfw; + + /* If non-NULL this file should be returned as "found" */ + const char *expect_bin; + + /* Space-separated list of filenames in expected order of searching */ + const char *expected_searches; + + /* NULL-terminated array of pointers to filenames to simulate directory content */ + const char * const *dir_files; +}; + +/* Dummy struct firmware to return from wm_adsp_request_firmware_files */ +static const struct firmware wm_adsp_find_test_dummy_firmware; + +/* Simple lookup of a filename in a list of names */ +static int wm_adsp_fw_find_test_firmware_request_simple_stub(const struct firmware **firmware, + const char *filename, + struct device *dev) +{ + struct kunit *test = kunit_get_current_test(); + const struct wm_adsp_fw_find_test_params *params = test->param_value; + int i; + + /* Non-parameterized test? */ + if (!params) + return -ENOENT; + + if (!params->dir_files) + return -ENOENT; + + for (i = 0; params->dir_files[i]; i++) { + if (strcmp(params->dir_files[i], filename) == 0) { + *firmware = &wm_adsp_find_test_dummy_firmware; + return 0; + } + } + + return -ENOENT; +} + +static void wm_adsp_fw_find_test_pick_file(struct kunit *test) +{ + struct wm_adsp_fw_find_test *priv = test->priv; + const struct wm_adsp_fw_find_test_params *params = test->param_value; + struct wm_adsp *dsp = &priv->dsp; + int i, ret; + + /* Concatenate string of dir content for error messages */ + for (i = 0; params->dir_files[i]; i++) { + strlcat(priv->searched_fw_files, params->dir_files[i], + sizeof(priv->searched_fw_files)); + strlcat(priv->searched_fw_files, ";", + sizeof(priv->searched_fw_files)); + } + + dsp->cs_dsp.name = params->dsp_name; + dsp->part = params->part; + dsp->fwf_name = params->fwf_name; + dsp->system_name = params->system_name; + dsp->component->name_prefix = params->alsa_name; + dsp->wmfw_optional = params->wmfw_optional; + dsp->bin_mandatory = params->bin_mandatory; + + kunit_activate_static_stub(test, + wm_adsp_firmware_request, + wm_adsp_fw_find_test_firmware_request_simple_stub); + + ret = wm_adsp_request_firmware_files(dsp, + &priv->found_wmfw_firmware, + &priv->found_wmfw_filename, + &priv->found_bin_firmware, + &priv->found_bin_filename); + kunit_deactivate_static_stub(test, wm_adsp_firmware_request); + KUNIT_EXPECT_EQ_MSG(test, ret, + (params->expect_wmfw || params->expect_bin) ? 0 : -ENOENT, + "%s\n", priv->searched_fw_files); + + KUNIT_EXPECT_EQ_MSG(test, !!priv->found_wmfw_filename, !!params->expect_wmfw, + "%s\n", priv->searched_fw_files); + KUNIT_EXPECT_EQ_MSG(test, !!priv->found_bin_filename, !!params->expect_bin, + "%s\n", priv->searched_fw_files); + + if (params->expect_wmfw) { + KUNIT_EXPECT_STREQ_MSG(test, priv->found_wmfw_filename, params->expect_wmfw, + "%s\n", priv->searched_fw_files); + } + + if (params->expect_bin) { + KUNIT_EXPECT_STREQ_MSG(test, priv->found_bin_filename, params->expect_bin, + "%s\n", priv->searched_fw_files); + } +} + +static int wm_adsp_fw_find_test_firmware_request_stub(const struct firmware **firmware, + const char *filename, + struct device *dev) +{ + struct kunit *test = kunit_get_current_test(); + const struct wm_adsp_fw_find_test_params *params = test->param_value; + struct wm_adsp_fw_find_test *priv = test->priv; + + /* + * Searches are accumulated as a single string of space-separated names. + * The list of expected searches are stored the same way in + * struct wm_adsp_fw_find_test_params. This allows for comparision using + * a simple KUNIT_EXPECT_STREQ(), which avoids the risk of bugs in a + * more complex custom comparison. + */ + if (priv->searched_fw_files[0] != '\0') + strlcat(priv->searched_fw_files, " ", sizeof(priv->searched_fw_files)); + + strlcat(priv->searched_fw_files, filename, sizeof(priv->searched_fw_files)); + + /* Non-parameterized test? */ + if (!params) + return -ENOENT; + + if (params->expect_wmfw && (strcmp(filename, params->expect_wmfw) == 0)) { + *firmware = &wm_adsp_find_test_dummy_firmware; + return 0; + } + + if (params->expect_bin && (strcmp(filename, params->expect_bin) == 0)) { + *firmware = &wm_adsp_find_test_dummy_firmware; + return 0; + } + + return -ENOENT; +} + +static void wm_adsp_fw_find_test_search_order(struct kunit *test) +{ + struct wm_adsp_fw_find_test *priv = test->priv; + const struct wm_adsp_fw_find_test_params *params = test->param_value; + struct wm_adsp *dsp = &priv->dsp; + + dsp->cs_dsp.name = params->dsp_name; + dsp->part = params->part; + dsp->fwf_name = params->fwf_name; + dsp->system_name = params->system_name; + dsp->component->name_prefix = params->alsa_name; + dsp->wmfw_optional = params->wmfw_optional; + + kunit_activate_static_stub(test, + wm_adsp_firmware_request, + wm_adsp_fw_find_test_firmware_request_stub); + + wm_adsp_request_firmware_files(dsp, + &priv->found_wmfw_firmware, + &priv->found_wmfw_filename, + &priv->found_bin_firmware, + &priv->found_bin_filename); + + kunit_deactivate_static_stub(test, wm_adsp_firmware_request); + + KUNIT_EXPECT_STREQ(test, priv->searched_fw_files, params->expected_searches); + + KUNIT_EXPECT_EQ(test, !!priv->found_wmfw_filename, !!params->expect_wmfw); + if (params->expect_wmfw) + KUNIT_EXPECT_STREQ(test, priv->found_wmfw_filename, params->expect_wmfw); + + KUNIT_EXPECT_EQ(test, !!priv->found_bin_filename, !!params->expect_bin); + if (params->expect_bin) + KUNIT_EXPECT_STREQ(test, priv->found_bin_filename, params->expect_bin); + + /* Either we get a filename and firmware, or neither */ + KUNIT_EXPECT_EQ(test, !!priv->found_wmfw_filename, !!priv->found_wmfw_firmware); + KUNIT_EXPECT_EQ(test, !!priv->found_bin_filename, !!priv->found_bin_firmware); +} + +static void wm_adsp_fw_find_test_find_firmware_byindex(struct kunit *test) +{ + struct wm_adsp_fw_find_test *priv = test->priv; + struct wm_adsp *dsp = &priv->dsp; + const char *fw_name; + + dsp->cs_dsp.name = "cs1234"; + dsp->part = "dsp1"; + for (dsp->fw = 0;; dsp->fw++) { + fw_name = wm_adsp_get_fwf_name_by_index(dsp->fw); + if (!fw_name) + break; + + kunit_activate_static_stub(test, + wm_adsp_firmware_request, + wm_adsp_fw_find_test_firmware_request_stub); + + wm_adsp_request_firmware_files(dsp, + &priv->found_wmfw_firmware, + &priv->found_wmfw_filename, + &priv->found_bin_firmware, + &priv->found_bin_filename); + + kunit_deactivate_static_stub(test, wm_adsp_firmware_request); + + KUNIT_EXPECT_NOT_NULL_MSG(test, + strstr(priv->searched_fw_files, fw_name), + "fw#%d Did not find '%s' in '%s'\n", + dsp->fw, fw_name, priv->searched_fw_files); + } +} + +static int wm_adsp_fw_find_test_case_init(struct kunit *test) +{ + struct wm_adsp_fw_find_test *priv; + struct device *test_dev; + int ret; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Require dummy struct snd_soc_component for the alsa name prefix string */ + priv->dsp.component = kunit_kzalloc(test, sizeof(*priv->dsp.component), GFP_KERNEL); + if (!priv->dsp.component) + return -ENOMEM; + + test->priv = priv; + + /* Create dummy amp device */ + test_dev = kunit_device_register(test, "wm_adsp_test_drv"); + if (IS_ERR(test_dev)) + return PTR_ERR(test_dev); + + priv->dsp.cs_dsp.dev = get_device(test_dev); + if (!priv->dsp.cs_dsp.dev) + return -ENODEV; + + ret = kunit_add_action_or_reset(test, _put_device_wrapper, priv->dsp.cs_dsp.dev); + if (ret) + return ret; + + return 0; +} + +static void wm_adsp_fw_find_test_case_exit(struct kunit *test) +{ + struct wm_adsp_fw_find_test *priv = test->priv; + + /* + * priv->found_wmfw_firmware and priv->found_bin_firmware are + * dummies not allocated by the real request_firmware() call they + * must not be passed to release_firmware(). + */ + wm_adsp_release_firmware_files(NULL, priv->found_wmfw_filename, + NULL, priv->found_bin_filename); +} + +static void wm_adsp_fw_find_test_param_desc(const struct wm_adsp_fw_find_test_params *param, + char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "%s %s fwf_name:%s system:%s alsa_name:%s %s expects:(%s %s)", + param->part, param->dsp_name, + param->fwf_name ? param->fwf_name : "", + param->system_name ? param->system_name : "", + param->alsa_name ? param->alsa_name : "", + param->wmfw_optional ? "wmfw_optional" : "", + param->expect_wmfw ? param->expect_wmfw : "", + param->expect_bin ? param->expect_bin : ""); +} + +/* Cases where firmware file not found. Tests full search sequence. */ +static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_full_search_cases[] = { + { /* system name and alsa prefix, wmfw mandatory. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw", + }, + { /* system name and alsa prefix, wmfw optional. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* system name only, wmfw mandatory. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw", + }, + { /* system name only, wmfw optional. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + + /* + * TODO: Is this a bug? Device-specific bin is only allowed when there + * is a system_name. But if there isn't any meaningful system name on + * a product, why can't it load firmware files qualified by alsa prefix? + */ + + { /* Alsa prefix, wmfw mandatory. No system name so generic files only. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw", + }, + { /* Alsa prefix, wmfw optional. No system name so generic files only. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .wmfw_optional = true, + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + + { /* fwf_name, system name and alsa prefix, wmfw mandatory. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .fwf_name = "ao", + .expected_searches = + "cirrus/cs1234-ao-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-ao-mbc-vss-abc123.wmfw " + "cs1234-ao-mbc-vss.wmfw " + "cirrus/cs1234-ao-mbc-vss.wmfw", + }, + { /* fwf_name, system name and alsa prefix, wmfw optional. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .fwf_name = "ao", + .wmfw_optional = true, + .expected_searches = + "cirrus/cs1234-ao-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-ao-mbc-vss-abc123.wmfw " + "cirrus/cs1234-ao-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-ao-mbc-vss-abc123.bin " + "cs1234-ao-mbc-vss.wmfw " + "cirrus/cs1234-ao-mbc-vss.wmfw " + "cirrus/cs1234-ao-mbc-vss.bin", + }, +}; +KUNIT_ARRAY_PARAM(wm_adsp_fw_find_full_search, + wm_adsp_fw_find_full_search_cases, + wm_adsp_fw_find_test_param_desc); + +/* Cases with system name and alsa prefix both given. */ +static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_system_alsaname_cases[] = { + { /* Fully-qualified wmfw exists. No bin */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + }, + { /* Optional fully-qualified wmfw exists. No bin */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + }, + { /* Fully-qualified wmfw and bin exist. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + }, + { /* Optional fully-qualified wmfw and fully-qualified bin exist. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + }, + { /* wmfw matches system name only. No bin */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* Optional wmfw matches system name only. No bin */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* wmfw matches system name only. Fully-qualified bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + }, + { /* Optional wmfw matches system name only. Fully-qualified bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + }, + { /* wmfw and bin match system name only. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* Optional wmfw and bin match system name only. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* Optional wmfw not found. bin matches fully-qualified name. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin", + }, + { /* Optional wmfw not found. bin matches system name only. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* No qualified wmfw. Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified optional wmfw. Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified wmfw. Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified optional wmfw. Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified or legacy wmfw. Generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No optional qualified or legacy wmfw. Generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified or legacy wmfw. Generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No optional qualified or legacy wmfw. Generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No optional qualified or generic wmfw. Generic bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, +}; +KUNIT_ARRAY_PARAM(wm_adsp_fw_find_system_alsaname, + wm_adsp_fw_find_system_alsaname_cases, + wm_adsp_fw_find_test_param_desc); + +/* Cases with system name but without alsa name prefix. */ +static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_system_cases[] = { + { /* Qualified wmfw found. No bin */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* Optional qualified wmfw found. No bin */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* Qualified wmfw found. Qualified bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* Optional qualified wmfw found. Qualified bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* Optional wmfw not found. Qualified bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin", + }, + { /* No qualified wmfw. Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified optional wmfw. Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified wmfw. Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified optional wmfw. Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified or legacy wmfw. Generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No optional qualified or legacy wmfw. Generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No qualified or legacy wmfw. Generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No optional qualified or legacy wmfw. Generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No optional qualified or generic wmfw. Generic bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123", + .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc123.bin " + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, +}; +KUNIT_ARRAY_PARAM(wm_adsp_fw_find_system, + wm_adsp_fw_find_system_cases, + wm_adsp_fw_find_test_param_desc); + +/* Cases without system name but with alsa name prefix. */ +static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_alsaname_cases[] = { + { /* Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* wmfw optional. Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* wmfw optional. Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Optional generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Optional generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy or generic wmfw. Generic bin found. */ + .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1", + .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, +}; +KUNIT_ARRAY_PARAM(wm_adsp_fw_find_alsaname, + wm_adsp_fw_find_alsaname_cases, + wm_adsp_fw_find_test_param_desc); + +/* Cases without system name or alsa name prefix. */ +static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_noqual_cases[] = { + { /* Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* wmfw optional. Legacy generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", + .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* wmfw optional. Legacy generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", + .wmfw_optional = true, + .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Optional generic wmfw found. No bin. */ + .part = "cs1234", .dsp_name = "dsp1", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy wmfw. Optional generic wmfw and bin found. */ + .part = "cs1234", .dsp_name = "dsp1", + .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, + { /* No legacy or generic wmfw. Generic bin found. */ + .part = "cs1234", .dsp_name = "dsp1", + .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .expected_searches = + "cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.wmfw " + "cirrus/cs1234-dsp1-mbc-vss.bin", + }, +}; +KUNIT_ARRAY_PARAM(wm_adsp_fw_find_noqual, + wm_adsp_fw_find_noqual_cases, + wm_adsp_fw_find_test_param_desc); + +/* + * Tests for filename normalization. The system name and alsa prefix strings + * should be converted to lower-case and delimiters are converted to '-', except + * for '.' which is preserved. + */ +static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_normalization_cases[] = { + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-vendor.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-vendor.bin", + }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor Device", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-vendor-device.bin", + }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor_Device", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-vendor-device.bin", + }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "1234:56AB", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-1234-56ab.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-1234-56ab.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-1234-56ab.bin", + }, + + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc", + .alsa_name = "LEFT", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-left.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc-left.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc-left.bin", + }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc", + .alsa_name = "LEFT AMP", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.bin", + }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc", + .alsa_name = "Left Amp", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.bin", + }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc", + .alsa_name = "Amp_1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-amp-1.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc-amp-1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc-amp-1.bin", + }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc", + .alsa_name = "cs1234.1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.bin", + }, +}; +KUNIT_ARRAY_PARAM(wm_adsp_fw_find_normalization, + wm_adsp_fw_find_normalization_cases, + wm_adsp_fw_find_test_param_desc); + +/* + * Dummy directory content for regression tests. + * DSP part name and system name are used to select different available + * files. + * + * System: + * WFBF1111 = wmfw and bin fully-qualified + * WSBF1111 = wmfw system-qualified, bin fully-qualified + * WSBS1111 = wmfw and bin system-qualified + * WFXX1111 = wmfw fully-qualified, bin not present + * XXBF1111 = wmfw not present, bin fully-qualified + * + * Part: + * cs1234 = for testing fully-qualified configurations + * cs1234nobin = generic wmfw without a bin available + * wm1234 = legacy wmfw and bin + * wm1234nobin = legacy wmfw without bin + */ +static const char * const wm_adsp_fw_find_test_dir_all_files[] = { + "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw", + "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.wmfw", + "cirrus/cs1234-dsp1-mbc-vss-wfbf1111.wmfw", + "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw", + "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.wmfw", + "cirrus/cs1234-dsp1-mbc-vss-wfxx1111.wmfw", + "cirrus/cs1234-dsp1-mbc-vss.wmfw", + "cirrus/cs1234nobin-dsp1-mbc-vss.wmfw", + "cirrus/wm1234-dsp1-mbc-vss.wmfw", + "cirrus/wm1234nobin-dsp1-mbc-vss.wmfw", + "wm1234-dsp1-mbc-vss.wmfw", + "wm1234nobin-dsp1-mbc-vss.wmfw", + "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin", + "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.bin", + "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-amp1.bin", + "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-l1u2.bin", + "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.bin", + "cirrus/cs1234-dsp1-mbc-vss-xxbf1111-amp1.bin", + "cirrus/cs1234-dsp1-mbc-vss.bin", + "cirrus/wm1234-dsp1-mbc-vss.bin", + "wm1234-dsp1-mbc-vss.bin", +}; + +/* + * Regression testing that a change in the search algorithm doesn't change + * which file is picked. This doesn't cover every possible combination, only + * those that are already in use and typical cases. + * + * It wouldn't be efficent to fully prove the algorithm this way (too many + * directory content combinations would be needed, and it only infers what the + * algorithm searched for, it doesn't prove exactly what searches were made). + * So the main testing is done by checking for the expected file searches. + * This regression test is independent of the search algorithm. + * + * The main tests already prove that the algorithm only searches for files + * with the correct qualifiers so we can assume that files with the wrong + * qualifiers would not be picked and there's no need to test for that here. + */ +static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_pick_cases[] = { + /* + * Amps + */ + { /* Full info, wmfw and bin fully-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw and bin fully-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111", + .alsa_name = "l1u2", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw only system-qualified, bin fully-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBF1111", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-amp1.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw only system-qualified, bin fully-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBF1111", + .alsa_name = "l1u2", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-l1u2.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw optional but present, and bin fully-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw and bin only system-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBS1111", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw optional but system-qualified wmfm present, bin fully-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBF1111", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-amp1.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw optional not present, and bin fully-qualified */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "XXBF1111", + .alsa_name = "amp1", .wmfw_optional = true, + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-xxbf1111-amp1.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw and bin fully-qualified, bin mandatory and present */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111", + .alsa_name = "amp1", .bin_mandatory = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw and bin fully-qualified, bin mandatory but not present */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFXX1111", + .alsa_name = "amp1", .bin_mandatory = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfxx1111.wmfw", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw optional but present, bin mandatory but not present */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFXX1111", + .alsa_name = "amp1", .wmfw_optional = true, .bin_mandatory = true, + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfxx1111.wmfw", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw and bin not present, generic fallbacks are present */ + .part = "cs1234", .dsp_name = "dsp1", .system_name = "XXXX1111", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* Full info, wmfw and bin not present, generic wmfw present */ + .part = "cs1234nobin", .dsp_name = "dsp1", .system_name = "XXXX1111", + .alsa_name = "amp1", + .expect_wmfw = "cirrus/cs1234nobin-dsp1-mbc-vss.wmfw", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + + /* + * Codecs + */ + { /* No qualifiers. Generic wmfws exist, legacy should be chosen. */ + .part = "wm1234nobin", .dsp_name = "dsp1", + .expect_wmfw = "wm1234nobin-dsp1-mbc-vss.wmfw", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* No qualifiers. Generic wmfw and bin exist, legacy should be chosen */ + .part = "wm1234", .dsp_name = "dsp1", + .expect_wmfw = "wm1234-dsp1-mbc-vss.wmfw", + .expect_bin = "wm1234-dsp1-mbc-vss.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* No qualifiers. New generic wmfw exists, no legacy files. */ + .part = "cs1234nobin", .dsp_name = "dsp1", + .expect_wmfw = "cirrus/cs1234nobin-dsp1-mbc-vss.wmfw", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, + { /* No qualifiers. New generic wmfw and bin exist, no legacy files. */ + .part = "cs1234", .dsp_name = "dsp1", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw", + .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin", + .dir_files = wm_adsp_fw_find_test_dir_all_files, + }, +}; +KUNIT_ARRAY_PARAM(wm_adsp_fw_find_pick, + wm_adsp_fw_find_pick_cases, + wm_adsp_fw_find_test_param_desc); + +static struct kunit_case wm_adsp_fw_find_test_cases[] = { + KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order, + wm_adsp_fw_find_full_search_gen_params), + + KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order, + wm_adsp_fw_find_system_alsaname_gen_params), + + KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order, + wm_adsp_fw_find_system_gen_params), + + KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order, + wm_adsp_fw_find_alsaname_gen_params), + + KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order, + wm_adsp_fw_find_noqual_gen_params), + + KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order, + wm_adsp_fw_find_normalization_gen_params), + + KUNIT_CASE_PARAM(wm_adsp_fw_find_test_pick_file, + wm_adsp_fw_find_pick_gen_params), + + KUNIT_CASE(wm_adsp_fw_find_test_find_firmware_byindex), + + { } /* terminator */ +}; + +static struct kunit_suite wm_adsp_fw_find_test_suite = { + .name = "wm-adsp-fw-find", + .init = wm_adsp_fw_find_test_case_init, + .exit = wm_adsp_fw_find_test_case_exit, + .test_cases = wm_adsp_fw_find_test_cases, +}; + +kunit_test_suite(wm_adsp_fw_find_test_suite); + +MODULE_DESCRIPTION("KUnit test for Cirrus Logic wm_adsp driver"); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); -- cgit v1.2.3 From 2c7c27025374abbdeda201ad103ddf27e8079aec Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:12 +0000 Subject: ASoC: wm_adsp: Remove duplicated code to find firmware file The 3rd search case in wm_adsp_request_firmware_files() does exactly the same bin file searches as the case immediately above it. Merge the conditional from the 3rd case into the second case so the duplicated code can be removed. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-6-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 346ede149a9e..a3f297510526 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -828,9 +828,10 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, } if (system_name) { - if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, - cirrus_dir, system_name, - NULL, "wmfw")) { + ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, + NULL, "wmfw"); + if (!ret || dsp->wmfw_optional) { if (suffix) wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, cirrus_dir, system_name, @@ -840,24 +841,10 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, cirrus_dir, system_name, NULL, "bin"); - return 0; - } - } - /* Check system-specific bin without wmfw before falling back to generic */ - if (dsp->wmfw_optional && system_name) { - if (suffix) - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - cirrus_dir, system_name, - suffix, "bin"); - - if (!*coeff_firmware) - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - cirrus_dir, system_name, - NULL, "bin"); - - if (*coeff_firmware) - return 0; + if (*wmfw_firmware || (dsp->wmfw_optional && *coeff_firmware)) + return 0; + } } /* Check legacy location */ -- cgit v1.2.3 From f8f0c68c75214e326c0d4cbcab8ecab882201f48 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:13 +0000 Subject: ASoC: wm_adsp: Use consistent error checks in wm_adsp_request_firmware_files() Use a consistent pattern of error checking in wm_adsp_request_firmware_files(). - The integer return value of wm_adsp_request_firmware_file() reports unrecoverable errors, for example -ENOMEM. - A NULL struct firmware pointer is a valid result. This not an error, not all DSPs require both files, some may not require any files. Previously wm_adsp_request_firmware_files() was using a mix of checking the return value and checking the struct firmware pointer to determine whether a file was found. It wasn't checking for unrecoverable errors. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-7-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 92 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index a3f297510526..9f39db680e07 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -753,7 +753,7 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, struct cs_dsp *cs_dsp = &dsp->cs_dsp; const char *fwf; char *s, c; - int ret = 0; + int ret; if (dsp->fwf_name) fwf = dsp->fwf_name; @@ -791,15 +791,17 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, } ret = wm_adsp_firmware_request(firmware, *filename, cs_dsp->dev); - if (ret != 0) { - adsp_dbg(dsp, "Failed to request '%s'\n", *filename); + if (ret < 0) { + adsp_dbg(dsp, "Failed to request '%s': %d\n", *filename, ret); kfree(*filename); *filename = NULL; + if (ret != -ENOENT) + return ret; } else { adsp_dbg(dsp, "Found '%s'\n", *filename); } - return ret; + return 0; } static const char * const cirrus_dir = "cirrus/"; @@ -817,12 +819,19 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, suffix = dsp->fwf_suffix; if (system_name && suffix) { - if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, - cirrus_dir, system_name, - suffix, "wmfw")) { - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - cirrus_dir, system_name, - suffix, "bin"); + ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, + suffix, "wmfw"); + if (ret < 0) + goto err; + + if (*wmfw_firmware) { + ret = wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + cirrus_dir, system_name, + suffix, "bin"); + if (ret < 0) + goto err; + return 0; } } @@ -831,16 +840,27 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, cirrus_dir, system_name, NULL, "wmfw"); - if (!ret || dsp->wmfw_optional) { - if (suffix) - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - cirrus_dir, system_name, - suffix, "bin"); + if (ret < 0) + goto err; + + if (*wmfw_firmware || dsp->wmfw_optional) { + if (suffix) { + ret = wm_adsp_request_firmware_file(dsp, + coeff_firmware, coeff_filename, + cirrus_dir, system_name, + suffix, "bin"); + if (ret < 0) + goto err; + } - if (!*coeff_firmware) - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - cirrus_dir, system_name, - NULL, "bin"); + if (!*coeff_firmware) { + ret = wm_adsp_request_firmware_file(dsp, + coeff_firmware, coeff_filename, + cirrus_dir, system_name, + NULL, "bin"); + if (ret < 0) + goto err; + } if (*wmfw_firmware || (dsp->wmfw_optional && *coeff_firmware)) return 0; @@ -848,19 +868,32 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, } /* Check legacy location */ - if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, - "", NULL, NULL, "wmfw")) { - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - "", NULL, NULL, "bin"); + ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + "", NULL, NULL, "wmfw"); + if (ret < 0) + goto err; + + if (*wmfw_firmware) { + ret = wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + "", NULL, NULL, "bin"); + if (ret < 0) + goto err; + return 0; } /* Fall back to generic wmfw and optional matching bin */ ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, cirrus_dir, NULL, NULL, "wmfw"); - if (!ret || dsp->wmfw_optional) { - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - cirrus_dir, NULL, NULL, "bin"); + if (ret < 0) + goto err; + + if (*wmfw_firmware || dsp->wmfw_optional) { + ret = wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + cirrus_dir, NULL, NULL, "bin"); + if (ret < 0) + goto err; + return 0; } @@ -869,7 +902,12 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, dsp->fwf_name ? dsp->fwf_name : dsp->cs_dsp.name, wm_adsp_fw[dsp->fw].file, system_name, suffix); - return -ENOENT; + ret = -ENOENT; +err: + wm_adsp_release_firmware_files(*wmfw_firmware, *wmfw_filename, + *coeff_firmware, *coeff_filename); + + return ret; } EXPORT_SYMBOL_IF_KUNIT(wm_adsp_request_firmware_files); -- cgit v1.2.3 From 66170cc7ed59fb7e1e192e53f1d690bd04e8c720 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:14 +0000 Subject: ASoC: wm_adsp: Convert '/' to '-' when normalizing firmware filenames Don't preserve '/' in firmware filename fields - convert it to '-' like other punctuation characters. The code originally normalized the entire string, including the directory prefix. To prevent breaking the directory it had to preserve '/' characters in the name, but this meant that the system name and ALSA prefix must not contain those characters. It's trivial to skip the directory name prefix and start the normalization after it, and that means the normalization does not need to make a special case for '/'. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-8-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 9f39db680e07..74c503fc3088 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -776,16 +776,15 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, return -ENOMEM; /* - * Make sure that filename is lower-case and any non alpha-numeric - * characters except full stop and forward slash are replaced with - * hyphens. + * Make sure that filename after dir is lower-case and any non-alpha-numeric + * characters except full-stop are replaced with hyphens. */ - s = *filename; + s = *filename + strlen(dir); while (*s) { c = *s; if (isalnum(c)) *s = tolower(c); - else if ((c != '.') && (c != '/')) + else if (c != '.') *s = '-'; s++; } -- cgit v1.2.3 From d8a4c96082e6f5c7aaf6f3e101effe7ff0ea4d6e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:15 +0000 Subject: ASoC: wm_adsp: Add KUnit test cases for '/' in firmware filenames Add test cases that '/' in the system name or ALSA prefix are converted to '-' in the firmware filename. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-9-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp_fw_find_test.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/codecs/wm_adsp_fw_find_test.c b/sound/soc/codecs/wm_adsp_fw_find_test.c index 556221d38a50..11047851fd80 100644 --- a/sound/soc/codecs/wm_adsp_fw_find_test.c +++ b/sound/soc/codecs/wm_adsp_fw_find_test.c @@ -949,6 +949,13 @@ static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_normalization_ca "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw " "cirrus/cs1234-dsp1-mbc-vss-vendor-device.bin", }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor/Device", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-vendor-device.bin", + }, { .part = "cs1234", .dsp_name = "dsp1", .system_name = "1234:56AB", .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-1234-56ab.wmfw", @@ -997,6 +1004,14 @@ static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_normalization_ca "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.wmfw " "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.bin", }, + { + .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc", + .alsa_name = "Spk/Jack", + .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-spk-jack.wmfw", + .expected_searches = + "cirrus/cs1234-dsp1-mbc-vss-abc-spk-jack.wmfw " + "cirrus/cs1234-dsp1-mbc-vss-abc-spk-jack.bin", + }, }; KUNIT_ARRAY_PARAM(wm_adsp_fw_find_normalization, wm_adsp_fw_find_normalization_cases, -- cgit v1.2.3 From 7bca3ca55ef53ca66fdf6e663290d0596a8f520d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:16 +0000 Subject: ASoC: wm_adsp: Use a struct to pass around firmware struct and filename Bundle the pointers to struct firmware and its filename into a new struct wm_adsp_fw_files. This simplifies passing these pointers around. Changes are also needed to the test cases in wm_adsp_fw_find_test.c that use this API. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-10-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 123 +++++++++++++------------------- sound/soc/codecs/wm_adsp.h | 21 +++--- sound/soc/codecs/wm_adsp_fw_find_test.c | 47 ++++-------- 3 files changed, 77 insertions(+), 114 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 74c503fc3088..bcc77797c09a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -717,20 +717,15 @@ int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); -VISIBLE_IF_KUNIT void wm_adsp_release_firmware_files(const struct firmware *wmfw_firmware, - char *wmfw_filename, - const struct firmware *coeff_firmware, - char *coeff_filename) +VISIBLE_IF_KUNIT void wm_adsp_release_firmware_files(struct wm_adsp_fw_files *fw) { - KUNIT_STATIC_STUB_REDIRECT(wm_adsp_release_firmware_files, - wmfw_firmware, wmfw_filename, - coeff_firmware, coeff_filename); + KUNIT_STATIC_STUB_REDIRECT(wm_adsp_release_firmware_files, fw); - release_firmware(wmfw_firmware); - kfree(wmfw_filename); + release_firmware(fw->wmfw.firmware); + kfree(fw->wmfw.filename); - release_firmware(coeff_firmware); - kfree(coeff_filename); + release_firmware(fw->coeff.firmware); + kfree(fw->coeff.filename); } EXPORT_SYMBOL_IF_KUNIT(wm_adsp_release_firmware_files); @@ -745,7 +740,7 @@ VISIBLE_IF_KUNIT int wm_adsp_firmware_request(const struct firmware **firmware, EXPORT_SYMBOL_IF_KUNIT(wm_adsp_firmware_request); static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, - const struct firmware **firmware, char **filename, + struct wm_adsp_fw_file *fw, const char *dir, const char *system_name, const char *asoc_component_prefix, const char *filetype) @@ -761,25 +756,25 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, fwf = dsp->cs_dsp.name; if (system_name && asoc_component_prefix) - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part, - fwf, wm_adsp_fw[dsp->fw].file, system_name, - asoc_component_prefix, filetype); + fw->filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part, + fwf, wm_adsp_fw[dsp->fw].file, system_name, + asoc_component_prefix, filetype); else if (system_name) - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part, - fwf, wm_adsp_fw[dsp->fw].file, system_name, - filetype); + fw->filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part, + fwf, wm_adsp_fw[dsp->fw].file, system_name, + filetype); else - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, fwf, - wm_adsp_fw[dsp->fw].file, filetype); + fw->filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, fwf, + wm_adsp_fw[dsp->fw].file, filetype); - if (*filename == NULL) + if (!fw->filename) return -ENOMEM; /* * Make sure that filename after dir is lower-case and any non-alpha-numeric * characters except full-stop are replaced with hyphens. */ - s = *filename + strlen(dir); + s = fw->filename + strlen(dir); while (*s) { c = *s; if (isalnum(c)) @@ -789,15 +784,15 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, s++; } - ret = wm_adsp_firmware_request(firmware, *filename, cs_dsp->dev); + ret = wm_adsp_firmware_request(&fw->firmware, fw->filename, cs_dsp->dev); if (ret < 0) { - adsp_dbg(dsp, "Failed to request '%s': %d\n", *filename, ret); - kfree(*filename); - *filename = NULL; + adsp_dbg(dsp, "Failed to request '%s': %d\n", fw->filename, ret); + kfree(fw->filename); + fw->filename = NULL; if (ret != -ENOENT) return ret; } else { - adsp_dbg(dsp, "Found '%s'\n", *filename); + adsp_dbg(dsp, "Found '%s'\n", fw->filename); } return 0; @@ -805,10 +800,7 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, static const char * const cirrus_dir = "cirrus/"; VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, - const struct firmware **wmfw_firmware, - char **wmfw_filename, - const struct firmware **coeff_firmware, - char **coeff_filename) + struct wm_adsp_fw_files *fw) { const char *system_name = dsp->system_name; const char *suffix = dsp->component->name_prefix; @@ -818,14 +810,14 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, suffix = dsp->fwf_suffix; if (system_name && suffix) { - ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, cirrus_dir, system_name, suffix, "wmfw"); if (ret < 0) goto err; - if (*wmfw_firmware) { - ret = wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + if (fw->wmfw.firmware) { + ret = wm_adsp_request_firmware_file(dsp, &fw->coeff, cirrus_dir, system_name, suffix, "bin"); if (ret < 0) @@ -836,45 +828,43 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, } if (system_name) { - ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, cirrus_dir, system_name, NULL, "wmfw"); if (ret < 0) goto err; - if (*wmfw_firmware || dsp->wmfw_optional) { + if (fw->wmfw.firmware || dsp->wmfw_optional) { if (suffix) { ret = wm_adsp_request_firmware_file(dsp, - coeff_firmware, coeff_filename, + &fw->coeff, cirrus_dir, system_name, suffix, "bin"); if (ret < 0) goto err; } - if (!*coeff_firmware) { + if (!fw->coeff.firmware) { ret = wm_adsp_request_firmware_file(dsp, - coeff_firmware, coeff_filename, + &fw->coeff, cirrus_dir, system_name, NULL, "bin"); if (ret < 0) goto err; } - if (*wmfw_firmware || (dsp->wmfw_optional && *coeff_firmware)) + if (fw->wmfw.firmware || (dsp->wmfw_optional && fw->coeff.firmware)) return 0; } } /* Check legacy location */ - ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, - "", NULL, NULL, "wmfw"); + ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, "", NULL, NULL, "wmfw"); if (ret < 0) goto err; - if (*wmfw_firmware) { - ret = wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, - "", NULL, NULL, "bin"); + if (fw->wmfw.firmware) { + ret = wm_adsp_request_firmware_file(dsp, &fw->coeff, "", NULL, NULL, "bin"); if (ret < 0) goto err; @@ -882,13 +872,13 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, } /* Fall back to generic wmfw and optional matching bin */ - ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, cirrus_dir, NULL, NULL, "wmfw"); if (ret < 0) goto err; - if (*wmfw_firmware || dsp->wmfw_optional) { - ret = wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + if (fw->wmfw.firmware || dsp->wmfw_optional) { + ret = wm_adsp_request_firmware_file(dsp, &fw->coeff, cirrus_dir, NULL, NULL, "bin"); if (ret < 0) goto err; @@ -903,8 +893,7 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, ret = -ENOENT; err: - wm_adsp_release_firmware_files(*wmfw_firmware, *wmfw_filename, - *coeff_firmware, *coeff_filename); + wm_adsp_release_firmware_files(fw); return ret; } @@ -939,29 +928,23 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); struct wm_adsp *dsp = &dsps[w->shift]; + struct wm_adsp_fw_files fw = { 0 }; int ret = 0; - char *wmfw_filename = NULL; - const struct firmware *wmfw_firmware = NULL; - char *coeff_filename = NULL; - const struct firmware *coeff_firmware = NULL; dsp->component = component; switch (event) { case SND_SOC_DAPM_POST_PMU: - ret = wm_adsp_request_firmware_files(dsp, - &wmfw_firmware, &wmfw_filename, - &coeff_firmware, &coeff_filename); + ret = wm_adsp_request_firmware_files(dsp, &fw); if (ret) break; ret = cs_dsp_adsp1_power_up(&dsp->cs_dsp, - wmfw_firmware, wmfw_filename, - coeff_firmware, coeff_filename, + fw.wmfw.firmware, fw.wmfw.filename, + fw.coeff.firmware, fw.coeff.filename, wm_adsp_fw_text[dsp->fw]); - wm_adsp_release_firmware_files(wmfw_firmware, wmfw_filename, - coeff_firmware, coeff_filename); + wm_adsp_release_firmware_files(&fw); break; case SND_SOC_DAPM_PRE_PMD: cs_dsp_adsp1_power_down(&dsp->cs_dsp); @@ -1037,33 +1020,27 @@ EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware) { + struct wm_adsp_fw_files fw = { 0 }; int ret = 0; - char *wmfw_filename = NULL; - const struct firmware *wmfw_firmware = NULL; - char *coeff_filename = NULL; - const struct firmware *coeff_firmware = NULL; if (load_firmware) { - ret = wm_adsp_request_firmware_files(dsp, - &wmfw_firmware, &wmfw_filename, - &coeff_firmware, &coeff_filename); + ret = wm_adsp_request_firmware_files(dsp, &fw); if (ret) return ret; } - if (dsp->bin_mandatory && !coeff_firmware) { + if (dsp->bin_mandatory && !fw.coeff.firmware) { ret = -ENOENT; goto err; } ret = cs_dsp_power_up(&dsp->cs_dsp, - wmfw_firmware, wmfw_filename, - coeff_firmware, coeff_filename, + fw.wmfw.firmware, fw.wmfw.filename, + fw.coeff.firmware, fw.coeff.filename, wm_adsp_fw_text[dsp->fw]); err: - wm_adsp_release_firmware_files(wmfw_firmware, wmfw_filename, - coeff_firmware, coeff_filename); + wm_adsp_release_firmware_files(&fw); return ret; } diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 6560dfc8c08d..e314c2299196 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -79,6 +79,16 @@ struct wm_adsp { SOC_ENUM_EXT(dspname " Firmware", wm_adsp_fw_enum[num], \ wm_adsp_fw_get, wm_adsp_fw_put) +struct wm_adsp_fw_file { + const struct firmware *firmware; + char *filename; +}; + +struct wm_adsp_fw_files { + struct wm_adsp_fw_file wmfw; + struct wm_adsp_fw_file coeff; +}; + extern const struct soc_enum wm_adsp_fw_enum[]; int wm_adsp1_init(struct wm_adsp *dsp); @@ -144,18 +154,11 @@ int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, #if IS_ENABLED(CONFIG_KUNIT) const char *wm_adsp_get_fwf_name_by_index(int index); -void wm_adsp_release_firmware_files(const struct firmware *wmfw_firmware, - char *wmfw_filename, - const struct firmware *coeff_firmware, - char *coeff_filename); +void wm_adsp_release_firmware_files(struct wm_adsp_fw_files *fw); int wm_adsp_firmware_request(const struct firmware **firmware, const char *filename, struct device *dev); -int wm_adsp_request_firmware_files(struct wm_adsp *dsp, - const struct firmware **wmfw_firmware, - char **wmfw_filename, - const struct firmware **coeff_firmware, - char **coeff_filename); +int wm_adsp_request_firmware_files(struct wm_adsp *dsp, struct wm_adsp_fw_files *fw); #endif #endif diff --git a/sound/soc/codecs/wm_adsp_fw_find_test.c b/sound/soc/codecs/wm_adsp_fw_find_test.c index 11047851fd80..44c26e991b35 100644 --- a/sound/soc/codecs/wm_adsp_fw_find_test.c +++ b/sound/soc/codecs/wm_adsp_fw_find_test.c @@ -16,10 +16,7 @@ KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); struct wm_adsp_fw_find_test { struct wm_adsp dsp; - const struct firmware *found_wmfw_firmware; - const struct firmware *found_bin_firmware; - char *found_wmfw_filename; - char *found_bin_filename; + struct wm_adsp_fw_files found_fw; char searched_fw_files[768]; }; @@ -101,28 +98,24 @@ static void wm_adsp_fw_find_test_pick_file(struct kunit *test) wm_adsp_firmware_request, wm_adsp_fw_find_test_firmware_request_simple_stub); - ret = wm_adsp_request_firmware_files(dsp, - &priv->found_wmfw_firmware, - &priv->found_wmfw_filename, - &priv->found_bin_firmware, - &priv->found_bin_filename); + ret = wm_adsp_request_firmware_files(dsp, &priv->found_fw); kunit_deactivate_static_stub(test, wm_adsp_firmware_request); KUNIT_EXPECT_EQ_MSG(test, ret, (params->expect_wmfw || params->expect_bin) ? 0 : -ENOENT, "%s\n", priv->searched_fw_files); - KUNIT_EXPECT_EQ_MSG(test, !!priv->found_wmfw_filename, !!params->expect_wmfw, + KUNIT_EXPECT_EQ_MSG(test, !!priv->found_fw.wmfw.filename, !!params->expect_wmfw, "%s\n", priv->searched_fw_files); - KUNIT_EXPECT_EQ_MSG(test, !!priv->found_bin_filename, !!params->expect_bin, + KUNIT_EXPECT_EQ_MSG(test, !!priv->found_fw.coeff.filename, !!params->expect_bin, "%s\n", priv->searched_fw_files); if (params->expect_wmfw) { - KUNIT_EXPECT_STREQ_MSG(test, priv->found_wmfw_filename, params->expect_wmfw, + KUNIT_EXPECT_STREQ_MSG(test, priv->found_fw.wmfw.filename, params->expect_wmfw, "%s\n", priv->searched_fw_files); } if (params->expect_bin) { - KUNIT_EXPECT_STREQ_MSG(test, priv->found_bin_filename, params->expect_bin, + KUNIT_EXPECT_STREQ_MSG(test, priv->found_fw.coeff.filename, params->expect_bin, "%s\n", priv->searched_fw_files); } } @@ -181,27 +174,23 @@ static void wm_adsp_fw_find_test_search_order(struct kunit *test) wm_adsp_firmware_request, wm_adsp_fw_find_test_firmware_request_stub); - wm_adsp_request_firmware_files(dsp, - &priv->found_wmfw_firmware, - &priv->found_wmfw_filename, - &priv->found_bin_firmware, - &priv->found_bin_filename); + wm_adsp_request_firmware_files(dsp, &priv->found_fw); kunit_deactivate_static_stub(test, wm_adsp_firmware_request); KUNIT_EXPECT_STREQ(test, priv->searched_fw_files, params->expected_searches); - KUNIT_EXPECT_EQ(test, !!priv->found_wmfw_filename, !!params->expect_wmfw); + KUNIT_EXPECT_EQ(test, !!priv->found_fw.wmfw.filename, !!params->expect_wmfw); if (params->expect_wmfw) - KUNIT_EXPECT_STREQ(test, priv->found_wmfw_filename, params->expect_wmfw); + KUNIT_EXPECT_STREQ(test, priv->found_fw.wmfw.filename, params->expect_wmfw); - KUNIT_EXPECT_EQ(test, !!priv->found_bin_filename, !!params->expect_bin); + KUNIT_EXPECT_EQ(test, !!priv->found_fw.coeff.filename, !!params->expect_bin); if (params->expect_bin) - KUNIT_EXPECT_STREQ(test, priv->found_bin_filename, params->expect_bin); + KUNIT_EXPECT_STREQ(test, priv->found_fw.coeff.filename, params->expect_bin); /* Either we get a filename and firmware, or neither */ - KUNIT_EXPECT_EQ(test, !!priv->found_wmfw_filename, !!priv->found_wmfw_firmware); - KUNIT_EXPECT_EQ(test, !!priv->found_bin_filename, !!priv->found_bin_firmware); + KUNIT_EXPECT_EQ(test, !!priv->found_fw.wmfw.filename, !!priv->found_fw.wmfw.firmware); + KUNIT_EXPECT_EQ(test, !!priv->found_fw.coeff.filename, !!priv->found_fw.coeff.firmware); } static void wm_adsp_fw_find_test_find_firmware_byindex(struct kunit *test) @@ -221,12 +210,7 @@ static void wm_adsp_fw_find_test_find_firmware_byindex(struct kunit *test) wm_adsp_firmware_request, wm_adsp_fw_find_test_firmware_request_stub); - wm_adsp_request_firmware_files(dsp, - &priv->found_wmfw_firmware, - &priv->found_wmfw_filename, - &priv->found_bin_firmware, - &priv->found_bin_filename); - + wm_adsp_request_firmware_files(dsp, &priv->found_fw); kunit_deactivate_static_stub(test, wm_adsp_firmware_request); KUNIT_EXPECT_NOT_NULL_MSG(test, @@ -278,8 +262,7 @@ static void wm_adsp_fw_find_test_case_exit(struct kunit *test) * dummies not allocated by the real request_firmware() call they * must not be passed to release_firmware(). */ - wm_adsp_release_firmware_files(NULL, priv->found_wmfw_filename, - NULL, priv->found_bin_filename); + wm_adsp_release_firmware_files(&priv->found_fw); } static void wm_adsp_fw_find_test_param_desc(const struct wm_adsp_fw_find_test_params *param, -- cgit v1.2.3 From 8fc5c7895185d1119ae76b509892a1d14e0bd483 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 10 Mar 2026 14:18:17 +0000 Subject: ASoC: wm_adsp: Combine some similar code in firmware file search In wm_adsp_request_firmware_files() squash the if (system_name && suffix) and the following if (system_name) blocks together. This removes some duplicated code. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260310141817.1871794-11-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 49 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index bcc77797c09a..a5fa0db250f2 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -804,47 +804,42 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, { const char *system_name = dsp->system_name; const char *suffix = dsp->component->name_prefix; + bool require_bin_suffix = false; int ret = 0; if (dsp->fwf_suffix) suffix = dsp->fwf_suffix; - if (system_name && suffix) { + if (system_name) { ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, cirrus_dir, system_name, suffix, "wmfw"); if (ret < 0) goto err; - if (fw->wmfw.firmware) { + if (suffix) { + if (fw->wmfw.firmware) { + require_bin_suffix = true; + } else { + /* Fallback to name without suffix */ + ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, + cirrus_dir, system_name, + NULL, "wmfw"); + if (ret < 0) + goto err; + } + } + + /* Look for matching .bin file */ + if (fw->wmfw.firmware || dsp->wmfw_optional) { ret = wm_adsp_request_firmware_file(dsp, &fw->coeff, cirrus_dir, system_name, suffix, "bin"); if (ret < 0) goto err; - return 0; - } - } - - if (system_name) { - ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, - cirrus_dir, system_name, - NULL, "wmfw"); - if (ret < 0) - goto err; - - if (fw->wmfw.firmware || dsp->wmfw_optional) { - if (suffix) { - ret = wm_adsp_request_firmware_file(dsp, - &fw->coeff, - cirrus_dir, system_name, - suffix, "bin"); - if (ret < 0) - goto err; - } - - if (!fw->coeff.firmware) { + if (suffix && !fw->coeff.firmware && !require_bin_suffix) { + /* Fallback to name without suffix */ ret = wm_adsp_request_firmware_file(dsp, &fw->coeff, cirrus_dir, system_name, @@ -852,10 +847,10 @@ VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp, if (ret < 0) goto err; } - - if (fw->wmfw.firmware || (dsp->wmfw_optional && fw->coeff.firmware)) - return 0; } + + if (fw->wmfw.firmware || (dsp->wmfw_optional && fw->coeff.firmware)) + return 0; } /* Check legacy location */ -- cgit v1.2.3