xref: /linux/kernel/irq/refcount_interrupt_test.c (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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 ===== */
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 
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 
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 
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 
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. */
109 static int test_init(struct kunit *test)
110 {
111 	TEST_IRQ_ON();
112 
113 	return 0;
114 }
115 
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