|
1 | 1 | /*
|
| 2 | + * Copyright (c) 2020 Stephanos Ioannidis <[email protected]> |
2 | 3 | * Copyright (c) 2018 Intel Corporation
|
3 | 4 | *
|
4 | 5 | * SPDX-License-Identifier: Apache-2.0
|
|
7 | 8 | #include <ztest.h>
|
8 | 9 | #include "interrupt_util.h"
|
9 | 10 |
|
10 |
| -#define DURATION 5 |
11 |
| -struct k_timer timer; |
| 11 | +#define DURATION 5 |
12 | 12 |
|
13 |
| -/* This tests uses two IRQ lines, selected within the range of IRQ lines |
14 |
| - * available on the target SOC the test executes on (and starting from |
15 |
| - * the maximum available IRQ line index) |
16 |
| - */ |
17 |
| -#define IRQ_LINE(offset) (CONFIG_NUM_IRQS - ((offset) + 1)) |
18 |
| - |
19 |
| -#define ISR0_OFFSET 1 |
20 |
| -#define ISR1_OFFSET 2 |
| 13 | +#define ISR0_TOKEN 0xDEADBEEF |
| 14 | +#define ISR1_TOKEN 0xCAFEBABE |
21 | 15 |
|
22 |
| -/* Keeping isr0 to be lowest priority than system timer |
23 |
| - * so that it can be interrupted by timer triggered. |
24 |
| - * In NRF5, RTC system timer is of priority 1 and |
25 |
| - * in all other architectures, system timer is considered |
26 |
| - * to be in priority 0. |
| 16 | +/* |
| 17 | + * This test uses two IRQ lines selected within the range of available IRQs on |
| 18 | + * the target SoC. These IRQs are platform and interrupt controller-specific, |
| 19 | + * and must be specified for every supported platform. |
| 20 | + * |
| 21 | + * In terms of priority, the IRQ1 is triggered from the ISR of the IRQ0; |
| 22 | + * therefore, the priority of IRQ1 must be greater than that of the IRQ0. |
27 | 23 | */
|
28 | 24 | #if defined(CONFIG_CPU_CORTEX_M)
|
29 |
| -u32_t irq_line_0; |
30 |
| -u32_t irq_line_1; |
31 |
| -#define ISR0_PRIO 2 |
32 |
| -#define ISR1_PRIO 1 |
| 25 | +/* |
| 26 | + * For Cortex-M NVIC, unused and available IRQs are automatically detected when |
| 27 | + * when the test is run. |
| 28 | + */ |
| 29 | +#define IRQ0_PRIO 2 |
| 30 | +#define IRQ1_PRIO 1 |
33 | 31 | #else
|
34 |
| -#define ISR0_PRIO 1 |
35 |
| -#define ISR1_PRIO 0 |
36 |
| -#endif /* CONFIG_CPU_CORTEX_M */ |
| 32 | +/* |
| 33 | + * For all the other platforms, use the last two available IRQ lines for |
| 34 | + * testing. |
| 35 | + */ |
| 36 | +#define IRQ0_LINE (CONFIG_NUM_IRQS - 1) |
| 37 | +#define IRQ1_LINE (CONFIG_NUM_IRQS - 2) |
| 38 | + |
| 39 | +#define IRQ0_PRIO 1 |
| 40 | +#define IRQ1_PRIO 0 |
| 41 | +#endif |
| 42 | + |
| 43 | +#ifndef NO_TRIGGER_FROM_SW |
| 44 | +static u32_t irq_line_0; |
| 45 | +static u32_t irq_line_1; |
37 | 46 |
|
38 |
| -volatile u32_t new_val; |
39 |
| -u32_t old_val = 0xDEAD; |
| 47 | +static u32_t isr0_result; |
| 48 | +static u32_t isr1_result; |
40 | 49 |
|
41 | 50 | void isr1(void *param)
|
42 | 51 | {
|
43 | 52 | ARG_UNUSED(param);
|
44 |
| - new_val = 0xDEAD; |
45 |
| - printk("%s ran !!\n", __func__); |
46 |
| -} |
47 | 53 |
|
48 |
| -/** |
49 |
| - * |
50 |
| - * triggering interrupt from the timer expiry function while isr0 |
51 |
| - * is in busy wait |
52 |
| - */ |
53 |
| -#ifndef NO_TRIGGER_FROM_SW |
54 |
| -static void handler(struct k_timer *timer) |
55 |
| -{ |
56 |
| - ARG_UNUSED(timer); |
57 |
| -#if defined(CONFIG_CPU_CORTEX_M) |
58 |
| - irq_enable(irq_line_1); |
59 |
| - trigger_irq(irq_line_1); |
60 |
| -#else |
61 |
| - irq_enable(IRQ_LINE(ISR1_OFFSET)); |
62 |
| - trigger_irq(IRQ_LINE(ISR1_OFFSET)); |
63 |
| -#endif /* CONFIG_CPU_CORTEX_M */ |
64 |
| -} |
65 |
| -#else |
66 |
| -void handler(void) |
67 |
| -{ |
68 |
| - ztest_test_skip(); |
| 54 | + printk("isr1: Enter\n"); |
| 55 | + |
| 56 | + /* Set verification token */ |
| 57 | + isr1_result = ISR1_TOKEN; |
| 58 | + |
| 59 | + printk("isr1: Leave\n"); |
69 | 60 | }
|
70 |
| -#endif /* NO_TRIGGER_FROM_SW */ |
71 | 61 |
|
72 | 62 | void isr0(void *param)
|
73 | 63 | {
|
74 | 64 | ARG_UNUSED(param);
|
75 |
| - printk("%s running !!\n", __func__); |
76 |
| -#if defined(CONFIG_BOARD_QEMU_CORTEX_M0) |
77 |
| - /* QEMU Cortex-M0 timer emulation appears to not capturing the |
78 |
| - * current time accurately, resulting in erroneous busy wait |
79 |
| - * implementation. |
80 |
| - * |
81 |
| - * Work-around: |
82 |
| - * Increase busy-loop duration to ensure the timer interrupt will fire |
83 |
| - * during the busy loop waiting. |
84 |
| - */ |
85 |
| - k_busy_wait(MS_TO_US(1000)); |
86 |
| -#else |
87 |
| - k_busy_wait(MS_TO_US(10)); |
88 |
| -#endif |
89 |
| - printk("%s execution completed !!\n", __func__); |
90 |
| - zassert_equal(new_val, old_val, "Nested interrupt is not working\n"); |
| 65 | + |
| 66 | + printk("isr0: Enter\n"); |
| 67 | + |
| 68 | + /* Set verification token */ |
| 69 | + isr0_result = ISR0_TOKEN; |
| 70 | + |
| 71 | + /* Trigger nested IRQ 1 */ |
| 72 | + trigger_irq(irq_line_1); |
| 73 | + |
| 74 | + /* Wait for interrupt */ |
| 75 | + k_busy_wait(MS_TO_US(DURATION)); |
| 76 | + |
| 77 | + /* Validate nested ISR result token */ |
| 78 | + zassert_equal(isr1_result, ISR1_TOKEN, "isr1 did not execute"); |
| 79 | + |
| 80 | + printk("isr0: Leave\n"); |
91 | 81 | }
|
92 | 82 |
|
93 | 83 | /**
|
| 84 | + * @brief Test interrupt nesting |
| 85 | + * |
| 86 | + * @ingroup kernel_interrupt_tests |
94 | 87 | *
|
95 |
| - * Interrupt nesting feature allows an ISR to be preempted in mid-execution |
96 |
| - * if a higher priority interrupt is signaled. The lower priority ISR resumes |
97 |
| - * execution once the higher priority ISR has completed its processing. |
98 |
| - * The expected control flow should be isr0 -> handler -> isr1 -> isr0 |
| 88 | + * This routine tests the interrupt nesting feature, which allows an ISR to be |
| 89 | + * preempted in mid-execution if a higher priority interrupt is signaled. The |
| 90 | + * lower priority ISR resumes execution once the higher priority ISR has |
| 91 | + * completed its processing. |
| 92 | + * |
| 93 | + * The expected control flow for this test is as follows: |
| 94 | + * |
| 95 | + * 1. [thread] Trigger IRQ 0 (lower priority) |
| 96 | + * 2. [isr0] Set ISR 0 result token and trigger IRQ 1 (higher priority) |
| 97 | + * 3. [isr1] Set ISR 1 result token and return |
| 98 | + * 4. [isr0] Validate ISR 1 result token and return |
| 99 | + * 5. [thread] Validate ISR 0 result token |
99 | 100 | */
|
100 |
| -#ifndef NO_TRIGGER_FROM_SW |
101 | 101 | void test_nested_isr(void)
|
102 | 102 | {
|
| 103 | + /* Resolve test IRQ line numbers */ |
103 | 104 | #if defined(CONFIG_CPU_CORTEX_M)
|
104 | 105 | irq_line_0 = get_available_nvic_line(CONFIG_NUM_IRQS);
|
105 | 106 | irq_line_1 = get_available_nvic_line(irq_line_0);
|
106 |
| - arch_irq_connect_dynamic(irq_line_0, ISR0_PRIO, isr0, NULL, 0); |
107 |
| - arch_irq_connect_dynamic(irq_line_1, ISR1_PRIO, isr1, NULL, 0); |
108 | 107 | #else
|
109 |
| - IRQ_CONNECT(IRQ_LINE(ISR0_OFFSET), ISR0_PRIO, isr0, NULL, 0); |
110 |
| - IRQ_CONNECT(IRQ_LINE(ISR1_OFFSET), ISR1_PRIO, isr1, NULL, 0); |
111 |
| -#endif /* CONFIG_CPU_CORTEX_M */ |
| 108 | + irq_line_0 = IRQ0_LINE; |
| 109 | + irq_line_1 = IRQ1_LINE; |
| 110 | +#endif |
112 | 111 |
|
113 |
| - k_timer_init(&timer, handler, NULL); |
114 |
| - k_timer_start(&timer, DURATION, K_NO_WAIT); |
| 112 | + /* Connect and enable test IRQs */ |
| 113 | + arch_irq_connect_dynamic(irq_line_0, IRQ0_PRIO, isr0, NULL, 0); |
| 114 | + arch_irq_connect_dynamic(irq_line_1, IRQ1_PRIO, isr1, NULL, 0); |
115 | 115 |
|
116 |
| -#if defined(CONFIG_CPU_CORTEX_M) |
117 | 116 | irq_enable(irq_line_0);
|
| 117 | + irq_enable(irq_line_1); |
| 118 | + |
| 119 | + /* Trigger test IRQ 0 */ |
118 | 120 | trigger_irq(irq_line_0);
|
119 |
| -#else |
120 |
| - irq_enable(IRQ_LINE(ISR0_OFFSET)); |
121 |
| - trigger_irq(IRQ_LINE(ISR0_OFFSET)); |
122 |
| -#endif /* CONFIG_CPU_CORTEX_M */ |
123 | 121 |
|
| 122 | + /* Wait for interrupt */ |
| 123 | + k_busy_wait(MS_TO_US(DURATION)); |
| 124 | + |
| 125 | + /* Validate ISR result token */ |
| 126 | + zassert_equal(isr0_result, ISR0_TOKEN, "isr0 did not execute"); |
124 | 127 | }
|
125 | 128 | #else
|
126 | 129 | void test_nested_isr(void)
|
|
0 commit comments