FILE
irq_test.c
File preview with syntax highlighting.
linux-6.19.14/kernel/irq/irq_test.c
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 15static irqreturn_t noop_handler(int irq, void *data) 16{ 17 return IRQ_HANDLED; 18} 19 20static void noop(struct irq_data *data) { } 21static unsigned int noop_ret(struct irq_data *data) { return 0; } 22 23static 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 31static 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 44static int irq_test_setup_fake_irq(struct kunit *test, struct irq_affinity_desc *affd) 45{ 46 struct irq_desc *desc; 47 int virq; 48 49 virq = irq_domain_alloc_descs(-1, 1, 0, NUMA_NO_NODE, affd); 50 KUNIT_ASSERT_GE(test, virq, 0); 51 52 irq_set_chip_and_handler(virq, &fake_irq_chip, handle_simple_irq); 53 54 desc = irq_to_desc(virq); 55 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 56 57 /* On some architectures, IRQs are NOREQUEST | NOPROBE by default. */ 58 irq_settings_clr_norequest(desc); 59 60 return virq; 61} 62 63static void irq_disable_depth_test(struct kunit *test) 64{ 65 struct irq_desc *desc; 66 int virq, ret; 67 68 virq = irq_test_setup_fake_irq(test, NULL); 69 70 desc = irq_to_desc(virq); 71 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 72 73 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 74 KUNIT_ASSERT_EQ(test, ret, 0); 75 76 KUNIT_EXPECT_EQ(test, desc->depth, 0); 77 78 disable_irq(virq); 79 KUNIT_EXPECT_EQ(test, desc->depth, 1); 80 81 enable_irq(virq); 82 KUNIT_EXPECT_EQ(test, desc->depth, 0); 83 84 free_irq(virq, NULL); 85} 86 87static void irq_free_disabled_test(struct kunit *test) 88{ 89 struct irq_desc *desc; 90 int virq, ret; 91 92 virq = irq_test_setup_fake_irq(test, NULL); 93 94 desc = irq_to_desc(virq); 95 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 96 97 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 98 KUNIT_ASSERT_EQ(test, ret, 0); 99 100 KUNIT_EXPECT_EQ(test, desc->depth, 0); 101 102 disable_irq(virq); 103 KUNIT_EXPECT_EQ(test, desc->depth, 1); 104 105 free_irq(virq, NULL); 106 KUNIT_EXPECT_GE(test, desc->depth, 1); 107 108 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 109 KUNIT_ASSERT_EQ(test, ret, 0); 110 KUNIT_EXPECT_EQ(test, desc->depth, 0); 111 112 free_irq(virq, NULL); 113} 114 115static void irq_shutdown_depth_test(struct kunit *test) 116{ 117 struct irq_desc *desc; 118 struct irq_data *data; 119 int virq, ret; 120 struct irq_affinity_desc affinity = { 121 .is_managed = 1, 122 .mask = CPU_MASK_ALL, 123 }; 124 125 if (!IS_ENABLED(CONFIG_SMP)) 126 kunit_skip(test, "requires CONFIG_SMP for managed shutdown"); 127 128 virq = irq_test_setup_fake_irq(test, &affinity); 129 130 desc = irq_to_desc(virq); 131 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 132 133 data = irq_desc_get_irq_data(desc); 134 KUNIT_ASSERT_PTR_NE(test, data, NULL); 135 136 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 137 KUNIT_ASSERT_EQ(test, ret, 0); 138 139 KUNIT_EXPECT_TRUE(test, irqd_is_activated(data)); 140 KUNIT_EXPECT_TRUE(test, irqd_is_started(data)); 141 KUNIT_EXPECT_TRUE(test, irqd_affinity_is_managed(data)); 142 143 KUNIT_EXPECT_EQ(test, desc->depth, 0); 144 145 disable_irq(virq); 146 KUNIT_EXPECT_EQ(test, desc->depth, 1); 147 148 scoped_guard(raw_spinlock_irqsave, &desc->lock) 149 irq_shutdown_and_deactivate(desc); 150 151 KUNIT_EXPECT_FALSE(test, irqd_is_activated(data)); 152 KUNIT_EXPECT_FALSE(test, irqd_is_started(data)); 153 154 KUNIT_EXPECT_EQ(test, irq_activate(desc), 0); 155#ifdef CONFIG_SMP 156 irq_startup_managed(desc); 157#endif 158 159 KUNIT_EXPECT_EQ(test, desc->depth, 1); 160 161 enable_irq(virq); 162 KUNIT_EXPECT_EQ(test, desc->depth, 0); 163 164 free_irq(virq, NULL); 165} 166 167static void irq_cpuhotplug_test(struct kunit *test) 168{ 169 struct irq_desc *desc; 170 struct irq_data *data; 171 int virq, ret; 172 struct irq_affinity_desc affinity = { 173 .is_managed = 1, 174 }; 175 176 if (!IS_ENABLED(CONFIG_SMP)) 177 kunit_skip(test, "requires CONFIG_SMP for CPU hotplug"); 178 if (!get_cpu_device(1)) 179 kunit_skip(test, "requires more than 1 CPU for CPU hotplug"); 180 if (!cpu_is_hotpluggable(1)) 181 kunit_skip(test, "CPU 1 must be hotpluggable"); 182 if (!cpu_online(1)) 183 kunit_skip(test, "CPU 1 must be online"); 184 185 cpumask_copy(&affinity.mask, cpumask_of(1)); 186 187 virq = irq_test_setup_fake_irq(test, &affinity); 188 189 desc = irq_to_desc(virq); 190 KUNIT_ASSERT_PTR_NE(test, desc, NULL); 191 192 data = irq_desc_get_irq_data(desc); 193 KUNIT_ASSERT_PTR_NE(test, data, NULL); 194 195 ret = request_irq(virq, noop_handler, 0, "test_irq", NULL); 196 KUNIT_ASSERT_EQ(test, ret, 0); 197 198 KUNIT_EXPECT_TRUE(test, irqd_is_activated(data)); 199 KUNIT_EXPECT_TRUE(test, irqd_is_started(data)); 200 KUNIT_EXPECT_TRUE(test, irqd_affinity_is_managed(data)); 201 202 KUNIT_EXPECT_EQ(test, desc->depth, 0); 203 204 disable_irq(virq); 205 KUNIT_EXPECT_EQ(test, desc->depth, 1); 206 207 KUNIT_EXPECT_EQ(test, remove_cpu(1), 0); 208 KUNIT_EXPECT_GE(test, desc->depth, 1); 209 KUNIT_EXPECT_EQ(test, add_cpu(1), 0); 210 211 KUNIT_EXPECT_EQ(test, desc->depth, 1); 212 213 enable_irq(virq); 214 KUNIT_EXPECT_TRUE(test, irqd_is_activated(data)); 215 KUNIT_EXPECT_TRUE(test, irqd_is_started(data)); 216 KUNIT_EXPECT_EQ(test, desc->depth, 0); 217 218 free_irq(virq, NULL); 219} 220 221static struct kunit_case irq_test_cases[] = { 222 KUNIT_CASE(irq_disable_depth_test), 223 KUNIT_CASE(irq_free_disabled_test), 224 KUNIT_CASE(irq_shutdown_depth_test), 225 KUNIT_CASE(irq_cpuhotplug_test), 226 {} 227}; 228 229static struct kunit_suite irq_test_suite = { 230 .name = "irq_test_cases", 231 .test_cases = irq_test_cases, 232}; 233 234kunit_test_suite(irq_test_suite); 235MODULE_DESCRIPTION("IRQ unit test suite"); 236MODULE_LICENSE("GPL");
~/
Read-only file preview.