irq: multilevel: add API to increment a multilevel IRQ

Unlike a normal IRQ, a multilevel IRQ can't be incremented by
simply `irq++`, as that would always increment the L1 of a IRQ,
regardless of its level. A function that understands the level
for which the IRQ operates in is required.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
Signed-off-by: Yong Cong Sin <yongcong.sin@gmail.com>
This commit is contained in:
Yong Cong Sin 2024-09-24 15:21:42 +08:00 committed by Alberto Escolar
commit 8bfdff3cb1
3 changed files with 62 additions and 0 deletions

View file

@ -333,6 +333,31 @@ static inline unsigned int irq_get_intc_irq(unsigned int irq)
}
}
/**
* @brief Increments the multilevel-encoded @a irq by @a val
*
* @param irq IRQ number in its zephyr format
* @param val Amount to increment
*
* @return @a irq incremented by @a val
*/
static inline unsigned int irq_increment(unsigned int irq, unsigned int val)
{
_z_irq_t z_irq = {
.irq = irq,
};
if (z_irq.bits.l3 != 0) {
z_irq.bits.l3 += val;
} else if (z_irq.bits.l2 != 0) {
z_irq.bits.l2 += val;
} else {
z_irq.bits.l1 += val;
}
return z_irq.irq;
}
#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */
#ifdef __cplusplus
}

View file

@ -40,5 +40,31 @@
interrupt-parent = <&test_l2_irq>;
interrupt-names = "test";
};
test_l1_irq_inc: interrupt-controller@bbbbdccc {
compatible = "vnd,intc";
reg = <0xbbbbdccc 0x10>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <12 0>; /* +1 */
interrupt-parent = <&test_cpu_intc>;
};
test_l2_irq_inc: interrupt-controller@bbbbdcdc {
compatible = "vnd,intc";
reg = <0xbbbbdcdc 0x10>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <14 0>; /* +2 */
interrupt-parent = <&test_l1_irq>;
};
test_l3_irq_inc: interrupt-holder-inc {
compatible = "vnd,interrupt-holder";
status = "okay";
interrupts = <16 3>; /* +3 */
interrupt-parent = <&test_l2_irq>;
interrupt-names = "test";
};
};
};

View file

@ -71,6 +71,17 @@ ZTEST(interrupt_feature, test_multi_level_api)
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);
}
ZTEST_SUITE(gen_isr_table_multilevel, NULL, NULL, NULL, NULL, NULL);