diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index ee2dd5349697d..e1a4090596609 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -599,6 +599,13 @@ struct softirq_action
asmlinkage void do_softirq(void);
asmlinkage void __do_softirq(void);
+#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST)
+void softirq_kunit_run_empty_worker(void);
+bool softirq_kunit_empty_worker_active(void);
+int softirq_kunit_run_empty_ksoftirqd(struct task_struct **owner,
+ int *owner_cpu, bool *armed);
+#endif
+
#ifdef CONFIG_PREEMPT_RT
extern void do_softirq_post_smp_call_flush(unsigned int was_pending);
#else
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 0d5fe265e354b..f6ed814f1f94a 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -10,6 +10,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define INSTANTIATE_EXPORTED_INTERRUPT_DISABLE
+#include <kunit/test-bug.h>
+#include <kunit/visibility.h>
+#include <linux/completion.h>
#include <linux/export.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
@@ -609,6 +612,190 @@ asmlinkage __visible void do_softirq(void)
#endif /* !CONFIG_PREEMPT_RT */
+#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST)
+enum softirq_kunit_empty_worker_phase {
+ SOFTIRQ_KUNIT_EMPTY_IDLE,
+ SOFTIRQ_KUNIT_EMPTY_PREPARING,
+ SOFTIRQ_KUNIT_EMPTY_ARMED,
+ SOFTIRQ_KUNIT_EMPTY_RUNNING,
+ SOFTIRQ_KUNIT_EMPTY_DONE,
+};
+
+struct softirq_kunit_empty_worker {
+ atomic_t phase;
+ struct completion done;
+ u32 held_pending;
+};
+
+static DEFINE_PER_CPU(struct softirq_kunit_empty_worker,
+ softirq_kunit_empty_workers);
+
+/*
+ * Exercise the worker boundaries without entering handle_softirqs().
+ *
+ * The caller must be in preemptible task context with interrupts enabled and
+ * no active softirq context. Like run_ksoftirqd(), this returns with local
+ * interrupts enabled.
+ */
+void softirq_kunit_run_empty_worker(void)
+{
+ ksoftirqd_run_begin();
+ /* Preserve any pending work which raced with the test seam. */
+ wakeup_softirqd();
+ ksoftirqd_run_end();
+}
+EXPORT_SYMBOL_IF_KUNIT(softirq_kunit_run_empty_worker);
+
+bool softirq_kunit_empty_worker_active(void)
+{
+ struct softirq_kunit_empty_worker *worker;
+
+ worker = raw_cpu_ptr(&softirq_kunit_empty_workers);
+ return atomic_read(&worker->phase) == SOFTIRQ_KUNIT_EMPTY_RUNNING &&
+ current == raw_cpu_read(ksoftirqd);
+}
+EXPORT_SYMBOL_IF_KUNIT(softirq_kunit_empty_worker_active);
+
+/*
+ * Force one real ksoftirqd invocation after its smpboot predicate observes
+ * no pending work. The run itself still uses run_ksoftirqd(). The caller must
+ * hold the CPU hotplug read lock across this call so the selected CPU and its
+ * ksoftirqd remain online. The returned task pointer carries no reference.
+ */
+int softirq_kunit_run_empty_ksoftirqd(struct task_struct **owner,
+ int *owner_cpu, bool *armed)
+{
+ struct softirq_kunit_empty_worker *worker;
+ struct task_struct *tsk;
+ unsigned long completed;
+ int this_cpu, phase, ret;
+
+ if (!owner || !owner_cpu || !armed)
+ return -EINVAL;
+ WRITE_ONCE(*owner, NULL);
+ WRITE_ONCE(*owner_cpu, -1);
+ WRITE_ONCE(*armed, false);
+
+ lockdep_assert_cpus_held();
+ this_cpu = get_cpu();
+ worker = this_cpu_ptr(&softirq_kunit_empty_workers);
+ if (atomic_cmpxchg(&worker->phase, SOFTIRQ_KUNIT_EMPTY_IDLE,
+ SOFTIRQ_KUNIT_EMPTY_PREPARING) !=
+ SOFTIRQ_KUNIT_EMPTY_IDLE) {
+ put_cpu();
+ return -EBUSY;
+ }
+
+ tsk = __this_cpu_read(ksoftirqd);
+ if (!tsk) {
+ atomic_set(&worker->phase, SOFTIRQ_KUNIT_EMPTY_IDLE);
+ put_cpu();
+ return -ENODEV;
+ }
+
+ init_completion(&worker->done);
+ worker->held_pending = 0;
+ WRITE_ONCE(*owner_cpu, this_cpu);
+ WRITE_ONCE(*owner, tsk);
+ /* Publish the owner before globally registered callbacks can match it. */
+ smp_store_release(armed, true);
+ atomic_set(&worker->phase, SOFTIRQ_KUNIT_EMPTY_ARMED);
+ wake_up_process(tsk);
+ put_cpu();
+
+ completed = wait_for_completion_timeout(&worker->done, 5 * HZ);
+ if (!completed) {
+ phase = atomic_cmpxchg(&worker->phase,
+ SOFTIRQ_KUNIT_EMPTY_ARMED,
+ SOFTIRQ_KUNIT_EMPTY_IDLE);
+ if (phase == SOFTIRQ_KUNIT_EMPTY_ARMED) {
+ ret = -ETIMEDOUT;
+ goto out_disarm;
+ }
+
+ /*
+ * Once the predicate has claimed the request, synchronize with
+ * complete() before making the completion reusable. CPU hotplug
+ * remains excluded by the caller while this helper runs. RT lock
+ * contention can delay the worker after it claims the request, so
+ * wait for it to finish.
+ */
+ if (phase != SOFTIRQ_KUNIT_EMPTY_RUNNING &&
+ phase != SOFTIRQ_KUNIT_EMPTY_DONE) {
+ ret = -EIO;
+ goto out_disarm;
+ }
+ wait_for_completion(&worker->done);
+ phase = atomic_cmpxchg(&worker->phase,
+ SOFTIRQ_KUNIT_EMPTY_DONE,
+ SOFTIRQ_KUNIT_EMPTY_IDLE);
+ ret = phase == SOFTIRQ_KUNIT_EMPTY_DONE ? -ETIMEDOUT : -EIO;
+ goto out_disarm;
+ }
+
+ phase = atomic_cmpxchg(&worker->phase, SOFTIRQ_KUNIT_EMPTY_DONE,
+ SOFTIRQ_KUNIT_EMPTY_IDLE);
+ ret = phase == SOFTIRQ_KUNIT_EMPTY_DONE ? 0 : -EIO;
+
+out_disarm:
+ WRITE_ONCE(*armed, false);
+ return ret;
+}
+EXPORT_SYMBOL_IF_KUNIT(softirq_kunit_run_empty_ksoftirqd);
+
+static bool softirq_kunit_force_empty_ksoftirqd(void)
+{
+ struct softirq_kunit_empty_worker *worker;
+
+ worker = this_cpu_ptr(&softirq_kunit_empty_workers);
+ if (atomic_read(&worker->phase) != SOFTIRQ_KUNIT_EMPTY_ARMED ||
+ current != __this_cpu_read(ksoftirqd))
+ return false;
+
+ return atomic_cmpxchg(&worker->phase, SOFTIRQ_KUNIT_EMPTY_ARMED,
+ SOFTIRQ_KUNIT_EMPTY_RUNNING) ==
+ SOFTIRQ_KUNIT_EMPTY_ARMED;
+}
+
+static bool softirq_kunit_begin_empty_ksoftirqd(void)
+{
+ struct softirq_kunit_empty_worker *worker;
+
+ worker = this_cpu_ptr(&softirq_kunit_empty_workers);
+ if (atomic_read(&worker->phase) != SOFTIRQ_KUNIT_EMPTY_RUNNING)
+ return false;
+
+ worker->held_pending = local_softirq_pending();
+ set_softirq_pending(0);
+ return true;
+}
+
+static void softirq_kunit_restore_empty_ksoftirqd(bool active)
+{
+ struct softirq_kunit_empty_worker *worker;
+
+ if (!active)
+ return;
+
+ lockdep_assert_irqs_disabled();
+ worker = this_cpu_ptr(&softirq_kunit_empty_workers);
+ or_softirq_pending(worker->held_pending);
+ worker->held_pending = 0;
+}
+
+static void softirq_kunit_finish_empty_ksoftirqd(bool active)
+{
+ struct softirq_kunit_empty_worker *worker;
+
+ if (!active)
+ return;
+
+ worker = this_cpu_ptr(&softirq_kunit_empty_workers);
+ atomic_set(&worker->phase, SOFTIRQ_KUNIT_EMPTY_DONE);
+ complete(&worker->done);
+}
+#endif
+
/*
* We restart softirq processing for at most MAX_SOFTIRQ_RESTART times,
* but break the loop if need_resched() is set or after 2 ms.@@ -1198,11 +1385,50 @@ void __init softirq_init(void)
static int ksoftirqd_should_run(unsigned int cpu)
{
- return local_softirq_pending();
+ unsigned int pending = local_softirq_pending();
+
+#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST)
+ if (!pending && static_branch_unlikely(&kunit_running) &&
+ softirq_kunit_force_empty_ksoftirqd())
+ return 1;
+#endif
+ return pending;
+}
+
+#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST)
+static void softirq_kunit_run_ksoftirqd(unsigned int cpu)
+{
+ bool kunit_empty;
+
+ ksoftirqd_run_begin();
+ kunit_empty = softirq_kunit_begin_empty_ksoftirqd();
+ if (local_softirq_pending()) {
+ /*
+ * We can safely run softirq on inline stack, as we are not deep
+ * in the task stack here.
+ */
+ handle_softirqs(true);
+ softirq_kunit_restore_empty_ksoftirqd(kunit_empty);
+ ksoftirqd_run_end();
+ softirq_kunit_finish_empty_ksoftirqd(kunit_empty);
+ cond_resched();
+ } else {
+ softirq_kunit_restore_empty_ksoftirqd(kunit_empty);
+ ksoftirqd_run_end();
+ softirq_kunit_finish_empty_ksoftirqd(kunit_empty);
+ }
}
+#endif
static void run_ksoftirqd(unsigned int cpu)
{
+#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST)
+ if (static_branch_unlikely(&kunit_running)) {
+ softirq_kunit_run_ksoftirqd(cpu);
+ return;
+ }
+#endif
+
ksoftirqd_run_begin();
if (local_softirq_pending()) {
/*diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig
index 9cdc881b8da29..2dc97edc38b1e 100644
--- a/kernel/trace/rv/Kconfig
+++ b/kernel/trace/rv/Kconfig
@@ -139,7 +139,9 @@ config RV_MONITORS_KUNIT_TEST
These tests verify that monitors correctly detect violations by
triggering fake events and validating the expected reactions.
- Enabling this may slightly increase overhead of some monitors if any
- unrelated KUnit test is running.
+ Building this option, including as a module, adds test-only hooks to
+ some monitored paths. KUnit's static key keeps the hooks dormant while
+ no test is running. Running this or another KUnit suite can temporarily
+ add slight overhead to those paths.
If unsure, say N.
diff --git a/kernel/trace/rv/monitors/irqstate/irqstate_kunit.c b/kernel/trace/rv/monitors/irqstate/irqstate_kunit.c
index e61c500a954a9..40fe9fd4b1fb4 100644
--- a/kernel/trace/rv/monitors/irqstate/irqstate_kunit.c
+++ b/kernel/trace/rv/monitors/irqstate/irqstate_kunit.c
@@ -885,6 +885,37 @@ struct irqstate_inline_bh_ctx {
bool exit_attached;
};
+struct irqstate_empty_worker_ctx {
+ struct task_struct *owner;
+ int owner_cpu;
+ unsigned int entries;
+ unsigned int exits;
+ unsigned int action_entries;
+ unsigned int action_exits;
+ unsigned int event_index;
+ bool armed;
+ bool real_worker;
+ bool inside_pair;
+ bool bad_order;
+ bool bad_boundary_context;
+ bool bad_boundary_cpu;
+ bool actions_at_exit;
+ bool entry_attached;
+ bool exit_attached;
+ bool action_entry_attached;
+ bool action_exit_attached;
+};
+
+static bool irqstate_empty_worker_matches(struct irqstate_empty_worker_ctx *empty_ctx)
+{
+ /* Pairs with owner publication in both empty-worker test paths. */
+ if (!smp_load_acquire(&empty_ctx->armed) ||
+ current != READ_ONCE(empty_ctx->owner))
+ return false;
+
+ return !empty_ctx->real_worker || softirq_kunit_empty_worker_active();
+}
+
static void irqstate_inline_bh_entry(void *data, bool serving,
bool from_hardirq)
{@@ -1154,6 +1185,202 @@ static void rv_test_irqstate_rt_inline_bh(struct kunit *test)
softirq_count() == saved_softirq);
}
+static void irqstate_empty_worker_entry(void *data, bool serving,
+ bool from_hardirq)
+{
+ struct irqstate_empty_worker_ctx *empty_ctx = data;
+
+ if (!irqstate_empty_worker_matches(empty_ctx))
+ return;
+ empty_ctx->entries++;
+ if (empty_ctx->event_index != 0 || empty_ctx->inside_pair)
+ empty_ctx->bad_order = true;
+ empty_ctx->event_index++;
+ empty_ctx->inside_pair = true;
+ if (!serving || !in_serving_softirq() || !irqs_disabled())
+ empty_ctx->bad_boundary_context = true;
+ if (raw_smp_processor_id() != READ_ONCE(empty_ctx->owner_cpu))
+ empty_ctx->bad_boundary_cpu = true;
+}
+
+static void irqstate_empty_worker_exit(void *data, bool serving,
+ bool from_hardirq)
+{
+ struct irqstate_empty_worker_ctx *empty_ctx = data;
+
+ if (!irqstate_empty_worker_matches(empty_ctx))
+ return;
+ empty_ctx->exits++;
+ if (empty_ctx->event_index != 1 || !empty_ctx->inside_pair)
+ empty_ctx->bad_order = true;
+ empty_ctx->event_index++;
+ if (!serving || !in_serving_softirq() || !irqs_disabled())
+ empty_ctx->bad_boundary_context = true;
+ if (raw_smp_processor_id() != READ_ONCE(empty_ctx->owner_cpu))
+ empty_ctx->bad_boundary_cpu = true;
+ empty_ctx->actions_at_exit = empty_ctx->action_entries ||
+ empty_ctx->action_exits;
+ empty_ctx->inside_pair = false;
+}
+
+static void irqstate_empty_worker_action_entry(void *data, unsigned int vec_nr)
+{
+ struct irqstate_empty_worker_ctx *empty_ctx = data;
+
+ if (!irqstate_empty_worker_matches(empty_ctx) ||
+ !empty_ctx->inside_pair)
+ return;
+ (void)vec_nr;
+ empty_ctx->action_entries++;
+ if (raw_smp_processor_id() != empty_ctx->owner_cpu)
+ empty_ctx->bad_boundary_cpu = true;
+}
+
+static void irqstate_empty_worker_action_exit(void *data, unsigned int vec_nr)
+{
+ struct irqstate_empty_worker_ctx *empty_ctx = data;
+
+ if (!irqstate_empty_worker_matches(empty_ctx) ||
+ !empty_ctx->inside_pair)
+ return;
+ (void)vec_nr;
+ empty_ctx->action_exits++;
+ if (raw_smp_processor_id() != empty_ctx->owner_cpu)
+ empty_ctx->bad_boundary_cpu = true;
+}
+
+static void irqstate_empty_worker_detach(void *data)
+{
+ struct irqstate_empty_worker_ctx *empty_ctx = data;
+
+ WRITE_ONCE(empty_ctx->armed, false);
+ if (empty_ctx->action_exit_attached)
+ unregister_trace_softirq_exit(irqstate_empty_worker_action_exit,
+ empty_ctx);
+ if (empty_ctx->action_entry_attached)
+ unregister_trace_softirq_entry(irqstate_empty_worker_action_entry,
+ empty_ctx);
+ if (empty_ctx->exit_attached)
+ unregister_trace_softirq_context_exit_tp(irqstate_empty_worker_exit,
+ empty_ctx);
+ if (empty_ctx->entry_attached)
+ unregister_trace_softirq_context_entry_tp(
+ irqstate_empty_worker_entry, empty_ctx);
+ tracepoint_synchronize_unregister();
+}
+
+static void run_irqstate_rt_empty_worker(struct kunit *test, bool real_worker)
+{
+ struct irqstate_empty_worker_ctx *empty_ctx;
+ struct rv_kunit_ctx *ctx = test->priv;
+ unsigned int saved_count, saved_softirq;
+ bool order_ok, restored;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
+ kunit_skip(test, "Requires RT worker serving boundaries");
+ return;
+ }
+
+ prepare_test(test, &rv_irqstate_ops.mon);
+ empty_ctx = kunit_kzalloc(test, sizeof(*empty_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, empty_ctx);
+ empty_ctx->real_worker = real_worker;
+
+ ret = register_trace_softirq_context_entry_tp(
+ irqstate_empty_worker_entry, empty_ctx);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ empty_ctx->entry_attached = true;
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test,
+ irqstate_empty_worker_detach,
+ empty_ctx));
+ ret = register_trace_softirq_context_exit_tp(irqstate_empty_worker_exit,
+ empty_ctx);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ empty_ctx->exit_attached = true;
+ ret = register_trace_softirq_entry(irqstate_empty_worker_action_entry,
+ empty_ctx);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ empty_ctx->action_entry_attached = true;
+ ret = register_trace_softirq_exit(irqstate_empty_worker_action_exit,
+ empty_ctx);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ empty_ctx->action_exit_attached = true;
+ attach_irqstate_test_probes();
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test, detach_irqstate_test_probes,
+ NULL));
+
+ KUNIT_ASSERT_TRUE(test, preemptible());
+ KUNIT_ASSERT_FALSE(test, irqs_disabled());
+ KUNIT_ASSERT_EQ(test, softirq_count(), 0U);
+ saved_count = preempt_count();
+ saved_softirq = softirq_count();
+ if (real_worker) {
+ cpus_read_lock();
+ ret = softirq_kunit_run_empty_ksoftirqd(&empty_ctx->owner,
+ &empty_ctx->owner_cpu,
+ &empty_ctx->armed);
+ cpus_read_unlock();
+ } else {
+ migrate_disable();
+ WRITE_ONCE(empty_ctx->owner_cpu, smp_processor_id());
+ WRITE_ONCE(empty_ctx->owner, current);
+ /* Publish the owner before globally registered callbacks match it. */
+ smp_store_release(&empty_ctx->armed, true);
+ softirq_kunit_run_empty_worker();
+ WRITE_ONCE(empty_ctx->armed, false);
+ migrate_enable();
+ ret = 0;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ KUNIT_ASSERT_NOT_NULL(test, empty_ctx->owner);
+
+ order_ok = empty_ctx->event_index == 2 && !empty_ctx->inside_pair &&
+ !empty_ctx->bad_order;
+ restored = preempt_count() == saved_count &&
+ softirq_count() == saved_softirq && !irqs_disabled();
+ KUNIT_EXPECT_EQ(test, empty_ctx->entries, 1U);
+ KUNIT_EXPECT_EQ(test, empty_ctx->exits, 1U);
+ KUNIT_EXPECT_EQ(test, empty_ctx->action_entries, 0U);
+ KUNIT_EXPECT_EQ(test, empty_ctx->action_exits, 0U);
+ KUNIT_EXPECT_TRUE(test, order_ok);
+ KUNIT_EXPECT_FALSE(test, empty_ctx->bad_boundary_context);
+ KUNIT_EXPECT_FALSE(test, empty_ctx->bad_boundary_cpu);
+ KUNIT_EXPECT_FALSE(test, empty_ctx->actions_at_exit);
+ KUNIT_EXPECT_EQ(test, preempt_count(), saved_count);
+ KUNIT_EXPECT_EQ(test, softirq_count(), saved_softirq);
+ KUNIT_EXPECT_FALSE(test, irqs_disabled());
+ RV_KUNIT_EXPECT_NO_REACTION(test, ctx);
+ if (real_worker)
+ kunit_info(test,
+ "RT smpboot empty worker events=%u/%u actions=%u/%u order=%u serving=%u same_cpu=%u restored=%u\n",
+ empty_ctx->entries, empty_ctx->exits,
+ empty_ctx->action_entries, empty_ctx->action_exits,
+ order_ok, !empty_ctx->bad_boundary_context,
+ !empty_ctx->bad_boundary_cpu, restored);
+ else
+ kunit_info(test,
+ "RT empty worker events=%u/%u actions=%u/%u order=%u serving=%u same_cpu=%u restored=%u\n",
+ empty_ctx->entries, empty_ctx->exits,
+ empty_ctx->action_entries, empty_ctx->action_exits,
+ order_ok, !empty_ctx->bad_boundary_context,
+ !empty_ctx->bad_boundary_cpu, restored);
+}
+
+/* Exercise an RT worker interval which executes no softirq action. */
+static void rv_test_irqstate_rt_empty_worker(struct kunit *test)
+{
+ run_irqstate_rt_empty_worker(test, false);
+}
+
+/* Exercise the real ksoftirqd task and its smpboot predicate. */
+static void rv_test_irqstate_rt_smpboot_empty_worker(struct kunit *test)
+{
+ run_irqstate_rt_empty_worker(test, true);
+}
+
static int irqstate_preempt_worker(void *arg)
{
struct irqstate_preempt_ctx *preempt_ctx = arg;@@ -1389,6 +1616,16 @@ static void rv_test_irqstate_rt_inline_bh(struct kunit *test)
kunit_skip(test, "Requires built-in RV tests");
}
+static void rv_test_irqstate_rt_empty_worker(struct kunit *test)
+{
+ kunit_skip(test, "Requires built-in RV tests");
+}
+
+static void rv_test_irqstate_rt_smpboot_empty_worker(struct kunit *test)
+{
+ kunit_skip(test, "Requires built-in RV tests");
+}
+
static void rv_test_irqstate_preempt(struct kunit *test)
{
kunit_skip(test, "Requires built-in RV tests");@@ -1414,6 +1651,8 @@ static void rv_test_irqstate_rt_prepare_switch(struct kunit *test)
#define rv_test_irqstate_live_toggle rv_test_stub
#define rv_test_irqstate_irq_exit_inline rv_test_stub
#define rv_test_irqstate_rt_inline_bh rv_test_stub
+#define rv_test_irqstate_rt_empty_worker rv_test_stub
+#define rv_test_irqstate_rt_smpboot_empty_worker rv_test_stub
#define rv_test_irqstate_preempt rv_test_stub
#define rv_test_irqstate_rt_prepare_irq rv_test_stub
#define rv_test_irqstate_rt_prepare_switch rv_test_stub
diff --git a/kernel/trace/rv/rv_monitors_test.c b/kernel/trace/rv/rv_monitors_test.c
index 9eb37cbd2de22..be3aaae2613a8 100644
--- a/kernel/trace/rv/rv_monitors_test.c
+++ b/kernel/trace/rv/rv_monitors_test.c
@@ -169,6 +169,8 @@ static struct kunit_case rv_mon_test_cases[] = {
KUNIT_CASE(rv_test_irqstate_live_toggle),
KUNIT_CASE(rv_test_irqstate_irq_exit_inline),
KUNIT_CASE(rv_test_irqstate_rt_inline_bh),
+ KUNIT_CASE(rv_test_irqstate_rt_empty_worker),
+ KUNIT_CASE(rv_test_irqstate_rt_smpboot_empty_worker),
KUNIT_CASE(rv_test_irqstate_preempt),
KUNIT_CASE(rv_test_irqstate_rt_prepare_irq),
KUNIT_CASE(rv_test_irqstate_rt_prepare_switch),--
2.39.5 (Apple Git-154)