Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firmware: cs_dsp: rate-limit log messages in KUnit builds

Use the dev_*_ratelimit() macros if the cs_dsp KUnit tests are enabled
in the build, and allow the KUnit tests to disable message output.

Some of the KUnit tests cause a very large number of log messages from
cs_dsp, because the tests perform many different test cases. This could
cause some lines to be dropped from the kernel log. Dropped lines can
prevent the KUnit wrappers from parsing the ktap output in the dmesg log.

The KUnit builds of cs_dsp export three bools that the KUnit tests can
use to entirely disable log output of err, warn and info messages. Some
tests have been updated to use this, replacing the previous fudge of a
usleep() in the exit handler of each test. We don't necessarily want to
disable all log messages if they aren't expected to be excessive,
so the rate-limiting allows leaving some logging enabled.

The rate-limited macros are not used in normal builds because it is not
appropriate to rate-limit every message. That could cause important
messages to be dropped, and there wouldn't be such a high rate of
messages in normal operation.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Reported-by: Mark Brown <broonie@kernel.org>
Closes: https://lore.kernel.org/linux-sound/af393f08-facb-4c44-a054-1f61254803ec@opensource.cirrus.com/T/#t
Fixes: cd8c058499b6 ("firmware: cs_dsp: Add KUnit testing of bin error cases")
Link: https://patch.msgid.link/20260130171256.863152-1-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Richard Fitzgerald and committed by
Mark Brown
10db9f68 611c7d22

