1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * KUnit test for refcounted interrupt enable/disables.
4 */
5
6 #include <kunit/test.h>
7 #include <linux/interrupt_rc.h>
8
9 #define TEST_IRQ_ON() KUNIT_EXPECT_FALSE(test, irqs_disabled())
10 #define TEST_IRQ_OFF() KUNIT_EXPECT_TRUE(test, irqs_disabled())
11
12 /* ===== Test cases ===== */
test_single_irq_change(struct kunit * test)13 static void test_single_irq_change(struct kunit *test)
14 {
15 local_interrupt_disable();
16 TEST_IRQ_OFF();
17 local_interrupt_enable();
18 }
19
test_nested_irq_change(struct kunit * test)20 static void test_nested_irq_change(struct kunit *test)
21 {
22 local_interrupt_disable();
23 TEST_IRQ_OFF();
24 local_interrupt_disable();
25 TEST_IRQ_OFF();
26 local_interrupt_disable();
27 TEST_IRQ_OFF();
28
29 local_interrupt_enable();
30 TEST_IRQ_OFF();
31 local_interrupt_enable();
32 TEST_IRQ_OFF();
33 local_interrupt_enable();
34 TEST_IRQ_ON();
35 }
36
test_multiple_irq_change(struct kunit * test)37 static void test_multiple_irq_change(struct kunit *test)
38 {
39 local_interrupt_disable();
40 TEST_IRQ_OFF();
41 local_interrupt_disable();
42 TEST_IRQ_OFF();
43
44 local_interrupt_enable();
45 TEST_IRQ_OFF();
46 local_interrupt_enable();
47 TEST_IRQ_ON();
48
49 local_interrupt_disable();
50 TEST_IRQ_OFF();
51 local_interrupt_enable();
52 TEST_IRQ_ON();
53 }
54
test_max_nesting_irq_change(struct kunit * test)55 static void test_max_nesting_irq_change(struct kunit *test)
56 {
57 for (int i = 0; i < __IRQ_MASK(HARDIRQ_DISABLE_BITS); i++) {
58 local_interrupt_disable();
59 TEST_IRQ_OFF();
60 }
61
62
63 for (int i = 0; i < __IRQ_MASK(HARDIRQ_DISABLE_BITS); i++) {
64 TEST_IRQ_OFF();
65 local_interrupt_enable();
66 }
67
68 TEST_IRQ_ON();
69
70 local_interrupt_disable();
71 TEST_IRQ_OFF();
72 local_interrupt_enable();
73 TEST_IRQ_ON();
74 }
75
test_irq_save(struct kunit * test)76 static void test_irq_save(struct kunit *test)
77 {
78 unsigned long flags;
79
80 local_irq_save(flags);
81 TEST_IRQ_OFF();
82 local_interrupt_disable();
83 TEST_IRQ_OFF();
84 local_interrupt_enable();
85 TEST_IRQ_OFF();
86 local_irq_restore(flags);
87 TEST_IRQ_ON();
88
89 local_interrupt_disable();
90 TEST_IRQ_OFF();
91 local_irq_save(flags);
92 TEST_IRQ_OFF();
93 local_irq_restore(flags);
94 TEST_IRQ_OFF();
95 local_interrupt_enable();
96 TEST_IRQ_ON();
97 }
98
99 static struct kunit_case test_cases[] = {
100 KUNIT_CASE(test_single_irq_change),
101 KUNIT_CASE(test_nested_irq_change),
102 KUNIT_CASE(test_multiple_irq_change),
103 KUNIT_CASE(test_max_nesting_irq_change),
104 KUNIT_CASE(test_irq_save),
105 {},
106 };
107
108 /* init and exit are the same. */
test_init(struct kunit * test)109 static int test_init(struct kunit *test)
110 {
111 TEST_IRQ_ON();
112
113 return 0;
114 }
115
test_exit(struct kunit * test)116 static void test_exit(struct kunit *test)
117 {
118 TEST_IRQ_ON();
119 }
120
121 static struct kunit_suite refcount_interrupt_test_suite = {
122 .name = "refcount_interrupt",
123 .test_cases = test_cases,
124 .init = test_init,
125 .exit = test_exit,
126 };
127
128 kunit_test_suite(refcount_interrupt_test_suite);
129 MODULE_AUTHOR("Lyude Paul <lyude@redhat.com>");
130 MODULE_DESCRIPTION("Refcounted interrupt unit test suite");
131 MODULE_LICENSE("GPL");
132