Skip to content

Commit 49e8d3d

Browse files
committed
Add support for > 64 IRQs
1 parent 19293fa commit 49e8d3d

File tree

2 files changed

+107
-45
lines changed

2 files changed

+107
-45
lines changed

native/src/include/irq_ctrl.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515

1616
#include <stdint.h>
1717

18+
/* Default to 32 interrupts */
19+
#ifndef N_IRQS
20+
#define N_IRQS 32
21+
#endif
22+
1823
#ifdef __cplusplus
1924
extern "C" {
2025
#endif
@@ -28,7 +33,10 @@ uint8_t hw_irq_ctrl_get_prio(unsigned int irq);
2833
int hw_irq_ctrl_get_highest_prio_irq(void);
2934
uint32_t hw_irq_ctrl_get_current_lock(void);
3035
uint32_t hw_irq_ctrl_change_lock(uint32_t new_lock);
36+
// This function is only supported with <= 64 interrupts.
37+
#if N_IRQS <= 64
3138
uint64_t hw_irq_ctrl_get_irq_status(void);
39+
#endif
3240
void hw_irq_ctrl_disable_irq(unsigned int irq);
3341
int hw_irq_ctrl_is_irq_enabled(unsigned int irq);
3442
void hw_irq_ctrl_clear_irq(unsigned int irq);
@@ -37,7 +45,6 @@ void hw_irq_ctrl_set_irq(unsigned int irq);
3745
void hw_irq_ctrl_raise_im(unsigned int irq);
3846
void hw_irq_ctrl_raise_im_from_sw(unsigned int irq);
3947

40-
#define N_IRQS 32
4148

4249
#ifdef __cplusplus
4350
}

native/src/irq_ctrl.c

Lines changed: 99 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,23 @@
99

1010
#include <stdint.h>
1111
#include <stdbool.h>
12+
#include <stddef.h>
1213
#include "nsi_internal.h"
1314
#include "nsi_cpu_if.h"
1415
#include "nsi_cpu0_interrupts.h"
1516
#include "irq_ctrl.h"
1617
#include "nsi_tasks.h"
18+
#include "nsi_tracing.h"
1719
#include "nsi_hws_models_if.h"
1820

21+
#define BITS_U64 64
22+
#define NUM_U64_IRQS (N_IRQS + BITS_U64 - 1) / BITS_U64
23+
1924
static uint64_t irq_ctrl_timer = NSI_NEVER;
2025

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.
2329

2430
/*
2531
* 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 */
2834
* case it is enabled later before clearing it.
2935
* If the irq_mask enables and interrupt pending in irq_premask, it will cause
3036
* the controller to raise the interrupt immediately
37+
* 0 means masked, 1 means unmasked
3138
*/
32-
static uint64_t irq_mask;
39+
static uint64_t irq_mask[NUM_U64_IRQS] = {0};
3340

3441
/*
3542
* Interrupts lock/disable. When set, interrupts are registered
@@ -44,10 +51,17 @@ static uint8_t irq_prio[N_IRQS]; /* Priority of each interrupt */
4451

4552
static int currently_running_prio = 256; /* 255 is the lowest prio interrupt */
4653

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+
4759
static void hw_irq_ctrl_init(void)
4860
{
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+
}
5165
irqs_locked = false;
5266
lock_ignore = false;
5367

@@ -70,11 +84,17 @@ int hw_irq_ctrl_get_cur_prio(void)
7084

7185
void hw_irq_ctrl_prio_set(unsigned int irq, unsigned int prio)
7286
{
87+
if (irq >= N_IRQS) {
88+
nsi_print_error_and_exit("Interrupt %i is out of range\n", irq);
89+
}
7390
irq_prio[irq] = prio;
7491
}
7592

7693
uint8_t hw_irq_ctrl_get_prio(unsigned int irq)
7794
{
95+
if (irq >= N_IRQS) {
96+
nsi_print_error_and_exit("Interrupt %i is out of range\n", irq);
97+
}
7898
return irq_prio[irq];
7999
}
80100

@@ -90,18 +110,19 @@ int hw_irq_ctrl_get_highest_prio_irq(void)
90110
return -1;
91111
}
92112

93-
uint64_t irq_status_temp = hw_irq_ctrl_get_irq_status();
94113
int winner = -1;
95114
int winner_prio = 256;
96115

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);
105126
}
106127
}
107128
return winner;
@@ -124,45 +145,58 @@ uint32_t hw_irq_ctrl_change_lock(uint32_t new_lock)
124145

125146
irqs_locked = new_lock;
126147

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+
}
129155
}
130156
return previous_lock;
131157
}
132158

159+
#if N_IRQS <= 64
133160
uint64_t hw_irq_ctrl_get_irq_status(void)
134161
{
135-
return irq_status;
162+
return irq_status[0];
136163
}
164+
#endif
137165

138166
void hw_irq_ctrl_clear_all_enabled_irqs(void)
139167
{
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+
}
142172
}
143173

144174
void hw_irq_ctrl_clear_all_irqs(void)
145175
{
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+
}
148180
}
149181

150182
void hw_irq_ctrl_disable_irq(unsigned int irq)
151183
{
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;
153190
}
154191

155192
int hw_irq_ctrl_is_irq_enabled(unsigned int irq)
156193
{
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;
166200
}
167201

168202
/*
@@ -173,8 +207,13 @@ uint64_t hw_irq_ctrl_get_irq_mask(void)
173207
*/
174208
void hw_irq_ctrl_clear_irq(unsigned int irq)
175209
{
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;
178217
}
179218

180219

@@ -188,24 +227,31 @@ void hw_irq_ctrl_clear_irq(unsigned int irq)
188227
*/
189228
void hw_irq_ctrl_enable_irq(unsigned int irq)
190229
{
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 */
193237
hw_irq_ctrl_raise_im_from_sw(irq);
194238
}
195239
}
196240

197241
static inline void hw_irq_ctrl_irq_raise_prefix(unsigned int irq)
198242
{
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) {
206244
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;
209255
}
210256
}
211257

@@ -217,6 +263,9 @@ static inline void hw_irq_ctrl_irq_raise_prefix(unsigned int irq)
217263
*/
218264
void hw_irq_ctrl_set_irq(unsigned int irq)
219265
{
266+
if (irq >= N_IRQS) {
267+
nsi_print_error_and_exit("Interrupt %i is out of range\n", irq);
268+
}
220269
hw_irq_ctrl_irq_raise_prefix(irq);
221270
if ((irqs_locked == false) || lock_ignore) {
222271
/*
@@ -254,6 +303,9 @@ static void irq_raising_from_hw_now(void)
254303
*/
255304
void hw_irq_ctrl_raise_im(unsigned int irq)
256305
{
306+
if (irq >= N_IRQS) {
307+
nsi_print_error_and_exit("Interrupt %i is out of range\n", irq);
308+
}
257309
hw_irq_ctrl_irq_raise_prefix(irq);
258310
irq_raising_from_hw_now();
259311
}
@@ -265,6 +317,9 @@ void hw_irq_ctrl_raise_im(unsigned int irq)
265317
*/
266318
void hw_irq_ctrl_raise_im_from_sw(unsigned int irq)
267319
{
320+
if (irq >= N_IRQS) {
321+
nsi_print_error_and_exit("Interrupt %i is out of range\n", irq);
322+
}
268323
hw_irq_ctrl_irq_raise_prefix(irq);
269324

270325
if (irqs_locked == false) {

0 commit comments

Comments
 (0)