Commit b2b2963e authored by Yong Cong Sin's avatar Yong Cong Sin Committed by Fabio Baltieri
Browse files

irq: multilevel: compile 3rd level IRQ APIs only when enabled

This revert the idea of 3fa7d783 from #78845.

The 3rd level IRQ APIs won't compile when
CONFIG_3RD_LEVEL_INTERRUPT_BITS=0.

Updated testcases accordingly.

Signed-off-by: default avatarYong Cong Sin <ycsin@meta.com>
Signed-off-by: default avatarYong Cong Sin <yongcong.sin@gmail.com>
parent d611e281
Loading
Loading
Loading
Loading
+42 −12
Changes for include/zephyr/irq_multilevel.h: 42 added lines, 12 removed lines.
Original line number Diff line number Diff line
@@ -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) {
	}
#else
	__ASSERT_NO_MSG(level <= 2);
#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */

	if (level == 2) {
		return z_irq.l2_intc.irq;
	} else {
		return 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 {
+20 −8
Changes for tests/kernel/gen_isr_table/src/multilevel_irq.c: 20 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -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 */
+48 −13
Changes for tests/kernel/interrupt/src/multilevel_irq.c: 48 added lines, 13 removed lines.
Original line number Diff line number Diff line
@@ -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);
+8 −0
Changes for tests/kernel/interrupt/testcase.yaml: 8 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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