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:
parent
4b2f5c7de2
commit
8bfdff3cb1
3 changed files with 62 additions and 0 deletions
|
@ -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 */
|
#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,5 +40,31 @@
|
||||||
interrupt-parent = <&test_l2_irq>;
|
interrupt-parent = <&test_l2_irq>;
|
||||||
interrupt-names = "test";
|
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";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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_l3), irqn_l2);
|
||||||
zassert_equal(irq_get_intc_irq(irqn_l2), irqn_l1);
|
zassert_equal(irq_get_intc_irq(irqn_l2), irqn_l1);
|
||||||
zassert_equal(irq_get_intc_irq(irqn_l1), 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);
|
ZTEST_SUITE(gen_isr_table_multilevel, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue