1 // SPDX-License-Identifier: LGPL-2.1+ 2 3 #include <linux/cleanup.h> 4 #include <linux/cpu.h> 5 #include <linux/cpumask.h> 6 #include <linux/interrupt.h> 7 #include <linux/irq.h> 8 #include <linux/irqdesc.h> 9 #include <linux/irqdomain.h> 10 #include <linux/nodemask.h> 11 #include <kunit/test.h> 12 13 #include "internals.h" 14 15 static irqreturn_t noop_handler(int irq, void *data) 16 { 17 return IRQ_HANDLED; 18 } 19 20 static void noop(struct irq_data *data) { } 21 static unsigned int noop_ret(struct irq_data *data) { return 0; } 22 23 static int noop_affinity(struct irq_data *data, const struct cpumask *dest, 24 bool force) 25 { 26 irq_data_update_effective_affinity(data, dest); 27 28 return 0; 29 } 30 31 static struct irq_chip fake_irq_chip = { 32 .name = "fake", 33 .irq_startup = noop_ret, 34 .irq_shutdown = noop, 35 .irq_enable = noop, 36 .irq_disable = noop, 37 .irq_ack = noop, 38 .irq_mask = noop, 39 .irq_unmask = noop, 40 .irq_set_affinity = noop_affinity, 41 .flags = IRQCHIP_SKIP_SET_WAKE, 42 }; 43 44 static void irq_disable_depth_test(struct kunit *test) 45 { 46 struct irq_desc *desc; 47 int virq, ret; 48 49 virq = irq_domain_alloc_descs(-1, 1, 0, NUMA_NO_NODE, NULL); 50 KUNIT_ASSERT_GE(test, virq, 0); 51 52 irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); 53 54 desc = irq_to_desc(virq); 55 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 56 57 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 58 KUNIT_EXPECT_EQ(test, ret, 0); 59 60 KUNIT_EXPECT_EQ(test, desc->depth, 0); 61 62 disable_irq(virq); 63 KUNIT_EXPECT_EQ(test, desc->depth, 1); 64 65 enable_irq(virq); 66 KUNIT_EXPECT_EQ(test, desc->depth, 0); 67 68 free_irq(virq, NULL); 69 } 70 71 static void irq_free_disabled_test(struct kunit *test) 72 { 73 struct irq_desc *desc; 74 int virq, ret; 75 76 virq = irq_domain_alloc_descs(-1, 1, 0, NUMA_NO_NODE, NULL); 77 KUNIT_ASSERT_GE(test, virq, 0); 78 79 irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); 80 81 desc = irq_to_desc(virq); 82 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 83 84 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 85 KUNIT_EXPECT_EQ(test, ret, 0); 86 87 KUNIT_EXPECT_EQ(test, desc->depth, 0); 88 89 disable_irq(virq); 90 KUNIT_EXPECT_EQ(test, desc->depth, 1); 91 92 free_irq(virq, NULL); 93 KUNIT_EXPECT_GE(test, desc->depth, 1); 94 95 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 96 KUNIT_EXPECT_EQ(test, ret, 0); 97 KUNIT_EXPECT_EQ(test, desc->depth, 0); 98 99 free_irq(virq, NULL); 100 } 101 102 static void irq_shutdown_depth_test(struct kunit *test) 103 { 104 struct irq_desc *desc; 105 struct irq_data *data; 106 int virq, ret; 107 struct irq_affinity_desc affinity = { 108 .is_managed = 1, 109 .mask = CPU_MASK_ALL, 110 }; 111 112 if (!IS_ENABLED(CONFIG_SMP)) 113 kunit_skip(test, "requires CONFIG_SMP for managed shutdown"); 114 115 virq = irq_domain_alloc_descs(-1, 1, 0, NUMA_NO_NODE, &affinity); 116 KUNIT_ASSERT_GE(test, virq, 0); 117 118 irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); 119 120 desc = irq_to_desc(virq); 121 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 122 123 data = irq_desc_get_irq_data(desc); 124 KUNIT_ASSERT_PTR_NE(test, data, NULL); 125 126 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 127 KUNIT_EXPECT_EQ(test, ret, 0); 128 129 KUNIT_EXPECT_TRUE(test, irqd_is_activated(data)); 130 KUNIT_EXPECT_TRUE(test, irqd_is_started(data)); 131 KUNIT_EXPECT_TRUE(test, irqd_affinity_is_managed(data)); 132 133 KUNIT_EXPECT_EQ(test, desc->depth, 0); 134 135 disable_irq(virq); 136 KUNIT_EXPECT_EQ(test, desc->depth, 1); 137 138 scoped_guard(raw_spinlock_irqsave, &desc->lock) 139 irq_shutdown_and_deactivate(desc); 140 141 KUNIT_EXPECT_FALSE(test, irqd_is_activated(data)); 142 KUNIT_EXPECT_FALSE(test, irqd_is_started(data)); 143 144 KUNIT_EXPECT_EQ(test, irq_activate(desc), 0); 145 #ifdef CONFIG_SMP 146 irq_startup_managed(desc); 147 #endif 148 149 KUNIT_EXPECT_EQ(test, desc->depth, 1); 150 151 enable_irq(virq); 152 KUNIT_EXPECT_EQ(test, desc->depth, 0); 153 154 free_irq(virq, NULL); 155 } 156 157 static void irq_cpuhotplug_test(struct kunit *test) 158 { 159 struct irq_desc *desc; 160 struct irq_data *data; 161 int virq, ret; 162 struct irq_affinity_desc affinity = { 163 .is_managed = 1, 164 }; 165 166 if (!IS_ENABLED(CONFIG_SMP)) 167 kunit_skip(test, "requires CONFIG_SMP for CPU hotplug"); 168 if (!get_cpu_device(1)) 169 kunit_skip(test, "requires more than 1 CPU for CPU hotplug"); 170 if (!cpu_is_hotpluggable(1)) 171 kunit_skip(test, "CPU 1 must be hotpluggable"); 172 173 cpumask_copy(&affinity.mask, cpumask_of(1)); 174 175 virq = irq_domain_alloc_descs(-1, 1, 0, NUMA_NO_NODE, &affinity); 176 KUNIT_ASSERT_GE(test, virq, 0); 177 178 irq_set_chip_and_handler(virq, &fake_irq_chip, handle_simple_irq); 179 180 desc = irq_to_desc(virq); 181 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 182 183 data = irq_desc_get_irq_data(desc); 184 KUNIT_ASSERT_PTR_NE(test, data, NULL); 185 186 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 187 KUNIT_EXPECT_EQ(test, ret, 0); 188 189 KUNIT_EXPECT_TRUE(test, irqd_is_activated(data)); 190 KUNIT_EXPECT_TRUE(test, irqd_is_started(data)); 191 KUNIT_EXPECT_TRUE(test, irqd_affinity_is_managed(data)); 192 193 KUNIT_EXPECT_EQ(test, desc->depth, 0); 194 195 disable_irq(virq); 196 KUNIT_EXPECT_EQ(test, desc->depth, 1); 197 198 KUNIT_EXPECT_EQ(test, remove_cpu(1), 0); 199 KUNIT_EXPECT_FALSE(test, irqd_is_activated(data)); 200 KUNIT_EXPECT_FALSE(test, irqd_is_started(data)); 201 KUNIT_EXPECT_GE(test, desc->depth, 1); 202 KUNIT_EXPECT_EQ(test, add_cpu(1), 0); 203 204 KUNIT_EXPECT_FALSE(test, irqd_is_activated(data)); 205 KUNIT_EXPECT_FALSE(test, irqd_is_started(data)); 206 KUNIT_EXPECT_EQ(test, desc->depth, 1); 207 208 enable_irq(virq); 209 KUNIT_EXPECT_TRUE(test, irqd_is_activated(data)); 210 KUNIT_EXPECT_TRUE(test, irqd_is_started(data)); 211 KUNIT_EXPECT_EQ(test, desc->depth, 0); 212 213 free_irq(virq, NULL); 214 } 215 216 static struct kunit_case irq_test_cases[] = { 217 KUNIT_CASE(irq_disable_depth_test), 218 KUNIT_CASE(irq_free_disabled_test), 219 KUNIT_CASE(irq_shutdown_depth_test), 220 KUNIT_CASE(irq_cpuhotplug_test), 221 {} 222 }; 223 224 static struct kunit_suite irq_test_suite = { 225 .name = "irq_test_cases", 226 .test_cases = irq_test_cases, 227 }; 228 229 kunit_test_suite(irq_test_suite); 230 MODULE_DESCRIPTION("IRQ unit test suite"); 231 MODULE_LICENSE("GPL"); 232