1 /*
2  * Copyright (c) 2019 Nordic Semiconductor ASA.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/arch/cpu.h>
9 #include <cmsis_core.h>
10 #include <zephyr/sys/barrier.h>
11 
12 static volatile int test_flag;
13 
arm_zero_latency_isr_handler(const void * args)14 void arm_zero_latency_isr_handler(const void *args)
15 {
16 	ARG_UNUSED(args);
17 
18 	test_flag = 1;
19 }
20 
ZTEST(arm_irq_advanced_features,test_arm_zero_latency_irqs)21 ZTEST(arm_irq_advanced_features, test_arm_zero_latency_irqs)
22 {
23 
24 	if (!IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) {
25 		TC_PRINT("Skipped (Cortex-M Mainline only)\n");
26 
27 		return;
28 	}
29 
30 	/* Determine an NVIC IRQ line that is not currently in use. */
31 	int i, key;
32 	int init_flag, post_flag;
33 
34 	init_flag = test_flag;
35 
36 	zassert_false(init_flag, "Test flag not initialized to zero\n");
37 
38 	for (i = CONFIG_NUM_IRQS - 1; i >= 0; i--) {
39 		if (NVIC_GetEnableIRQ(i) == 0) {
40 			/*
41 			 * Interrupts configured statically with IRQ_CONNECT(.)
42 			 * are automatically enabled. NVIC_GetEnableIRQ()
43 			 * returning false, here, implies that the IRQ line is
44 			 * either not implemented or it is not enabled, thus,
45 			 * currently not in use by Zephyr.
46 			 */
47 
48 			/* Set the NVIC line to pending. */
49 			NVIC_SetPendingIRQ(i);
50 
51 			if (NVIC_GetPendingIRQ(i)) {
52 				/*
53 				 * If the NVIC line is pending, it is
54 				 * guaranteed that it is implemented; clear the
55 				 * line.
56 				 */
57 				NVIC_ClearPendingIRQ(i);
58 
59 				if (!NVIC_GetPendingIRQ(i)) {
60 					/*
61 					 * If the NVIC line can be successfully
62 					 * un-pended, it is guaranteed that it
63 					 * can be used for software interrupt
64 					 * triggering. Return the NVIC line
65 					 * number.
66 					 */
67 					break;
68 				}
69 			}
70 		}
71 	}
72 
73 	zassert_true(i >= 0,
74 		"No available IRQ line to configure as zero-latency\n");
75 
76 	TC_PRINT("Available IRQ line: %u\n", i);
77 
78 	/* Configure the available IRQ line as zero-latency. */
79 
80 	arch_irq_connect_dynamic(i, 0 /* Unused */,
81 		arm_zero_latency_isr_handler,
82 		NULL,
83 		IRQ_ZERO_LATENCY);
84 
85 	NVIC_ClearPendingIRQ(i);
86 	NVIC_EnableIRQ(i);
87 
88 	/* Lock interrupts */
89 	key = irq_lock();
90 
91 	/* Set the zero-latency IRQ to pending state. */
92 	NVIC_SetPendingIRQ(i);
93 
94 	/*
95 	 * Instruction barriers to make sure the NVIC IRQ is
96 	 * set to pending state before 'test_flag' is checked.
97 	 */
98 	barrier_dsync_fence_full();
99 	barrier_isync_fence_full();
100 
101 	/* Confirm test flag is set by the zero-latency ISR handler. */
102 	post_flag = test_flag;
103 	zassert_true(post_flag == 1, "Test flag not set by ISR\n");
104 
105 	irq_unlock(key);
106 }
107 
108 /**
109  * @}
110  */
111