+138 -14
+37
drivers/firmware/cirrus/cs_dsp.c
··· 9 9 * Cirrus Logic International Semiconductor Ltd. 10 10 */ 11 11 12 + #include <kunit/visibility.h> 12 13 #include <linux/cleanup.h> 13 14 #include <linux/ctype.h> 14 15 #include <linux/debugfs.h> ··· 25 24 #include <linux/firmware/cirrus/cs_dsp.h> 26 25 #include <linux/firmware/cirrus/wmfw.h> 27 26 27 + #include "cs_dsp.h" 28 + 29 + /* 30 + * When the KUnit test is running the error-case tests will cause a lot 31 + * of messages. Rate-limit to prevent overflowing the kernel log buffer 32 + * during KUnit test runs. 33 + */ 34 + #if IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST) 35 + bool cs_dsp_suppress_err_messages; 36 + EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_err_messages); 37 + 38 + bool cs_dsp_suppress_warn_messages; 39 + EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_warn_messages); 40 + 41 + bool cs_dsp_suppress_info_messages; 42 + EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_info_messages); 43 + 44 + #define cs_dsp_err(_dsp, fmt, ...) \ 45 + do { \ 46 + if (!cs_dsp_suppress_err_messages) \ 47 + dev_err_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \ 48 + } while (false) 49 + #define cs_dsp_warn(_dsp, fmt, ...) \ 50 + do { \ 51 + if (!cs_dsp_suppress_warn_messages) \ 52 + dev_warn_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \ 53 + } while (false) 54 + #define cs_dsp_info(_dsp, fmt, ...) \ 55 + do { \ 56 + if (!cs_dsp_suppress_info_messages) \ 57 + dev_info_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \ 58 + } while (false) 59 + #define cs_dsp_dbg(_dsp, fmt, ...) \ 60 + dev_dbg_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 61 + #else 28 62 #define cs_dsp_err(_dsp, fmt, ...) \ 29 63 dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 30 64 #define cs_dsp_warn(_dsp, fmt, ...) \ ··· 68 32 dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 69 33 #define cs_dsp_dbg(_dsp, fmt, ...) \ 70 34 dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) 35 + #endif 71 36 72 37 #define ADSP1_CONTROL_1 0x00 73 38 #define ADSP1_CONTROL_2 0x02
+18
drivers/firmware/cirrus/cs_dsp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * cs_dsp.h -- Private header for cs_dsp driver. 4 + * 5 + * Copyright (C) 2026 Cirrus Logic, Inc. and 6 + * Cirrus Logic International Semiconductor Ltd. 7 + */ 8 + 9 + #ifndef FW_CS_DSP_H 10 + #define FW_CS_DSP_H 11 + 12 + #if IS_ENABLED(CONFIG_KUNIT) 13 + extern bool cs_dsp_suppress_err_messages; 14 + extern bool cs_dsp_suppress_warn_messages; 15 + extern bool cs_dsp_suppress_info_messages; 16 + #endif 17 + 18 + #endif /* ifndef FW_CS_DSP_H */
+21 -1
drivers/firmware/cirrus/test/cs_dsp_test_bin.c
··· 17 17 #include <linux/random.h> 18 18 #include <linux/regmap.h> 19 19 20 + #include "../cs_dsp.h" 21 + 20 22 /* 21 23 * Test method is: 22 24 * ··· 2226 2224 return ret; 2227 2225 2228 2226 /* Automatically call cs_dsp_remove() when test case ends */ 2229 - return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 2227 + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 2228 + if (ret) 2229 + return ret; 2230 + 2231 + /* 2232 + * The large number of test cases will cause an unusually large amount 2233 + * of dev_info() messages from cs_dsp, so suppress these. 2234 + */ 2235 + cs_dsp_suppress_info_messages = true; 2236 + 2237 + return 0; 2238 + } 2239 + 2240 + static void cs_dsp_bin_test_exit(struct kunit *test) 2241 + { 2242 + cs_dsp_suppress_info_messages = false; 2230 2243 } 2231 2244 2232 2245 static int cs_dsp_bin_test_halo_init(struct kunit *test) ··· 2553 2536 static struct kunit_suite cs_dsp_bin_test_halo = { 2554 2537 .name = "cs_dsp_bin_halo", 2555 2538 .init = cs_dsp_bin_test_halo_init, 2539 + .exit = cs_dsp_bin_test_exit, 2556 2540 .test_cases = cs_dsp_bin_test_cases_halo, 2557 2541 }; 2558 2542 2559 2543 static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = { 2560 2544 .name = "cs_dsp_bin_adsp2_32bit", 2561 2545 .init = cs_dsp_bin_test_adsp2_32bit_init, 2546 + .exit = cs_dsp_bin_test_exit, 2562 2547 .test_cases = cs_dsp_bin_test_cases_adsp2, 2563 2548 }; 2564 2549 2565 2550 static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = { 2566 2551 .name = "cs_dsp_bin_adsp2_16bit", 2567 2552 .init = cs_dsp_bin_test_adsp2_16bit_init, 2553 + .exit = cs_dsp_bin_test_exit, 2568 2554 .test_cases = cs_dsp_bin_test_cases_adsp2, 2569 2555 }; 2570 2556
+18 -6
drivers/firmware/cirrus/test/cs_dsp_test_bin_error.c
··· 18 18 #include <linux/string.h> 19 19 #include <linux/vmalloc.h> 20 20 21 + #include "../cs_dsp.h" 22 + 21 23 KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); 22 24 KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *); 23 25 ··· 382 380 383 381 static void cs_dsp_bin_err_test_exit(struct kunit *test) 384 382 { 385 - /* 386 - * Testing error conditions can produce a lot of log output 387 - * from cs_dsp error messages, so rate limit the test cases. 388 - */ 389 - usleep_range(200, 500); 383 + cs_dsp_suppress_err_messages = false; 384 + cs_dsp_suppress_warn_messages = false; 385 + cs_dsp_suppress_info_messages = false; 390 386 } 391 387 392 388 static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *dsp, ··· 474 474 return ret; 475 475 476 476 /* Automatically call cs_dsp_remove() when test case ends */ 477 - return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 477 + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 478 + if (ret) 479 + return ret; 480 + 481 + /* 482 + * Testing error conditions can produce a lot of log output 483 + * from cs_dsp error messages, so suppress messages. 484 + */ 485 + cs_dsp_suppress_err_messages = true; 486 + cs_dsp_suppress_warn_messages = true; 487 + cs_dsp_suppress_info_messages = true; 488 + 489 + return 0; 478 490 } 479 491 480 492 static int cs_dsp_bin_err_test_halo_init(struct kunit *test)
+25 -1
drivers/firmware/cirrus/test/cs_dsp_test_wmfw.c
··· 18 18 #include <linux/string.h> 19 19 #include <linux/vmalloc.h> 20 20 21 + #include "../cs_dsp.h" 22 + 21 23 /* 22 24 * Test method is: 23 25 * ··· 1855 1853 return ret; 1856 1854 1857 1855 /* Automatically call cs_dsp_remove() when test case ends */ 1858 - return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 1856 + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 1857 + if (ret) 1858 + return ret; 1859 + 1860 + /* 1861 + * The large number of test cases will cause an unusually large amount 1862 + * of dev_info() messages from cs_dsp, so suppress these. 1863 + */ 1864 + cs_dsp_suppress_info_messages = true; 1865 + 1866 + return 0; 1867 + } 1868 + 1869 + static void cs_dsp_wmfw_test_exit(struct kunit *test) 1870 + { 1871 + cs_dsp_suppress_info_messages = false; 1859 1872 } 1860 1873 1861 1874 static int cs_dsp_wmfw_test_halo_init(struct kunit *test) ··· 2180 2163 static struct kunit_suite cs_dsp_wmfw_test_halo = { 2181 2164 .name = "cs_dsp_wmfwV3_halo", 2182 2165 .init = cs_dsp_wmfw_test_halo_init, 2166 + .exit = cs_dsp_wmfw_test_exit, 2183 2167 .test_cases = cs_dsp_wmfw_test_cases_halo, 2184 2168 }; 2185 2169 2186 2170 static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = { 2187 2171 .name = "cs_dsp_wmfwV0_adsp2_32bit", 2188 2172 .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init, 2173 + .exit = cs_dsp_wmfw_test_exit, 2189 2174 .test_cases = cs_dsp_wmfw_test_cases_adsp2, 2190 2175 }; 2191 2176 2192 2177 static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = { 2193 2178 .name = "cs_dsp_wmfwV1_adsp2_32bit", 2194 2179 .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init, 2180 + .exit = cs_dsp_wmfw_test_exit, 2195 2181 .test_cases = cs_dsp_wmfw_test_cases_adsp2, 2196 2182 }; 2197 2183 2198 2184 static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = { 2199 2185 .name = "cs_dsp_wmfwV2_adsp2_32bit", 2200 2186 .init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init, 2187 + .exit = cs_dsp_wmfw_test_exit, 2201 2188 .test_cases = cs_dsp_wmfw_test_cases_adsp2, 2202 2189 }; 2203 2190 2204 2191 static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = { 2205 2192 .name = "cs_dsp_wmfwV0_adsp2_16bit", 2206 2193 .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init, 2194 + .exit = cs_dsp_wmfw_test_exit, 2207 2195 .test_cases = cs_dsp_wmfw_test_cases_adsp2, 2208 2196 }; 2209 2197 2210 2198 static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = { 2211 2199 .name = "cs_dsp_wmfwV1_adsp2_16bit", 2212 2200 .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init, 2201 + .exit = cs_dsp_wmfw_test_exit, 2213 2202 .test_cases = cs_dsp_wmfw_test_cases_adsp2, 2214 2203 }; 2215 2204 2216 2205 static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = { 2217 2206 .name = "cs_dsp_wmfwV2_adsp2_16bit", 2218 2207 .init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init, 2208 + .exit = cs_dsp_wmfw_test_exit, 2219 2209 .test_cases = cs_dsp_wmfw_test_cases_adsp2, 2220 2210 }; 2221 2211
+18 -6
drivers/firmware/cirrus/test/cs_dsp_test_wmfw_error.c
··· 18 18 #include <linux/string.h> 19 19 #include <linux/vmalloc.h> 20 20 21 + #include "../cs_dsp.h" 22 + 21 23 KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *); 22 24 KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *); 23 25 ··· 991 989 992 990 static void cs_dsp_wmfw_err_test_exit(struct kunit *test) 993 991 { 994 - /* 995 - * Testing error conditions can produce a lot of log output 996 - * from cs_dsp error messages, so rate limit the test cases. 997 - */ 998 - usleep_range(200, 500); 992 + cs_dsp_suppress_err_messages = false; 993 + cs_dsp_suppress_warn_messages = false; 994 + cs_dsp_suppress_info_messages = false; 999 995 } 1000 996 1001 997 static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp, ··· 1072 1072 return ret; 1073 1073 1074 1074 /* Automatically call cs_dsp_remove() when test case ends */ 1075 - return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 1075 + ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp); 1076 + if (ret) 1077 + return ret; 1078 + 1079 + /* 1080 + * Testing error conditions can produce a lot of log output 1081 + * from cs_dsp error messages, so suppress messages. 1082 + */ 1083 + cs_dsp_suppress_err_messages = true; 1084 + cs_dsp_suppress_warn_messages = true; 1085 + cs_dsp_suppress_info_messages = true; 1086 + 1087 + return 0; 1076 1088 } 1077 1089 1078 1090 static int cs_dsp_wmfw_err_test_halo_init(struct kunit *test)
+1
drivers/firmware/cirrus/test/cs_dsp_tests.c
··· 12 12 MODULE_LICENSE("GPL"); 13 13 MODULE_IMPORT_NS("FW_CS_DSP"); 14 14 MODULE_IMPORT_NS("FW_CS_DSP_KUNIT_TEST_UTILS"); 15 + MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");