Skip to content

Commit cce530c

Browse files
jgl-metacfriedt
authored andcommitted
scripts: build: gen_isr_tables: make bit masks configurable
Some architectures such as RISC-v support more than 255 interrupts per aggrigator. This diff adds the ability to forgo the aggrigator pattern and use a configurable number of bits for multilevel interruts. Signed-off-by: Joshua Lilly <[email protected]>
1 parent 02f4aeb commit cce530c

File tree

6 files changed

+207
-20
lines changed

6 files changed

+207
-20
lines changed

doc/kernel/services/interrupts.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,23 @@ unique identifier which is then used to fetch the appropriate handler function
455455
and parameter out of a table populated when the dynamic interrupt was
456456
connected.
457457

458+
Going Beyond the Default Supported Number of Interrupts
459+
-------------------------------------------------------
460+
461+
When generating interrupts in the multilevel configuration, 8-bits per level is the default
462+
mask used when determining which level a given interrupt code belongs to. This can become
463+
a problem when dealing with CPUs that support more than 255 interrupts per single
464+
aggregator. In this case it may be desirable to override these defaults and use a custom
465+
number of bits per level. Regardless of how many bits used for each level, the sum of
466+
the total bits used between all levels must sum to be less than or equal to 32-bits,
467+
fitting into a single 32-bit integer. To modify the bit total per level, override the
468+
default 8 in `Kconfig.multilevel` by setting :kconfig:option:`CONFIG_1ST_LEVEL_INTERRUPT_BITS`
469+
for the first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second tier and
470+
:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third tier. These masks control the
471+
length of the bit masks and shift to apply when generating interrupt values, when checking the
472+
interrupts level and converting interrupts to a different level. The logic controlling
473+
this can be found in `irq.h`
474+
458475
Suggested Uses
459476
**************
460477

drivers/interrupt_controller/Kconfig.multilevel

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,19 @@ config MULTI_LEVEL_INTERRUPTS
1818
by the hardware. (The term "aggregator" here means "interrupt
1919
controller".)
2020

21+
config 1ST_LEVEL_INTERRUPT_BITS
22+
int "Total number of first level interrupt bits"
23+
range 1 32
24+
default 8
25+
help
26+
The number of bits to use of the 32 bit interrupt mask for first
27+
tier interrupts.
28+
2129
config MAX_IRQ_PER_AGGREGATOR
2230
int "Max IRQs per interrupt aggregator"
2331
default 0
2432
depends on MULTI_LEVEL_INTERRUPTS
33+
2534
help
2635
The maximum number of interrupt inputs to any aggregator in the
2736
system.
@@ -52,6 +61,14 @@ config NUM_2ND_LEVEL_AGGREGATORS
5261
aggregator can manage at most MAX_IRQ_PER_AGGREGATOR level 2
5362
interrupts.
5463

64+
config 2ND_LEVEL_INTERRUPT_BITS
65+
int "Total number of second level interrupt bits"
66+
range 0 31
67+
default 8
68+
help
69+
The number of bits to use of the 32 bit interrupt mask for second
70+
tier interrupts.
71+
5572
prev-level-num = 1
5673
cur-level-num = 2
5774
cur-level = 2ND
@@ -98,6 +115,14 @@ config 3RD_LVL_ISR_TBL_OFFSET
98115
where storage for 3rd level interrupt ISRs begins. This is
99116
typically allocated after ISRs for level 2 interrupts.
100117

118+
config 3RD_LEVEL_INTERRUPT_BITS
119+
int "Total number of third level interrupt bits"
120+
range 0 30
121+
default 8
122+
help
123+
The number of bits to use of the 32 bit interrupt mask for third
124+
tier interrupts.
125+
101126
prev-level-num = 2
102127
cur-level-num = 3
103128
cur-level = 3RD

include/zephyr/irq.h

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
/* Pull in the arch-specific implementations */
1515
#include <zephyr/arch/cpu.h>
16+
#include <zephyr/sys/util.h>
1617

1718
#ifndef _ASMLANGUAGE
1819
#include <zephyr/toolchain.h>
@@ -22,6 +23,11 @@
2223
extern "C" {
2324
#endif
2425

26+
#if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) && CONFIG_MAX_IRQ_PER_AGGREGATOR > 0
27+
BUILD_ASSERT((LOG2(CONFIG_MAX_IRQ_PER_AGGREGATOR) + 1) <= CONFIG_1ST_LEVEL_INTERRUPT_BITS,
28+
"CONFIG_MAX_IRQ_PER_AGGREGATOR is too large");
29+
#endif
30+
2531
/**
2632
* @defgroup isr_apis Interrupt Service Routine APIs
2733
* @ingroup kernel_apis
@@ -265,23 +271,26 @@ void z_smp_global_unlock(unsigned int key);
265271
*/
266272
static inline unsigned int irq_get_level(unsigned int irq)
267273
{
268-
#if defined(CONFIG_3RD_LEVEL_INTERRUPTS)
269-
return ((irq >> 16) & 0xFF) != 0 ? 3 :
270-
(((irq >> 8) & 0xFF) == 0 ? 1 : 2);
271-
#elif defined(CONFIG_2ND_LEVEL_INTERRUPTS)
272-
return ((irq >> 8) & 0xFF) == 0 ? 1 : 2;
273-
#else
274-
ARG_UNUSED(irq);
274+
const uint32_t mask2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) <<
275+
CONFIG_1ST_LEVEL_INTERRUPT_BITS;
276+
const uint32_t mask3 = BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS) <<
277+
(CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS);
278+
279+
if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS) && (irq & mask3) != 0) {
280+
return 3;
281+
}
282+
283+
if (IS_ENABLED(CONFIG_2ND_LEVEL_INTERRUPTS) && (irq & mask2) != 0) {
284+
return 2;
285+
}
275286

