From be66a2040f93f299487b7865988c520d76866608 Mon Sep 17 00:00:00 2001 From: Joshua Lilly Date: Tue, 1 Aug 2023 14:44:51 -0700 Subject: [PATCH] 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 --- doc/kernel/services/interrupts.rst | 17 ++++++++ .../interrupt_controller/Kconfig.multilevel | 24 +++++++++++ include/zephyr/irq.h | 40 +++++++++++++------ scripts/build/gen_isr_tables.py | 34 +++++++++++++++- 4 files changed, 100 insertions(+), 15 deletions(-) diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index 7746cc594ba0dea..1496dc7fa7aef55 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -455,6 +455,23 @@ unique identifier which is then used to fetch the appropriate handler function and parameter out of a table populated when the dynamic interrupt was connected. +Going Beyond the Default Supported Number of Interrupts +------------------------------------------------------- + +When generating interrupts in the multilevel configuration, 8-bits per level is the default +mask used when determining which level a given interrupt code belongs to. This can become +a problem when dealing with CPUs that support more than 255 interrupts per single +aggregator. In this case it may be desirable to override these defaults and use a custom +number of bits per level. Regardless of how many bits used for each level, the sum of +the total bits used between all levels must sum to be less than or equal to 32-bits, +fitting into a single 32-bit integer. To modify the bit total per level, override the +default 8 in `Kconfig.multilevel` by setting :kconfig:option:`CONFIG_1ST_LEVEL_INTERRUPT_BITS` +for the first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second tier and +:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third tier. These masks control the +length of the bit masks and shift to apply when generating interrupt values, when checking the +interrupts level and converting interrupts to a different level. The logic controlling +this can be found in `irq.h` + Suggested Uses ************** diff --git a/drivers/interrupt_controller/Kconfig.multilevel b/drivers/interrupt_controller/Kconfig.multilevel index a5be2f276cb4dc7..020f148b05f129d 100644 --- a/drivers/interrupt_controller/Kconfig.multilevel +++ b/drivers/interrupt_controller/Kconfig.multilevel @@ -18,6 +18,14 @@ config MULTI_LEVEL_INTERRUPTS by the hardware. (The term "aggregator" here means "interrupt controller".) +config 1ST_LEVEL_INTERRUPT_BITS + int "Total number of first level interrupt bits" + range 1 32 + default 8 + help + The number of bits to use of the 32 bit interrupt mask for first + tier interrupts. + config MAX_IRQ_PER_AGGREGATOR int "Max IRQs per interrupt aggregator" default 0 @@ -52,6 +60,14 @@ config NUM_2ND_LEVEL_AGGREGATORS aggregator can manage at most MAX_IRQ_PER_AGGREGATOR level 2 interrupts. +config 2ND_LEVEL_INTERRUPT_BITS + int "Total number of second level interrupt bits" + range 1 31 + default 8 + help + The number of bits to use of the 32 bit interrupt mask for second + tier interrupts. + prev-level-num = 1 cur-level-num = 2 cur-level = 2ND @@ -98,6 +114,14 @@ config 3RD_LVL_ISR_TBL_OFFSET where storage for 3rd level interrupt ISRs begins. This is typically allocated after ISRs for level 2 interrupts. +config 3RD_LEVEL_INTERRUPT_BITS + int "Total number of third level interrupt bits" + range 1 30 + default 8 + help + The number of bits to use of the 32 bit interrupt mask for third + tier interrupts. + prev-level-num = 2 cur-level-num = 3 cur-level = 3RD diff --git a/include/zephyr/irq.h b/include/zephyr/irq.h index b68d91738196c75..fb9d32a9ac06df2 100644 --- a/include/zephyr/irq.h +++ b/include/zephyr/irq.h @@ -13,6 +13,8 @@ /* Pull in the arch-specific implementations */ #include +#include +#include #ifndef _ASMLANGUAGE #include @@ -22,6 +24,11 @@ extern "C" { #endif +#if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) && CONFIG_MAX_IRQ_PER_AGGREGATOR > 0 +BUILD_ASSERT((LOG2(CONFIG_MAX_IRQ_PER_AGGREGATOR) + 1) <= CONFIG_1ST_LEVEL_INTERRUPT_BITS, + "CONFIG_MAX_IRQ_PER_AGGREGATOR is too large"); +#endif + /** * @defgroup isr_apis Interrupt Service Routine APIs * @ingroup kernel_apis @@ -255,6 +262,7 @@ void z_smp_global_unlock(unsigned int key); #define irq_unlock(key) arch_irq_unlock(key) #endif +#if defined(CONFIG_2ND_LEVEL_INTERRUPTS) /** * @brief Return IRQ level * This routine returns the interrupt level number of the provided interrupt. @@ -266,10 +274,16 @@ void z_smp_global_unlock(unsigned int key); static inline unsigned int irq_get_level(unsigned int irq) { #if defined(CONFIG_3RD_LEVEL_INTERRUPTS) - return ((irq >> 16) & 0xFF) != 0 ? 3 : - (((irq >> 8) & 0xFF) == 0 ? 1 : 2); + return ((irq >> CONFIG_3RD_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS) + & BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS) << + (CONFIG_2ND_LEVEL_INTERRUPT_BITS + CONFIG_3RD_LEVEL_INTERRUPT_BITS)) != 0 ? + 3 : (((irq >> CONFIG_2ND_LEVEL_INTERRUPT_BITS) + & BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) << + CONFIG_2ND_LEVEL_INTERRUPT_BITS) == 0 ? 1 : 2); #elif defined(CONFIG_2ND_LEVEL_INTERRUPTS) - return ((irq >> 8) & 0xFF) == 0 ? 1 : 2; + return ((irq >> CONFIG_2ND_LEVEL_INTERRUPT_BITS) & + BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) << CONFIG_2ND_LEVEL_INTERRUPT_BITS) == 0 ? + 1 : 2; #else ARG_UNUSED(irq); @@ -277,11 +291,9 @@ static inline unsigned int irq_get_level(unsigned int irq) #endif } -#ifdef CONFIG_2ND_LEVEL_INTERRUPTS /** * @brief Return the 2nd level interrupt number * - * * This routine returns the second level irq number of the zephyr irq * number passed in * @@ -291,10 +303,11 @@ static inline unsigned int irq_get_level(unsigned int irq) */ static inline unsigned int irq_from_level_2(unsigned int irq) { -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - return ((irq >> 8) & 0xFF) - 1; +#if defined(CONFIG_3RD_LEVEL_INTERRUPTS) + return ((irq >> CONFIG_2ND_LEVEL_INTERRUPT_BITS) & + BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS)) - 1; #else - return (irq >> 8) - 1; + return (irq >> CONFIG_2ND_LEVEL_INTERRUPT_BITS) - 1; #endif } @@ -312,7 +325,7 @@ static inline unsigned int irq_from_level_2(unsigned int irq) */ static inline unsigned int irq_to_level_2(unsigned int irq) { - return (irq + 1) << 8; + return (irq + 1) << CONFIG_2ND_LEVEL_INTERRUPT_BITS; } /** @@ -327,7 +340,7 @@ static inline unsigned int irq_to_level_2(unsigned int irq) */ static inline unsigned int irq_parent_level_2(unsigned int irq) { - return irq & 0xFF; + return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); } #endif @@ -345,7 +358,7 @@ static inline unsigned int irq_parent_level_2(unsigned int irq) */ static inline unsigned int irq_from_level_3(unsigned int irq) { - return (irq >> 16) - 1; + return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS) - 1; } /** @@ -362,7 +375,7 @@ static inline unsigned int irq_from_level_3(unsigned int irq) */ static inline unsigned int irq_to_level_3(unsigned int irq) { - return (irq + 1) << 16; + return (irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS; } /** @@ -377,7 +390,8 @@ static inline unsigned int irq_to_level_3(unsigned int irq) */ static inline unsigned int irq_parent_level_3(unsigned int irq) { - return (irq >> 8) & 0xFF; + return (irq >> CONFIG_2ND_LEVEL_INTERRUPT_BITS) & + BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); } #endif diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index 708557582dc4044..7aa671dcbd6aa29 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -27,6 +27,8 @@ SECND_LVL_INTERRUPTS = 0x0000FF00 THIRD_LVL_INTERRUPTS = 0x00FF0000 +INTERRUPT_BITS = [8, 8, 8] + def debug(text): if args.debug: sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") @@ -230,6 +232,24 @@ def getindex(irq, irq_aggregator_pos): format(irq, irq_aggregator_pos) + " Recheck interrupt configuration.") +def bit_mask(bits): + mask = 0 + for _ in range(0, bits): + mask = (mask << 1) | 1 + return mask + +def update_masks(): + global FIRST_LVL_INTERRUPTS + global SECND_LVL_INTERRUPTS + global THIRD_LVL_INTERRUPTS + + if sum(INTERRUPT_BITS) > 32: + raise ValueError("Too many interrupt bits") + + FIRST_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[0]) + SECND_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[1] + THIRD_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[2] + def main(): parse_args() @@ -240,6 +260,8 @@ def main(): if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"] + INTERRUPT_BITS[0] = syms["CONFIG_1ST_LEVEL_INTERRUPT_BITS"] + if "CONFIG_2ND_LEVEL_INTERRUPTS" in syms: num_aggregators = syms["CONFIG_NUM_2ND_LEVEL_AGGREGATORS"] irq2_baseoffset = syms["CONFIG_2ND_LVL_ISR_TBL_OFFSET"] @@ -247,6 +269,9 @@ def main(): format(str(i).zfill(2))] for i in range(num_aggregators)] + + INTERRUPT_BITS[1] = syms["CONFIG_2ND_LEVEL_INTERRUPT_BITS"] + debug('2nd level offsets: {}'.format(list_2nd_lvl_offsets)) if "CONFIG_3RD_LEVEL_INTERRUPTS" in syms: @@ -256,8 +281,12 @@ def main(): format(str(i).zfill(2))] for i in range(num_aggregators)] + + INTERRUPT_BITS[2] = syms["CONFIG_3RD_LEVEL_INTERRUPT_BITS"] + debug('3rd level offsets: {}'.format(list_3rd_lvl_offsets)) + update_masks() intlist = read_intlist(args.intlist, syms) nvec = intlist["num_vectors"] offset = intlist["offset"] @@ -266,6 +295,7 @@ def main(): raise ValueError('nvec is too large, check endianness.') swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" + vt_spurious_handler = "z_irq_spurious" vt_irq_handler = "_isr_wrapper" @@ -311,8 +341,8 @@ def main(): else: # Figure out third level interrupt position debug('IRQ = ' + hex(irq)) - irq3 = (irq & THIRD_LVL_INTERRUPTS) >> 16 - irq2 = (irq & SECND_LVL_INTERRUPTS) >> 8 + irq3 = (irq & THIRD_LVL_INTERRUPTS) >> INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + irq2 = (irq & SECND_LVL_INTERRUPTS) >> INTERRUPT_BITS[1] irq1 = irq & FIRST_LVL_INTERRUPTS if irq3: