Rework the way that kernel log messages are rate-limited or suppressed
while running the cs_dsp KUnit tests.
Under normal conditions cs_dsp doesn't produce an unreasonable number of
log messages, and state changes are relatively infrequent. But the KUnit
tests run through a very large number of test cases, especially error
cases, and this produces an unusually large amount of log output from
cs_dsp.
The original fix for this in commit
10db9f6899dd ("firmware: cs_dsp:
rate-limit log messages in KUnit builds") was effective but not pretty.
It involved different definitions of the log macros for KUnit and
not-KUnit builds, and exported variables for the KUnit tests to disable
log messages. I would have preferred to turn the log macros into real
functions that can contain a KUNIT_STATIC_STUB_REDIRECT(), but the
dev_xxx() macros don't have a version that take va_args, so they can't
be wrapped by a function.
This patch enables the use of a KUNIT_STATIC_STUB_REDIRECT() instead
of exported variables, and avoids the need for different definitions of
the debug macros in KUnit and not-KUnit builds.
- A new function cs_dsp_can_emit_message() returns true if the
messages can be emitted to the kernel log. In a normal not-KUnit build
this function collapses to simply returning true. In KUnit builds it
will rate-limit output, and this uses a single static rate limiter so
it limits the overall rate across all cs_dsp log messages. The KUnit
test can redirect it to change the suppression behavior.
- The cs_dsp debug message macros are changed to only call the dev_xxx()
if cs_dsp_can_emit_message() returns true. These are still macros so
there is no problem wrapping the dev_xxx(). For a normal not-KUnit
build cs_dsp_can_emit_message() always returns true so these macros
simplify down to being identical to calling dev_xxx() directly.
- The KUnit tests that cause a lot of cs_dsp messages now redirect
cs_dsp_can_emit_message() to a local function. This returns false
to suppress cs_dsp messages, unless DEBUG is defined for that test.
I have checked that for a x86_64 production (non-KUnit) build the
disassembled cs_dsp.o is identical to what was generated from the
original code. So the complier is correctly simplifying the
cs_dsp_can_emit_message() and macros down to only the call to dev_xxx().
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://patch.msgid.link/20260310130343.1791951-1-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
* Cirrus Logic International Semiconductor Ltd.
*/
+#include <kunit/static_stub.h>
#include <kunit/visibility.h>
#include <linux/cleanup.h>
#include <linux/ctype.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/ratelimit.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
/*
* When the KUnit test is running the error-case tests will cause a lot
* of messages. Rate-limit to prevent overflowing the kernel log buffer
- * during KUnit test runs.
+ * during KUnit test runs and allow the test to redirect this function.
+ * In normal (not KUnit) builds this collapses to only return true.
*/
-#if IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST)
-bool cs_dsp_suppress_err_messages;
-EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_err_messages);
+VISIBLE_IF_KUNIT bool cs_dsp_can_emit_message(void)
+{
+ KUNIT_STATIC_STUB_REDIRECT(cs_dsp_can_emit_message);
-bool cs_dsp_suppress_warn_messages;
-EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_warn_messages);
+ if (IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST)) {
+ static DEFINE_RATELIMIT_STATE(_rs,
+ DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+ return __ratelimit(&_rs);
+ }
-bool cs_dsp_suppress_info_messages;
-EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_info_messages);
+ return true;
+}
+EXPORT_SYMBOL_IF_KUNIT(cs_dsp_can_emit_message);
-#define cs_dsp_err(_dsp, fmt, ...) \
- do { \
- if (!cs_dsp_suppress_err_messages) \
- dev_err_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+#define cs_dsp_err(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
-#define cs_dsp_warn(_dsp, fmt, ...) \
- do { \
- if (!cs_dsp_suppress_warn_messages) \
- dev_warn_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+
+#define cs_dsp_warn(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
-#define cs_dsp_info(_dsp, fmt, ...) \
- do { \
- if (!cs_dsp_suppress_info_messages) \
- dev_info_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+
+#define cs_dsp_info(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+ } while (false)
+
+#define cs_dsp_dbg(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
-#define cs_dsp_dbg(_dsp, fmt, ...) \
- dev_dbg_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#else
-#define cs_dsp_err(_dsp, fmt, ...) \
- dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#define cs_dsp_warn(_dsp, fmt, ...) \
- dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#define cs_dsp_info(_dsp, fmt, ...) \
- dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#define cs_dsp_dbg(_dsp, fmt, ...) \
- dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#endif
#define ADSP1_CONTROL_1 0x00
#define ADSP1_CONTROL_2 0x02
#define FW_CS_DSP_H
#if IS_ENABLED(CONFIG_KUNIT)
-extern bool cs_dsp_suppress_err_messages;
-extern bool cs_dsp_suppress_warn_messages;
-extern bool cs_dsp_suppress_info_messages;
+bool cs_dsp_can_emit_message(void);
#endif
#endif /* ifndef FW_CS_DSP_H */
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
KUNIT_EXPECT_EQ(test, reg_val, payload_data);
}
+static bool cs_dsp_bin_test_can_emit_message_hook(void)
+{
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
+}
+
static int cs_dsp_bin_test_common_init(struct kunit *test, struct cs_dsp *dsp,
int wmdr_ver)
{
* The large number of test cases will cause an unusually large amount
* of dev_info() messages from cs_dsp, so suppress these.
*/
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_bin_test_can_emit_message_hook);
return 0;
}
-static void cs_dsp_bin_test_exit(struct kunit *test)
-{
- cs_dsp_suppress_info_messages = false;
-}
-
static int cs_dsp_bin_test_halo_init_common(struct kunit *test, int wmdr_ver)
{
struct cs_dsp *dsp;
static struct kunit_suite cs_dsp_bin_test_halo = {
.name = "cs_dsp_bin_halo",
.init = cs_dsp_bin_test_halo_init,
- .exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_halo,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = {
.name = "cs_dsp_bin_adsp2_32bit",
.init = cs_dsp_bin_test_adsp2_32bit_init,
- .exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = {
.name = "cs_dsp_bin_adsp2_16bit",
.init = cs_dsp_bin_test_adsp2_16bit_init,
- .exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
0);
}
-static void cs_dsp_bin_err_test_exit(struct kunit *test)
+static bool cs_dsp_bin_err_test_can_emit_message_hook(void)
{
- cs_dsp_suppress_err_messages = false;
- cs_dsp_suppress_warn_messages = false;
- cs_dsp_suppress_info_messages = false;
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
}
static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so suppress messages.
*/
- cs_dsp_suppress_err_messages = true;
- cs_dsp_suppress_warn_messages = true;
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_bin_err_test_can_emit_message_hook);
return 0;
}
static struct kunit_suite cs_dsp_bin_err_test_halo = {
.name = "cs_dsp_bin_err_halo",
.init = cs_dsp_bin_err_test_halo_init,
- .exit = cs_dsp_bin_err_test_exit,
.test_cases = cs_dsp_bin_err_test_cases,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_err_test_adsp2_32bit = {
.name = "cs_dsp_bin_err_adsp2_32bit",
.init = cs_dsp_bin_err_test_adsp2_32bit_init,
- .exit = cs_dsp_bin_err_test_exit,
.test_cases = cs_dsp_bin_err_test_cases,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_err_test_adsp2_16bit = {
.name = "cs_dsp_bin_err_adsp2_16bit",
.init = cs_dsp_bin_err_test_adsp2_16bit_init,
- .exit = cs_dsp_bin_err_test_exit,
.test_cases = cs_dsp_bin_err_test_cases,
.attr.speed = KUNIT_SPEED_SLOW,
};
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);
}
+static bool cs_dsp_wmfw_test_can_emit_message_hook(void)
+{
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
+}
+
static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp,
int wmfw_version)
{
* The large number of test cases will cause an unusually large amount
* of dev_info() messages from cs_dsp, so suppress these.
*/
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_wmfw_test_can_emit_message_hook);
return 0;
}
-static void cs_dsp_wmfw_test_exit(struct kunit *test)
-{
- cs_dsp_suppress_info_messages = false;
-}
-
static int cs_dsp_wmfw_test_halo_init(struct kunit *test)
{
struct cs_dsp *dsp;
static struct kunit_suite cs_dsp_wmfw_test_halo = {
.name = "cs_dsp_wmfwV3_halo",
.init = cs_dsp_wmfw_test_halo_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_halo,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
.attr.speed = KUNIT_SPEED_SLOW,
};
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
-EOVERFLOW);
}
-static void cs_dsp_wmfw_err_test_exit(struct kunit *test)
+static bool cs_dsp_wmfw_err_test_can_emit_message_hook(void)
{
- cs_dsp_suppress_err_messages = false;
- cs_dsp_suppress_warn_messages = false;
- cs_dsp_suppress_info_messages = false;
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
}
static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so suppress messages.
*/
- cs_dsp_suppress_err_messages = true;
- cs_dsp_suppress_warn_messages = true;
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_wmfw_err_test_can_emit_message_hook);
return 0;
}
static struct kunit_suite cs_dsp_wmfw_err_test_halo = {
.name = "cs_dsp_wmfwV3_err_halo",
.init = cs_dsp_wmfw_err_test_halo_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v3,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_err_adsp2_32bit",
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v0,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_err_adsp2_32bit",
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v1,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_err_adsp2_32bit",
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v2,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_err_adsp2_16bit",
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v0,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_err_adsp2_16bit",
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v1,
.attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_err_adsp2_16bit",
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v2,
.attr.speed = KUNIT_SPEED_SLOW,
};