9
9
10
10
#include <stdint.h>
11
11
#include <stdbool.h>
12
+ #include <stddef.h>
12
13
#include "nsi_internal.h"
13
14
#include "nsi_cpu_if.h"
14
15
#include "nsi_cpu0_interrupts.h"
15
16
#include "irq_ctrl.h"
16
17
#include "nsi_tasks.h"
18
+ #include "nsi_tracing.h"
17
19
#include "nsi_hws_models_if.h"
18
20
21
+ #define BITS_U64 64
22
+ #define NUM_U64_IRQS (N_IRQS + BITS_U64 - 1) / BITS_U64
23
+
19
24
static uint64_t irq_ctrl_timer = NSI_NEVER ;
20
25
21
- static uint64_t irq_status ; /* pending interrupts */
22
- static uint64_t irq_premask ; /* interrupts before the mask */
26
+ // Bitmasks for each interrupt.
27
+ static uint64_t irq_status [NUM_U64_IRQS ] = {0 }; // Pending interrupts.
28
+ static uint64_t irq_premask [NUM_U64_IRQS ] = {0 }; // Interrupts before the mask.
23
29
24
30
/*
25
31
* Mask of which interrupts will actually cause the cpu to vector into its
@@ -28,8 +34,9 @@ static uint64_t irq_premask; /* interrupts before the mask */
28
34
* case it is enabled later before clearing it.
29
35
* If the irq_mask enables and interrupt pending in irq_premask, it will cause
30
36
* the controller to raise the interrupt immediately
37
+ * 0 means masked, 1 means unmasked
31
38
*/
32
- static uint64_t irq_mask ;
39
+ static uint64_t irq_mask [ NUM_U64_IRQS ] = { 0 } ;
33
40
34
41
/*
35
42
* Interrupts lock/disable. When set, interrupts are registered
@@ -44,10 +51,17 @@ static uint8_t irq_prio[N_IRQS]; /* Priority of each interrupt */
44
51
45
52
static int currently_running_prio = 256 ; /* 255 is the lowest prio interrupt */
46
53
54
+ static uint64_t global_irq_to_bitmask (unsigned int irq , size_t * u64_idx ) {
55
+ * u64_idx = irq / BITS_U64 ;
56
+ return ((uint64_t ) 1 << (irq % BITS_U64 ));
57
+ }
58
+
47
59
static void hw_irq_ctrl_init (void )
48
60
{
49
- irq_mask = 0U ; /* Let's assume all interrupts are disable at boot */
50
- irq_premask = 0U ;
61
+ for (int i = 0 ; i < NUM_U64_IRQS ; i ++ ) {
62
+ irq_mask [i ] = 0 ;
63
+ irq_premask [i ] = 0 ;
64
+ }
51
65
irqs_locked = false;
52
66
lock_ignore = false;
53
67
@@ -70,11 +84,17 @@ int hw_irq_ctrl_get_cur_prio(void)
70
84
71
85
void hw_irq_ctrl_prio_set (unsigned int irq , unsigned int prio )
72
86
{
87
+ if (irq >= N_IRQS ) {
88
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
89
+ }
73
90
irq_prio [irq ] = prio ;
74
91
}
75
92
76
93
uint8_t hw_irq_ctrl_get_prio (unsigned int irq )
77
94
{
95
+ if (irq >= N_IRQS ) {
96
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
97
+ }
78
98
return irq_prio [irq ];
79
99
}
80
100
@@ -90,18 +110,19 @@ int hw_irq_ctrl_get_highest_prio_irq(void)
90
110
return -1 ;
91
111
}
92
112
93
- uint64_t irq_status_temp = hw_irq_ctrl_get_irq_status ();
94
113
int winner = -1 ;
95
114
int winner_prio = 256 ;
96
115
97
- while (irq_status_temp != 0U ) {
98
- int irq_nbr = nsi_find_lsb_set64 (irq_status_temp ) - 1 ;
99
-
100
- irq_status_temp &= ~((uint64_t ) 1 << irq_nbr );
101
- if ((winner_prio > (int )irq_prio [irq_nbr ])
102
- && (currently_running_prio > (int )irq_prio [irq_nbr ])) {
103
- winner = irq_nbr ;
104
- winner_prio = irq_prio [irq_nbr ];
116
+ for (int i = 0 ; i < NUM_U64_IRQS ; i ++ ) {
117
+ uint64_t status = irq_status [i ];
118
+ while (status != 0 ) {
119
+ int bit_idx = nsi_find_lsb_set64 (status ) - 1 ;
120
+ int irq_nbr = bit_idx + (i * BITS_U64 );
121
+ if (winner_prio > irq_prio [irq_nbr ] && currently_running_prio > irq_prio [irq_nbr ]) {
122
+ winner = irq_nbr ;
123
+ winner_prio = irq_prio [irq_nbr ];
124
+ }
125
+ status &= ~(1ULL << bit_idx );
105
126
}
106
127
}
107
128
return winner ;
@@ -124,45 +145,58 @@ uint32_t hw_irq_ctrl_change_lock(uint32_t new_lock)
124
145
125
146
irqs_locked = new_lock ;
126
147
127
- if ((previous_lock == true) && (new_lock == false) && (irq_status != 0U )) {
128
- nsif_cpu0_irq_raised_from_sw ();
148
+ if ((previous_lock == true) && (new_lock == false)) {
149
+ for (int i = 0 ; i < NUM_U64_IRQS ; i ++ ) {
150
+ if (irq_status [i ] != 0 ) {
151
+ nsif_cpu0_irq_raised_from_sw ();
152
+ break ;
153
+ }
154
+ }
129
155
}
130
156
return previous_lock ;
131
157
}
132
158
159
+ #if N_IRQS <= 64
133
160
uint64_t hw_irq_ctrl_get_irq_status (void )
134
161
{
135
- return irq_status ;
162
+ return irq_status [ 0 ] ;
136
163
}
164
+ #endif
137
165
138
166
void hw_irq_ctrl_clear_all_enabled_irqs (void )
139
167
{
140
- irq_status = 0U ;
141
- irq_premask &= ~irq_mask ;
168
+ for (int i = 0 ; i < NUM_U64_IRQS ; i ++ ) {
169
+ irq_status [i ] = 0 ;
170
+ irq_premask [i ] &= ~irq_mask [i ];
171
+ }
142
172
}
143
173
144
174
void hw_irq_ctrl_clear_all_irqs (void )
145
175
{
146
- irq_status = 0U ;
147
- irq_premask = 0U ;
176
+ for (int i = 0 ; i < NUM_U64_IRQS ; i ++ ) {
177
+ irq_status [i ] = 0 ;
178
+ irq_premask [i ] = 0 ;
179
+ }
148
180
}
149
181
150
182
void hw_irq_ctrl_disable_irq (unsigned int irq )
151
183
{
152
- irq_mask &= ~((uint64_t )1 <<irq );
184
+ if (irq >= N_IRQS ) {
185
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
186
+ }
187
+ size_t u64_idx ;
188
+ uint64_t bit_mask = global_irq_to_bitmask (irq , & u64_idx );
189
+ irq_mask [u64_idx ] &= ~bit_mask ;
153
190
}
154
191
155
192
int hw_irq_ctrl_is_irq_enabled (unsigned int irq )
156
193
{
157
- return (irq_mask & ((uint64_t )1 << irq ))?1 :0 ;
158
- }
159
-
160
- /**
161
- * Get the current interrupt enable mask
162
- */
163
- uint64_t hw_irq_ctrl_get_irq_mask (void )
164
- {
165
- return irq_mask ;
194
+ if (irq >= N_IRQS ) {
195
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
196
+ }
197
+ size_t u64_idx ;
198
+ uint64_t bit_mask = global_irq_to_bitmask (irq , & u64_idx );
199
+ return irq_mask [u64_idx ] & bit_mask ;
166
200
}
167
201
168
202
/*
@@ -173,8 +207,13 @@ uint64_t hw_irq_ctrl_get_irq_mask(void)
173
207
*/
174
208
void hw_irq_ctrl_clear_irq (unsigned int irq )
175
209
{
176
- irq_status &= ~((uint64_t )1 <<irq );
177
- irq_premask &= ~((uint64_t )1 <<irq );
210
+ if (irq >= N_IRQS ) {
211
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
212
+ }
213
+ size_t u64_idx ;
214
+ uint64_t bit_mask = global_irq_to_bitmask (irq , & u64_idx );
215
+ irq_status [u64_idx ] &= ~bit_mask ;
216
+ irq_premask [u64_idx ] &= ~bit_mask ;
178
217
}
179
218
180
219
@@ -188,24 +227,31 @@ void hw_irq_ctrl_clear_irq(unsigned int irq)
188
227
*/
189
228
void hw_irq_ctrl_enable_irq (unsigned int irq )
190
229
{
191
- irq_mask |= ((uint64_t )1 <<irq );
192
- if (irq_premask & ((uint64_t )1 <<irq )) { /* if the interrupt is pending */
230
+ if (irq >= N_IRQS ) {
231
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
232
+ }
233
+ size_t u64_idx ;
234
+ uint64_t bit_mask = global_irq_to_bitmask (irq , & u64_idx );
235
+ irq_mask [u64_idx ] |= bit_mask ;
236
+ if (irq_premask [u64_idx ] & bit_mask ) { /* if the interrupt is pending */
193
237
hw_irq_ctrl_raise_im_from_sw (irq );
194
238
}
195
239
}
196
240
197
241
static inline void hw_irq_ctrl_irq_raise_prefix (unsigned int irq )
198
242
{
199
- if (irq < N_IRQS ) {
200
- irq_premask |= ((uint64_t )1 <<irq );
201
-
202
- if (irq_mask & ((uint64_t )1 << irq )) {
203
- irq_status |= ((uint64_t )1 <<irq );
204
- }
205
- } else if (irq == PHONY_HARD_IRQ ) {
243
+ if (irq == PHONY_HARD_IRQ ) {
206
244
lock_ignore = true;
207
- } else {
208
- /* PHONY_WEAK_IRQ does not require any action */
245
+ } else if (irq >= N_IRQS ) {
246
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
247
+ }
248
+ size_t u64_idx ;
249
+ uint64_t bit_mask = global_irq_to_bitmask (irq , & u64_idx );
250
+
251
+ irq_premask [u64_idx ] |= bit_mask ;
252
+
253
+ if (irq_mask [u64_idx ] & bit_mask ) {
254
+ irq_status [u64_idx ] |= bit_mask ;
209
255
}
210
256
}
211
257
@@ -217,6 +263,9 @@ static inline void hw_irq_ctrl_irq_raise_prefix(unsigned int irq)
217
263
*/
218
264
void hw_irq_ctrl_set_irq (unsigned int irq )
219
265
{
266
+ if (irq >= N_IRQS ) {
267
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
268
+ }
220
269
hw_irq_ctrl_irq_raise_prefix (irq );
221
270
if ((irqs_locked == false) || lock_ignore ) {
222
271
/*
@@ -254,6 +303,9 @@ static void irq_raising_from_hw_now(void)
254
303
*/
255
304
void hw_irq_ctrl_raise_im (unsigned int irq )
256
305
{
306
+ if (irq >= N_IRQS ) {
307
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
308
+ }
257
309
hw_irq_ctrl_irq_raise_prefix (irq );
258
310
irq_raising_from_hw_now ();
259
311
}
@@ -265,6 +317,9 @@ void hw_irq_ctrl_raise_im(unsigned int irq)
265
317
*/
266
318
void hw_irq_ctrl_raise_im_from_sw (unsigned int irq )
267
319
{
320
+ if (irq >= N_IRQS ) {
321
+ nsi_print_error_and_exit ("Interrupt %i is out of range\n" , irq );
322
+ }
268
323
hw_irq_ctrl_irq_raise_prefix (irq );
269
324
270
325
if (irqs_locked == false) {
0 commit comments