1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2023 Meta.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/device.h>
9 #include <zephyr/irq.h>
10 #include <zephyr/sw_isr_table.h>
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/sys/util.h>
13
14 BUILD_ASSERT(CONFIG_MAX_IRQ_PER_AGGREGATOR < BIT(CONFIG_2ND_LEVEL_INTERRUPT_BITS),
15 "L2 bits not enough to cover the number of L2 IRQs");
16 #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
17 BUILD_ASSERT(CONFIG_MAX_IRQ_PER_AGGREGATOR < BIT(CONFIG_3RD_LEVEL_INTERRUPT_BITS),
18 "L3 bits not enough to cover the number of L3 IRQs");
19 #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
20
21 /**
22 * @brief Get the aggregator that's responsible for the given irq
23 *
24 * @param irq IRQ number to query
25 *
26 * @return Aggregator entry, NULL if irq is level 1 or not found.
27 */
get_intc_entry_for_irq(unsigned int irq)28 static const struct _irq_parent_entry *get_intc_entry_for_irq(unsigned int irq)
29 {
30 const unsigned int level = irq_get_level(irq);
31
32 /* 1st level aggregator is not registered */
33 if (level == 1) {
34 return NULL;
35 }
36
37 const unsigned int intc_irq = irq_get_intc_irq(irq);
38
39 /* Find an aggregator entry that matches the level & intc_irq */
40 STRUCT_SECTION_FOREACH_ALTERNATE(intc_table, _irq_parent_entry, intc) {
41 if ((intc->level == level) && (intc->irq == intc_irq)) {
42 return intc;
43 }
44 }
45
46 return NULL;
47 }
48
z_get_sw_isr_device_from_irq(unsigned int irq)49 const struct device *z_get_sw_isr_device_from_irq(unsigned int irq)
50 {
51 const struct _irq_parent_entry *intc = get_intc_entry_for_irq(irq);
52
53 __ASSERT(intc != NULL, "can't find an aggregator to handle irq(%X)", irq);
54
55 return intc != NULL ? intc->dev : NULL;
56 }
57
z_get_sw_isr_irq_from_device(const struct device * dev)58 unsigned int z_get_sw_isr_irq_from_device(const struct device *dev)
59 {
60 /* Get the IRQN for the aggregator */
61 STRUCT_SECTION_FOREACH_ALTERNATE(intc_table, _irq_parent_entry, intc) {
62 if (intc->dev == dev) {
63 return intc->irq;
64 }
65 }
66
67 __ASSERT(false, "dev(%p) not found", dev);
68
69 return 0;
70 }
71
z_get_sw_isr_table_idx(unsigned int irq)72 unsigned int z_get_sw_isr_table_idx(unsigned int irq)
73 {
74 unsigned int table_idx, local_irq;
75 const struct _irq_parent_entry *intc = get_intc_entry_for_irq(irq);
76 const unsigned int level = irq_get_level(irq);
77
78 if (intc != NULL) {
79 local_irq = irq_from_level(irq, level);
80 __ASSERT_NO_MSG(local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR);
81
82 table_idx = intc->offset + local_irq;
83 } else {
84 /* irq level must be 1 if no intc entry */
85 __ASSERT(level == 1, "can't find an aggregator to handle irq(%X)", irq);
86 table_idx = irq;
87 }
88
89 table_idx -= CONFIG_GEN_IRQ_START_VECTOR;
90
91 __ASSERT(table_idx < IRQ_TABLE_SIZE, "table_idx(%d) < IRQ_TABLE_SIZE(%d)", table_idx,
92 IRQ_TABLE_SIZE);
93
94 return table_idx;
95 }
96