276287
return 1;
277-
#endif
278288
}
279289

280-
#ifdef CONFIG_2ND_LEVEL_INTERRUPTS
290+
#if defined(CONFIG_2ND_LEVEL_INTERRUPTS)
281291
/**
282292
* @brief Return the 2nd level interrupt number
283293
*
284-
*
285294
* This routine returns the second level irq number of the zephyr irq
286295
* number passed in
287296
*
@@ -291,10 +300,11 @@ static inline unsigned int irq_get_level(unsigned int irq)
291300
*/
292301
static inline unsigned int irq_from_level_2(unsigned int irq)
293302
{
294-
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
295-
return ((irq >> 8) & 0xFF) - 1;
303+
#if defined(CONFIG_3RD_LEVEL_INTERRUPTS)
304+
return ((irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) &
305+
BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1;
296306
#else
297-
return (irq >> 8) - 1;
307+
return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) - 1;
298308
#endif
299309
}
300310

@@ -312,7 +322,7 @@ static inline unsigned int irq_from_level_2(unsigned int irq)
312322
*/
313323
static inline unsigned int irq_to_level_2(unsigned int irq)
314324
{
315-
return (irq + 1) << 8;
325+
return (irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS;
316326
}
317327

318328
/**
@@ -327,7 +337,7 @@ static inline unsigned int irq_to_level_2(unsigned int irq)
327337
*/
328338
static inline unsigned int irq_parent_level_2(unsigned int irq)
329339
{
330-
return irq & 0xFF;
340+
return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS);
331341
}
332342
#endif
333343

@@ -345,7 +355,7 @@ static inline unsigned int irq_parent_level_2(unsigned int irq)
345355
*/
346356
static inline unsigned int irq_from_level_3(unsigned int irq)
347357
{
348-
return (irq >> 16) - 1;
358+
return (irq >> (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1;
349359
}
350360

351361
/**
@@ -362,7 +372,7 @@ static inline unsigned int irq_from_level_3(unsigned int irq)
362372
*/
363373
static inline unsigned int irq_to_level_3(unsigned int irq)
364374
{
365-
return (irq + 1) << 16;
375+
return (irq + 1) << (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS);
366376
}
367377

368378
/**
@@ -377,7 +387,8 @@ static inline unsigned int irq_to_level_3(unsigned int irq)
377387
*/
378388
static inline unsigned int irq_parent_level_3(unsigned int irq)
379389
{
380-
return (irq >> 8) & 0xFF;
390+
return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) &
391+
BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS);
381392
}
382393
#endif
383394

