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