Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | /* * Copyright (c) 2018 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #include <sw_isr_table.h> #include <arch/cpu.h> #include <sys/__assert.h> /* * 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 = 0U; for (i = 0U; 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)(const void *), const 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 == 2U) { 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 == 3U) { 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)(const void *), const void *parameter, uint32_t flags) { ARG_UNUSED(flags); ARG_UNUSED(priority); z_isr_install(irq, routine, parameter); return irq; } #endif /* CONFIG_DYNAMIC_INTERRUPTS */ |