irq: multilevel: compile 3rd level IRQ APIs only when enabled
This revert the idea of 3fa7d78
from #78845.
The 3rd level IRQ APIs won't compile when
CONFIG_3RD_LEVEL_INTERRUPT_BITS=0.
Updated testcases accordingly.
Signed-off-by: Yong Cong Sin <ycsin@meta.com>
Signed-off-by: Yong Cong Sin <yongcong.sin@gmail.com>
This commit is contained in:
parent
d611e28103
commit
b2b2963e6a
4 changed files with 119 additions and 34 deletions
|
@ -32,15 +32,19 @@ typedef union _z_irq {
|
|||
uint32_t l1: CONFIG_1ST_LEVEL_INTERRUPT_BITS;
|
||||
/* Second level interrupt bits */
|
||||
uint32_t l2: CONFIG_2ND_LEVEL_INTERRUPT_BITS;
|
||||
#if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
|
||||
/* Third level interrupt bits */
|
||||
uint32_t l3: CONFIG_3RD_LEVEL_INTERRUPT_BITS;
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
} bits;
|
||||
|
||||
#if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
|
||||
/* Third level IRQ's interrupt controller */
|
||||
struct {
|
||||
/* IRQ of the third level interrupt aggregator */
|
||||
uint32_t irq: CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS;
|
||||
} l3_intc;
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
/* Second level IRQ's interrupt controller */
|
||||
struct {
|
||||
|
@ -61,16 +65,20 @@ static inline uint32_t _z_l2_irq(_z_irq_t irq)
|
|||
return irq.bits.l2 - 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
static inline uint32_t _z_l3_irq(_z_irq_t irq)
|
||||
{
|
||||
return irq.bits.l3 - 1;
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
static inline unsigned int _z_irq_get_level(_z_irq_t z_irq)
|
||||
{
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
if (z_irq.bits.l3 != 0) {
|
||||
return 3;
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
if (z_irq.bits.l2 != 0) {
|
||||
return 2;
|
||||
|
@ -142,7 +150,9 @@ static inline unsigned int irq_to_level_2(unsigned int irq)
|
|||
.bits = {
|
||||
.l1 = 0,
|
||||
.l2 = irq + 1,
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
.l3 = 0,
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -168,6 +178,7 @@ static inline unsigned int irq_parent_level_2(unsigned int irq)
|
|||
return _z_l1_irq(z_irq);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Return the 3rd level interrupt number
|
||||
*
|
||||
|
@ -241,6 +252,7 @@ static inline unsigned int irq_parent_level_3(unsigned int irq)
|
|||
|
||||
return _z_l2_irq(z_irq);
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
/**
|
||||
* @brief Return the interrupt number for a given level
|
||||
|
@ -256,11 +268,14 @@ static inline unsigned int irq_from_level(unsigned int irq, unsigned int level)
|
|||
return irq;
|
||||
} else if (level == 2) {
|
||||
return irq_from_level_2(irq);
|
||||
} else if (level == 3) {
|
||||
}
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
else if (level == 3) {
|
||||
return irq_from_level_3(irq);
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
/* level is higher than 3 */
|
||||
/* level is higher than what's supported */
|
||||
__ASSERT_NO_MSG(false);
|
||||
return irq;
|
||||
}
|
||||
|
@ -279,11 +294,14 @@ static inline unsigned int irq_to_level(unsigned int irq, unsigned int level)
|
|||
return irq;
|
||||
} else if (level == 2) {
|
||||
return irq_to_level_2(irq);
|
||||
} else if (level == 3) {
|
||||
}
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
else if (level == 3) {
|
||||
return irq_to_level_3(irq);
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
/* level is higher than 3 */
|
||||
/* level is higher than what's supported */
|
||||
__ASSERT_NO_MSG(false);
|
||||
return irq;
|
||||
}
|
||||
|
@ -303,11 +321,14 @@ static inline unsigned int irq_parent_level(unsigned int irq, unsigned int level
|
|||
return irq;
|
||||
} else if (level == 2) {
|
||||
return irq_parent_level_2(irq);
|
||||
} else if (level == 3) {
|
||||
}
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
else if (level == 3) {
|
||||
return irq_parent_level_3(irq);
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
/* level is higher than 3 */
|
||||
/* level is higher than what's supported */
|
||||
__ASSERT_NO_MSG(false);
|
||||
return irq;
|
||||
}
|
||||
|
@ -322,19 +343,24 @@ static inline unsigned int irq_parent_level(unsigned int irq, unsigned int level
|
|||
static inline unsigned int irq_get_intc_irq(unsigned int irq)
|
||||
{
|
||||
const unsigned int level = irq_get_level(irq);
|
||||
|
||||
__ASSERT_NO_MSG(level <= 3);
|
||||
_z_irq_t z_irq = {
|
||||
.irq = irq,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
__ASSERT_NO_MSG(level <= 3);
|
||||
if (level == 3) {
|
||||
return z_irq.l3_intc.irq;
|
||||
} else if (level == 2) {
|
||||
return z_irq.l2_intc.irq;
|
||||
} else {
|
||||
return irq;
|
||||
}
|
||||
#else
|
||||
__ASSERT_NO_MSG(level <= 2);
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
if (level == 2) {
|
||||
return z_irq.l2_intc.irq;
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -351,8 +377,12 @@ static inline unsigned int irq_increment(unsigned int irq, unsigned int val)
|
|||
.irq = irq,
|
||||
};
|
||||
|
||||
if (z_irq.bits.l3 != 0) {
|
||||
if (false) {
|
||||
/* so that it evaluates the next condition */
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
} else if (z_irq.bits.l3 != 0) {
|
||||
z_irq.bits.l3 += val;
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
} else if (z_irq.bits.l2 != 0) {
|
||||
z_irq.bits.l2 += val;
|
||||
} else {
|
||||
|
|
|
@ -14,17 +14,21 @@ static void test_multi_level_bit_masks_fn(uint32_t irq1, uint32_t irq2, uint32_t
|
|||
const uint32_t l3_shift = CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS;
|
||||
const uint32_t hwirq1 = irq1;
|
||||
const uint32_t hwirq2 = irq2 - 1;
|
||||
const uint32_t hwirq3 = irq3 - 1;
|
||||
const bool has_l3 = irq3 > 0;
|
||||
const bool has_l2 = irq2 > 0;
|
||||
const uint32_t level = has_l3 ? 3 : has_l2 ? 2 : 1;
|
||||
const uint32_t irqn_l1 = irq1;
|
||||
const uint32_t irqn_l2 = (irq2 << l2_shift) | irqn_l1;
|
||||
const uint32_t irqn = (irq3 << l3_shift) | irqn_l2;
|
||||
int level;
|
||||
|
||||
if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS) && (irq3 > 0)) {
|
||||
level = 3;
|
||||
} else if (IS_ENABLED(CONFIG_2ND_LEVEL_INTERRUPTS) && (irq2 > 0)) {
|
||||
level = 2;
|
||||
} else {
|
||||
level = 1;
|
||||
}
|
||||
zassert_equal(level, irq_get_level(irqn));
|
||||
|
||||
if (has_l2) {
|
||||
if (irq2 > 0) {
|
||||
zassert_equal(hwirq2, irq_from_level_2(irqn));
|
||||
zassert_equal(hwirq2, irq_from_level(irqn, 2));
|
||||
zassert_equal((hwirq2 + 1) << l2_shift, irq_to_level_2(hwirq2));
|
||||
|
@ -33,7 +37,10 @@ static void test_multi_level_bit_masks_fn(uint32_t irq1, uint32_t irq2, uint32_t
|
|||
zassert_equal(hwirq1, irq_parent_level(irqn, 2));
|
||||
}
|
||||
|
||||
if (has_l3) {
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
if (irq3 > 0) {
|
||||
const uint32_t hwirq3 = irq3 - 1;
|
||||
|
||||
zassert_equal(hwirq3, irq_from_level_3(irqn));
|
||||
zassert_equal(hwirq3, irq_from_level(irqn, 3));
|
||||
zassert_equal((hwirq3 + 1) << l3_shift, irq_to_level_3(hwirq3));
|
||||
|
@ -41,10 +48,15 @@ static void test_multi_level_bit_masks_fn(uint32_t irq1, uint32_t irq2, uint32_t
|
|||
zassert_equal(hwirq2, irq_parent_level_3(irqn));
|
||||
zassert_equal(hwirq2, irq_parent_level(irqn, 3));
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
if (has_l3) {
|
||||
if (false) {
|
||||
/* always skipped */
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
} else if (irq3 > 0) {
|
||||
zassert_equal(irqn_l2, irq_get_intc_irq(irqn));
|
||||
} else if (has_l2) {
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
} else if (irq2 > 0) {
|
||||
zassert_equal(irqn_l1, irq_get_intc_irq(irqn));
|
||||
} else {
|
||||
/* degenerate cases */
|
||||
|
|
|
@ -12,18 +12,15 @@
|
|||
ZTEST(interrupt_feature, test_multi_level_api)
|
||||
{
|
||||
/* Zephyr multilevel-encoded IRQ */
|
||||
const uint32_t irqn_l3 = DT_IRQN(DT_NODELABEL(test_l3_irq));
|
||||
const uint32_t irqn_l2 = DT_IRQN(DT_NODELABEL(test_l2_irq));
|
||||
const uint32_t irqn_l1 = DT_IRQN(DT_NODELABEL(test_l1_irq));
|
||||
/* Raw IRQ specified in the devicetree */
|
||||
const uint32_t raw_l3 = DT_IRQ(DT_NODELABEL(test_l3_irq), irq);
|
||||
const uint32_t raw_l2 = DT_IRQ(DT_NODELABEL(test_l2_irq), irq);
|
||||
const uint32_t raw_l1 = DT_IRQ(DT_NODELABEL(test_l1_irq), irq);
|
||||
|
||||
/**
|
||||
* - irq_get_level()
|
||||
*/
|
||||
zassert_equal(3, irq_get_level(irqn_l3));
|
||||
zassert_equal(2, irq_get_level(irqn_l2));
|
||||
zassert_equal(1, irq_get_level(irqn_l1));
|
||||
|
||||
|
@ -32,13 +29,59 @@ ZTEST(interrupt_feature, test_multi_level_api)
|
|||
* - irq_to_level_2()
|
||||
* - irq_parent_level_2()
|
||||
*/
|
||||
zassert_equal(irq_from_level_2(irqn_l3), raw_l2);
|
||||
zassert_equal(irq_from_level_2(irqn_l2), raw_l2);
|
||||
|
||||
zassert_equal(irq_to_level_2(raw_l2) & irqn_l2, irq_to_level_2(raw_l2));
|
||||
|
||||
zassert_equal(irq_parent_level_2(irqn_l2), raw_l1);
|
||||
|
||||
/**
|
||||
* - irq_from_level()
|
||||
* - irq_to_level()
|
||||
* - irq_parent_level()
|
||||
*/
|
||||
zassert_equal(irq_from_level(irqn_l2, 2), raw_l2);
|
||||
|
||||
zassert_equal(irq_to_level(raw_l2, 2) & irqn_l2, irq_to_level(raw_l2, 2));
|
||||
|
||||
zassert_equal(irq_parent_level(irqn_l2, 2), raw_l1);
|
||||
|
||||
/**
|
||||
* - irq_get_intc_irq()
|
||||
*/
|
||||
zassert_equal(irq_get_intc_irq(irqn_l2), irqn_l1);
|
||||
zassert_equal(irq_get_intc_irq(irqn_l1), irqn_l1);
|
||||
|
||||
const uint32_t irqn_l2_inc = DT_IRQN(DT_NODELABEL(test_l2_irq_inc));
|
||||
const uint32_t irqn_l1_inc = DT_IRQN(DT_NODELABEL(test_l1_irq_inc));
|
||||
|
||||
/**
|
||||
* - irq_increment()
|
||||
*/
|
||||
zassert_equal(irq_increment(irqn_l1, 1), irqn_l1_inc);
|
||||
zassert_equal(irq_increment(irqn_l2, 2), irqn_l2_inc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
ZTEST(interrupt_feature, test_multi_level_api_l3)
|
||||
{
|
||||
/* Zephyr multilevel-encoded IRQ */
|
||||
const uint32_t irqn_l2 = DT_IRQN(DT_NODELABEL(test_l2_irq));
|
||||
const uint32_t irqn_l3 = DT_IRQN(DT_NODELABEL(test_l3_irq));
|
||||
/* Raw IRQ specified in the devicetree */
|
||||
const uint32_t raw_l2 = DT_IRQ(DT_NODELABEL(test_l2_irq), irq);
|
||||
const uint32_t raw_l3 = DT_IRQ(DT_NODELABEL(test_l3_irq), irq);
|
||||
|
||||
/**
|
||||
* - irq_get_level()
|
||||
*/
|
||||
zassert_equal(3, irq_get_level(irqn_l3));
|
||||
|
||||
/**
|
||||
* - irq_from_level_2()
|
||||
*/
|
||||
zassert_equal(irq_from_level_2(irqn_l3), raw_l2);
|
||||
|
||||
/**
|
||||
* - irq_from_level_3()
|
||||
* - irq_to_level_3()
|
||||
|
@ -56,32 +99,24 @@ ZTEST(interrupt_feature, test_multi_level_api)
|
|||
* - irq_parent_level()
|
||||
*/
|
||||
zassert_equal(irq_from_level(irqn_l3, 2), raw_l2);
|
||||
zassert_equal(irq_from_level(irqn_l2, 2), raw_l2);
|
||||
zassert_equal(irq_from_level(irqn_l3, 3), raw_l3);
|
||||
|
||||
zassert_equal(irq_to_level(raw_l2, 2) & irqn_l2, irq_to_level(raw_l2, 2));
|
||||
zassert_equal(irq_to_level(raw_l3, 3) & irqn_l3, irq_to_level(raw_l3, 3));
|
||||
|
||||
zassert_equal(irq_parent_level(irqn_l2, 2), raw_l1);
|
||||
zassert_equal(irq_parent_level(irqn_l3, 3), raw_l2);
|
||||
|
||||
/**
|
||||
* - irq_get_intc_irq()
|
||||
*/
|
||||
zassert_equal(irq_get_intc_irq(irqn_l3), irqn_l2);
|
||||
zassert_equal(irq_get_intc_irq(irqn_l2), irqn_l1);
|
||||
zassert_equal(irq_get_intc_irq(irqn_l1), irqn_l1);
|
||||
|
||||
const uint32_t irqn_l3_inc = DT_IRQN(DT_NODELABEL(test_l3_irq_inc));
|
||||
const uint32_t irqn_l2_inc = DT_IRQN(DT_NODELABEL(test_l2_irq_inc));
|
||||
const uint32_t irqn_l1_inc = DT_IRQN(DT_NODELABEL(test_l1_irq_inc));
|
||||
|
||||
/**
|
||||
* - irq_increment()
|
||||
*/
|
||||
zassert_equal(irq_increment(irqn_l1, 1), irqn_l1_inc);
|
||||
zassert_equal(irq_increment(irqn_l2, 2), irqn_l2_inc);
|
||||
zassert_equal(irq_increment(irqn_l3, 3), irqn_l3_inc);
|
||||
}
|
||||
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
|
||||
|
||||
ZTEST_SUITE(gen_isr_table_multilevel, NULL, NULL, NULL, NULL, NULL);
|
||||
|
|
|
@ -93,3 +93,11 @@ tests:
|
|||
- EXTRA_DTC_OVERLAY_FILE="multilevel_irq.overlay"
|
||||
extra_configs:
|
||||
- CONFIG_TEST_MULTILEVEL_IRQ=y
|
||||
arch.interrupt.multilevel_l3:
|
||||
filter: CONFIG_MULTI_LEVEL_INTERRUPTS
|
||||
extra_args:
|
||||
- EXTRA_DTC_OVERLAY_FILE="multilevel_irq.overlay"
|
||||
extra_configs:
|
||||
- CONFIG_TEST_MULTILEVEL_IRQ=y
|
||||
- CONFIG_3RD_LEVEL_INTERRUPTS=y
|
||||
- CONFIG_3RD_LEVEL_INTERRUPT_BITS=11
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue