| /* |
| * Copyright (c) 2018 Intel Corporation. |
| * Copyright (c) 2023 Meta. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/device.h> |
| #include <zephyr/irq.h> |
| #include <zephyr/sw_isr_table.h> |
| #include <zephyr/sys/__assert.h> |
| #include <zephyr/sys/util.h> |
| |
| BUILD_ASSERT(CONFIG_MAX_IRQ_PER_AGGREGATOR < BIT(CONFIG_2ND_LEVEL_INTERRUPT_BITS), |
| "L2 bits not enough to cover the number of L2 IRQs"); |
| #ifdef CONFIG_3RD_LEVEL_INTERRUPTS |
| BUILD_ASSERT(CONFIG_MAX_IRQ_PER_AGGREGATOR < BIT(CONFIG_3RD_LEVEL_INTERRUPT_BITS), |
| "L3 bits not enough to cover the number of L3 IRQs"); |
| #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ |
| |
| /** |
| * @brief Get the aggregator that's responsible for the given irq |
| * |
| * @param irq IRQ number to query |
| * |
| * @return Aggregator entry, NULL if irq is level 1 or not found. |
| */ |
| static const struct _irq_parent_entry *get_intc_entry_for_irq(unsigned int irq) |
| { |
| const unsigned int level = irq_get_level(irq); |
| |
| /* 1st level aggregator is not registered */ |
| if (level == 1) { |
| return NULL; |
| } |
| |
| const unsigned int intc_irq = irq_get_intc_irq(irq); |
| |
| /* Find an aggregator entry that matches the level & intc_irq */ |
| STRUCT_SECTION_FOREACH_ALTERNATE(intc_table, _irq_parent_entry, intc) { |
| if ((intc->level == level) && (intc->irq == intc_irq)) { |
| return intc; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const struct device *z_get_sw_isr_device_from_irq(unsigned int irq) |
| { |
| const struct _irq_parent_entry *intc = get_intc_entry_for_irq(irq); |
| |
| __ASSERT(intc != NULL, "can't find an aggregator to handle irq(%X)", irq); |
| |
| return intc != NULL ? intc->dev : NULL; |
| } |
| |
| unsigned int z_get_sw_isr_irq_from_device(const struct device *dev) |
| { |
| /* Get the IRQN for the aggregator */ |
| STRUCT_SECTION_FOREACH_ALTERNATE(intc_table, _irq_parent_entry, intc) { |
| if (intc->dev == dev) { |
| return intc->irq; |
| } |
| } |
| |
| __ASSERT(false, "dev(%p) not found", dev); |
| |
| return 0; |
| } |
| |
| unsigned int z_get_sw_isr_table_idx(unsigned int irq) |
| { |
| unsigned int table_idx, local_irq; |
| const struct _irq_parent_entry *intc = get_intc_entry_for_irq(irq); |
| const unsigned int level = irq_get_level(irq); |
| |
| if (intc != NULL) { |
| local_irq = irq_from_level(irq, level); |
| __ASSERT_NO_MSG(local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR); |
| |
| table_idx = intc->offset + local_irq; |
| } else { |
| /* irq level must be 1 if no intc entry */ |
| __ASSERT(level == 1, "can't find an aggregator to handle irq(%X)", irq); |
| table_idx = irq; |
| } |
| |
| table_idx -= CONFIG_GEN_IRQ_START_VECTOR; |
| |
| __ASSERT(table_idx < IRQ_TABLE_SIZE, "table_idx(%d) < IRQ_TABLE_SIZE(%d)", table_idx, |
| IRQ_TABLE_SIZE); |
| |
| return table_idx; |
| } |