File Index
Files and directories
Sign in
FILE

irq_test.c

File preview with syntax highlighting.

linux-6.19.14/kernel/irq/irq_test.c 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.