You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.5 KiB
95 lines
2.5 KiB
/* |
|
* 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; |
|
}
|
|
|