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_NUM_2ND_LEVEL_AGGREGATORS * CONFIG_MAX_IRQ_PER_AGGREGATOR) <=
15 		     BIT(CONFIG_2ND_LEVEL_INTERRUPT_BITS),
16 	     "L2 bits not enough to cover the number of L2 IRQs");
17 
18 /**
19  * @brief Get the aggregator that's responsible for the given irq
20  *
21  * @param irq IRQ number to query
22  *
23  * @return Aggregator entry, NULL if irq is level 1 or not found.
24  */
get_intc_entry_for_irq(unsigned int irq)25 static const struct _irq_parent_entry *get_intc_entry_for_irq(unsigned int irq)
26 {
27 	const unsigned int level = irq_get_level(irq);
28 
29 	/* 1st level aggregator is not registered */
30 	if (level == 1) {
31 		return NULL;
32 	}
33 
34 	const unsigned int intc_irq = irq_get_intc_irq(irq);
35 
36 	/* Find an aggregator entry that matches the level & intc_irq */
37 	STRUCT_SECTION_FOREACH_ALTERNATE(intc_table, _irq_parent_entry, intc) {
38 		if ((intc->level == level) && (intc->irq == intc_irq)) {
39 			return intc;
40 		}
41 	}
42 
43 	return NULL;
44 }
45 
z_get_sw_isr_device_from_irq(unsigned int irq)46 const struct device *z_get_sw_isr_device_from_irq(unsigned int irq)
47 {
48 	const struct _irq_parent_entry *intc = get_intc_entry_for_irq(irq);
49 
50 	__ASSERT(intc != NULL, "can't find an aggregator to handle irq(%X)", irq);
51 
52 	return intc != NULL ? intc->dev : NULL;
53 }
54 
z_get_sw_isr_irq_from_device(const struct device * dev)55 unsigned int z_get_sw_isr_irq_from_device(const struct device *dev)
56 {
57 	/* Get the IRQN for the aggregator */
58 	STRUCT_SECTION_FOREACH_ALTERNATE(intc_table, _irq_parent_entry, intc) {
59 		if (intc->dev == dev) {
60 			return intc->irq;
61 		}
62 	}
63 
64 	__ASSERT(false, "dev(%p) not found", dev);
65 
66 	return 0;
67 }
68 
z_get_sw_isr_table_idx(unsigned int irq)69 unsigned int z_get_sw_isr_table_idx(unsigned int irq)
70 {
71 	unsigned int table_idx, local_irq;
72 	const struct _irq_parent_entry *intc = get_intc_entry_for_irq(irq);
73 	const unsigned int level = irq_get_level(irq);
74 
75 	if (intc != NULL) {
76 		local_irq = irq_from_level(irq, level);
77 		__ASSERT_NO_MSG(local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR);
78 
79 		table_idx = intc->offset + local_irq;
80 	} else {
81 		/* irq level must be 1 if no intc entry */
82 		__ASSERT(level == 1, "can't find an aggregator to handle irq(%X)", irq);
83 		table_idx = irq;
84 	}
85 
86 	table_idx -= CONFIG_GEN_IRQ_START_VECTOR;
87 
88 	__ASSERT_NO_MSG(table_idx < IRQ_TABLE_SIZE);
89 
90 	return table_idx;
91 }
92