/* * Copyright (c) 2018 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include /* * Common code for arches that use software ISR tables (CONFIG_GEN_ISR_TABLES) */ #ifdef CONFIG_DYNAMIC_INTERRUPTS #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS struct irq_parent_offset { unsigned int irq; unsigned int offset; }; #define INIT_IRQ_PARENT_OFFSET(i, o) { \ .irq = i, \ .offset = o, \ }, #define IRQ_INDEX_TO_OFFSET(i, base) (base + i * CONFIG_MAX_IRQ_PER_AGGREGATOR) #ifdef CONFIG_2ND_LEVEL_INTERRUPTS #define CAT_2ND_LVL_LIST(i, base) \ INIT_IRQ_PARENT_OFFSET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET, \ IRQ_INDEX_TO_OFFSET(i, base)) static struct irq_parent_offset lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] = { UTIL_LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, CONFIG_2ND_LVL_ISR_TBL_OFFSET) }; #endif/* CONFIG_2ND_LEVEL_INTERRUPTS */ #ifdef CONFIG_3RD_LEVEL_INTERRUPTS #define CAT_3RD_LVL_LIST(i, base) \ INIT_IRQ_PARENT_OFFSET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET, \ IRQ_INDEX_TO_OFFSET(i, base)) static struct irq_parent_offset lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] = { UTIL_LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, CONFIG_3RD_LVL_ISR_TBL_OFFSET) }; #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ unsigned int get_parent_offset(unsigned int parent_irq, struct irq_parent_offset list[], unsigned int length) { unsigned int i; unsigned int offset = 0; for (i = 0; i < length; ++i) { if (list[i].irq == parent_irq) { offset = list[i].offset; break; } } __ASSERT(i != length, "Invalid argument: %i", parent_irq); return offset; } #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ void z_isr_install(unsigned int irq, void (*routine)(void *), void *param) { unsigned int table_idx; /* * Do not assert on the IRQ enable status for ARM GIC since the SGI * type interrupts are always enabled and attempting to install an ISR * for them will cause the assertion to fail. */ #ifndef CONFIG_GIC __ASSERT(!irq_is_enabled(irq), "IRQ %d is enabled", irq); #endif /* !CONFIG_GIC */ #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS unsigned int level; unsigned int parent_irq; unsigned int parent_offset; level = irq_get_level(irq); if (level == 2) { parent_irq = irq_parent_level_2(irq); parent_offset = get_parent_offset(parent_irq, lvl2_irq_list, CONFIG_NUM_2ND_LEVEL_AGGREGATORS); table_idx = parent_offset + irq_from_level_2(irq); } #ifdef CONFIG_3RD_LEVEL_INTERRUPTS else if (level == 3) { parent_irq = irq_parent_level_3(irq); parent_offset = get_parent_offset(parent_irq, lvl3_irq_list, CONFIG_NUM_3RD_LEVEL_AGGREGATORS); table_idx = parent_offset + irq_from_level_3(irq); } #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ else { table_idx = irq; } table_idx -= CONFIG_GEN_IRQ_START_VECTOR; #else table_idx = irq - CONFIG_GEN_IRQ_START_VECTOR; #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ /* If dynamic IRQs are enabled, then the _sw_isr_table is in RAM and * can be modified */ _sw_isr_table[table_idx].arg = param; _sw_isr_table[table_idx].isr = routine; } /* Some architectures don't/can't interpret flags or priority and have * no more processing to do than this. Provide a generic fallback. */ int __weak arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(void *), void *parameter, uint32_t flags) { ARG_UNUSED(flags); ARG_UNUSED(priority); z_isr_install(irq, routine, parameter); return irq; } #endif /* CONFIG_DYNAMIC_INTERRUPTS */