scripts/build/gen_isr_tables.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
SECND_LVL_INTERRUPTS = 0x0000FF00
2828
THIRD_LVL_INTERRUPTS = 0x00FF0000
2929

30+
INTERRUPT_BITS = [8, 8, 8]
31+
3032
def debug(text):
3133
if args.debug:
3234
sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
@@ -230,6 +232,24 @@ def getindex(irq, irq_aggregator_pos):
230232
format(irq, irq_aggregator_pos) +
231233
" Recheck interrupt configuration.")
232234

235+
def bit_mask(bits):
236+
mask = 0
237+
for _ in range(0, bits):
238+
mask = (mask << 1) | 1
239+
return mask
240+
241+
def update_masks():
242+
global FIRST_LVL_INTERRUPTS
243+
global SECND_LVL_INTERRUPTS
244+
global THIRD_LVL_INTERRUPTS
245+
246+
if sum(INTERRUPT_BITS) > 32:
247+
raise ValueError("Too many interrupt bits")
248+
249+
FIRST_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[0])
250+
SECND_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0]
251+
THIRD_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[2]
252+
233253
def main():
234254
parse_args()
235255

@@ -240,6 +260,11 @@ def main():
240260
if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms:
241261
max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"]
242262

263+
INTERRUPT_BITS[0] = syms["CONFIG_1ST_LEVEL_INTERRUPT_BITS"]
264+
INTERRUPT_BITS[1] = syms["CONFIG_2ND_LEVEL_INTERRUPT_BITS"]
265+
INTERRUPT_BITS[2] = syms["CONFIG_3RD_LEVEL_INTERRUPT_BITS"]
266+
update_masks()
267+
243268
if "CONFIG_2ND_LEVEL_INTERRUPTS" in syms:
244269
num_aggregators = syms["CONFIG_NUM_2ND_LEVEL_AGGREGATORS"]
245270
irq2_baseoffset = syms["CONFIG_2ND_LVL_ISR_TBL_OFFSET"]
@@ -311,8 +336,8 @@ def main():
311336
else:
312337
# Figure out third level interrupt position
313338
debug('IRQ = ' + hex(irq))
314-
irq3 = (irq & THIRD_LVL_INTERRUPTS) >> 16
315-
irq2 = (irq & SECND_LVL_INTERRUPTS) >> 8
339+
irq3 = (irq & THIRD_LVL_INTERRUPTS) >> INTERRUPT_BITS[0] + INTERRUPT_BITS[1]
340+
irq2 = (irq & SECND_LVL_INTERRUPTS) >> INTERRUPT_BITS[0]
316341
irq1 = irq & FIRST_LVL_INTERRUPTS
317342

318343
if irq3:

tests/kernel/gen_isr_table/src/main.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,97 @@ static void *gen_isr_table_setup(void)
381381
return NULL;
382382
}
383383

384+
#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS
385+
ZTEST(gen_isr_table, test_multi_level_bit_masks_sec)
386+
{
387+
#if CONFIG_1ST_LEVEL_INTERRUPT_BITS < 10 && CONFIG_2ND_LEVEL_INTERRUPT_BITS < 10
388+
ztest_test_skip();
389+
#endif
390+
/* 0x400 is an l2 interrupt */
391+
unsigned int irq = 0x400;
392+
unsigned int level = 0;
393+
unsigned int ret_irq = 0;
394+
395+
level = irq_get_level(irq);
396+
397+
zassert_equal(2, level);
398+
399+
/* 0x40 is l1 interrupt since it is less than 10 bits */
400+
irq = 0x40;
401+
level = irq_get_level(irq);
402+
zassert_equal(1, level);
403+
404+
/* this is an l2 interrupt since it is more than 10 bits */
405+
irq = 0x800;
406+
ret_irq = irq_from_level_2(irq);
407+
zassert_equal(1, ret_irq);
408+
409+
/* convert l1 interrupt to l2 */
410+
irq = 0x1;
411+
ret_irq = irq_to_level_2(irq);
412+
zassert_equal(0x800, ret_irq);
413+
414+
/* get the parent of this l2 interrupt */
415+
irq = 0x401;
416+
ret_irq = irq_parent_level_2(irq);
417+
zassert_equal(1, ret_irq);
418+
}
419+
#endif
420+
421+
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
422+
ZTEST(gen_isr_table, test_multi_level_bit_masks_thr)
423+
{
424+
#if CONFIG_2ND_LEVEL_INTERRUPT_BITS < 10 && CONFIG_3RD_LEVEL_INTERRUPT_BITS < 9
425+
ztest_test_skip();
426+
# endif
427+
/* 0x400 is an l2 interrupt */
428+
unsigned int irq = 0x400;
429+
unsigned int level = 0;
430+
unsigned int ret_irq = 0;
431+
432+
433+
/* note the first part of this test is the same as the above
434+
* test this is to ensure the values are true after enabling l3 interrupts
435+
*/
436+
level = irq_get_level(irq);
437+
438+
zassert_equal(2, level);
439+
440+
/* this irq is within 10 bits so it is a l1 interrupt */
441+
irq = 0x40;
442+
level = irq_get_level(irq);
443+
zassert_equal(1, level);
444+
445+
/* this irq is in the second 10 bits so it is a l2 interrupt */
446+
irq = 0x800;
447+
ret_irq = irq_from_level_2(irq);
448+
zassert_equal(1, ret_irq);
449+
450+
/* convert a l1 interrupt to an l2 0x1 is less than 10 bits so it is l1 */
451+
irq = 0x1;
452+
ret_irq = irq_to_level_2(irq);
453+
zassert_equal(0x800, ret_irq);
454+
455+
/* get the parent of an l2 interrupt 0x401 is an l2 interrupt with parent 1 */
456+
irq = 0x401;
457+
ret_irq = irq_parent_level_2(irq);
458+
zassert_equal(1, ret_irq);
459+
460+
/* get the irq from level 3 this value is an l3 interrupt */
461+
irq = 0x200000;
462+
ret_irq = irq_from_level_3(irq);
463+
zassert_equal(1, ret_irq);
464+
465+
/* convert the zero interrupt to l3 */
466+
irq = 0x0;
467+
ret_irq = irq_to_level_3(irq);
468+
zassert_equal(0x100000, ret_irq);
469+
470+
/* parent of the l3 interrupt */
471+
irq = 0x101000;
472+
ret_irq = irq_parent_level_3(irq);
473+
zassert_equal(0x4, ret_irq);
474+
}
475+
#endif
476+
384477
ZTEST_SUITE(gen_isr_table, NULL, gen_isr_table_setup, NULL, NULL, NULL);

tests/kernel/gen_isr_table/testcase.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,19 @@ tests:
6464
filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED
6565
extra_configs:
6666
- CONFIG_GEN_IRQ_VECTOR_TABLE=n
67+
arch.interrupt.gen_isr_table.bit_shift_2nd_level:
68+
platform_allow: qemu_riscv32
69+
filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED
70+
extra_configs:
71+
- CONFIG_1ST_LEVEL_INTERRUPT_BITS=10
72+
- CONFIG_2ND_LEVEL_INTERRUPT_BITS=10
73+
arch.interrupt.gen_isr_table.bit_shift_3rd_level:
74+
platform_allow: qemu_riscv32
75+
filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED
76+
extra_configs:
77+
- CONFIG_MULTI_LEVEL_INTERRUPTS=y
78+
- CONFIG_2ND_LEVEL_INTERRUPTS=y
79+
- CONFIG_3RD_LEVEL_INTERRUPTS=y
80+
- CONFIG_1ST_LEVEL_INTERRUPT_BITS=10
81+
- CONFIG_2ND_LEVEL_INTERRUPT_BITS=10
82+
- CONFIG_3RD_LEVEL_INTERRUPT_BITS=9

0 commit comments

Comments
 (0)