1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/interrupt_util.h>
9
10 #define ISR_DYN_ARG 0xab249cfd
11
12 static unsigned int handler_has_run;
13 static uintptr_t handler_test_result;
14
dyn_isr(const void * arg)15 static void dyn_isr(const void *arg)
16 {
17 ARG_UNUSED(arg);
18 handler_test_result = (uintptr_t)arg;
19 handler_has_run++;
20 }
21
22 #if defined(CONFIG_GEN_SW_ISR_TABLE)
23 extern struct _isr_table_entry _sw_isr_table[];
24
25 #if defined(CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET)
26 #define IRQ_OFFSET CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET
27 #else
28 #define IRQ_OFFSET 0
29 #endif
30
31 /**
32 * @brief Test dynamic ISR installation
33 *
34 * @ingroup kernel_interrupt_tests
35 *
36 * @details This routine locates an unused entry in the software ISR table,
37 * installs a dynamic ISR to the unused entry by calling the dynamic
38 * configured function, and verifies that the ISR is successfully installed
39 * by checking the software ISR table entry.
40 *
41 * @see arch_irq_connect_dynamic()
42 */
ZTEST(interrupt_feature,test_isr_dynamic)43 ZTEST(interrupt_feature, test_isr_dynamic)
44 {
45 int i;
46 const void *argval;
47
48 for (i = 0; i < (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR); i++) {
49 if (_sw_isr_table[i].isr == z_irq_spurious) {
50 break;
51 }
52 }
53
54 zassert_true(_sw_isr_table[i].isr == z_irq_spurious,
55 "could not find slot for dynamic isr");
56
57 printk("installing dynamic ISR for IRQ %d\n",
58 CONFIG_GEN_IRQ_START_VECTOR + i);
59
60 argval = (const void *)&i;
61 arch_irq_connect_dynamic(i + CONFIG_GEN_IRQ_START_VECTOR, 0, dyn_isr,
62 argval, 0);
63
64 zassert_true(_sw_isr_table[i + IRQ_OFFSET].isr == dyn_isr &&
65 _sw_isr_table[i + IRQ_OFFSET].arg == argval,
66 "dynamic isr did not install successfully");
67 }
68 #else
69 /*
70 * For testing arch such as x86, x86_64 and posix which support dynamic
71 * interrupt but without SW ISR table, we test it by applying for a
72 * dynamic interrupt and then trigger it to check if happened correctly.
73 */
74 #if defined(CONFIG_X86)
75 #define IV_IRQS 32 /* start of vectors available for x86 IRQs */
76 #define TEST_IRQ_DYN_LINE 25
77
78 #elif defined(CONFIG_ARCH_POSIX)
79 #define TEST_IRQ_DYN_LINE 5
80 #endif
81
ZTEST(interrupt_feature,test_isr_dynamic)82 ZTEST(interrupt_feature, test_isr_dynamic)
83 {
84 int vector_num;
85
86 /**TESTPOINT: configuration of interrupts dynamically at runtime */
87 vector_num = arch_irq_connect_dynamic(TEST_IRQ_DYN_LINE, 1, dyn_isr,
88 (void *)ISR_DYN_ARG, 0);
89
90 #if defined(CONFIG_X86_64)
91 /* The isr table for x86_64 is visiable, so check it up here */
92 extern void (*x86_irq_funcs[])(const void *);
93 extern const void *x86_irq_args[];
94
95 zassert_true(x86_irq_funcs[vector_num - IV_IRQS] == dyn_isr &&
96 x86_irq_args[vector_num - IV_IRQS] == (void *)ISR_DYN_ARG,
97 "dynamic isr did not install successfully");
98 #endif
99
100 TC_PRINT("vector(%d)\n", vector_num);
101 zassert_true(vector_num > 0,
102 "irq connect dynamic failed");
103
104 zassert_equal(handler_has_run, 0,
105 "handler has run before interrupt trigger");
106
107 irq_enable(TEST_IRQ_DYN_LINE);
108
109 trigger_irq(vector_num);
110
111 zassert_equal(handler_has_run, 1,
112 "interrupt triggered but handler has not run(%d)",
113 handler_has_run);
114
115 /**TESTPOINT: pass word-sized parameter to interrupt */
116 zassert_equal(handler_test_result, ISR_DYN_ARG,
117 "parameter(0x%lx) in handler is not correct",
118 handler_test_result);
119
120 trigger_irq(vector_num);
121
122 /**TESTPOINT: interrupt triggered again */
123 zassert_equal(handler_has_run, 2,
124 "interrupt triggered but handler has not run(%d)",
125 handler_has_run);
126
127 irq_disable(TEST_IRQ_DYN_LINE);
128 }
129 #endif /* CONFIG_GEN_SW_ISR_TABLE */
130