/* * Copyright (c) 2021 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include /* * Other arch has already been tested in testcase of gen_isr_table, * so we only test x86 series here. */ #define TEST_IRQ_LINE_1 27 #define TEST_IRQ_LINE_2 28 #define TEST_IRQ_PRIO 2 volatile uint32_t reg_int_executed[2]; void isr_comm(const void *param) { int choice = POINTER_TO_INT(param); switch (choice) { case TEST_IRQ_LINE_1: reg_int_executed[0]++; break; case TEST_IRQ_LINE_2: reg_int_executed[1]++; break; default: break; } } /** * @brief Test regular interrupt * * @details Validate regular interrupt works as expected. * - Register two regular interrupt at build time. * - Trigger interrupt and check if isr handler has executed or not. * - Also check irq_enable and irq_disable works. * * @ingroup kernel_interrupt_tests * * @see IRQ_CONNECT(), irq_enable(), irq_disable(), * irq_unlock(), */ ZTEST(interrupt_feature, test_isr_regular) { int trig_vec1, trig_vec2; IRQ_CONNECT(TEST_IRQ_LINE_1, TEST_IRQ_PRIO, isr_comm, (void *)TEST_IRQ_LINE_1, 0); IRQ_CONNECT(TEST_IRQ_LINE_2, TEST_IRQ_PRIO, isr_comm, (void *)TEST_IRQ_LINE_2, 0); trig_vec1 = Z_IRQ_TO_INTERRUPT_VECTOR(TEST_IRQ_LINE_1); trig_vec2 = Z_IRQ_TO_INTERRUPT_VECTOR(TEST_IRQ_LINE_2); TC_PRINT("irq(%d)=vector(%d)\n", TEST_IRQ_LINE_1, trig_vec1); TC_PRINT("irq(%d)=vector(%d)\n", TEST_IRQ_LINE_2, trig_vec2); irq_enable(TEST_IRQ_LINE_1); irq_enable(TEST_IRQ_LINE_2); trigger_irq(trig_vec1); zassert_true(reg_int_executed[0] == 1 && reg_int_executed[1] == 0, "ISR1 should execute"); trigger_irq(trig_vec2); zassert_true(reg_int_executed[0] == 1 && reg_int_executed[1] == 1, "Both ISR should execute"); unsigned int key = irq_lock(); /* trigger under irq locked */ trigger_irq(trig_vec1); trigger_irq(trig_vec2); zassert_true(reg_int_executed[0] == 1 && reg_int_executed[1] == 1, "Both ISR should not execute again(%d)(%d)", reg_int_executed[0], reg_int_executed[1]); irq_unlock(key); #ifdef CONFIG_BOARD_QEMU_X86 /* QEMU seems to have an issue in that interrupts seem to post on * the instruction after the 'sti' that is part of irq_unlock(). This * can cause an issue if the instruction after the 'sti' ends up looking * at the state that the ISR is suppose to update. This has been shown * to happen when building this test for LLVM. * * Adding a nop instruction allows QEMU to post the ISR before any state * gets examined as a workaround. * * See GitHub issue zephyrproject-rtos/sdk-ng#629 for the qemu bug. */ arch_nop(); #endif /* interrupt serve after irq unlocked */ zassert_true(reg_int_executed[0] == 2 && reg_int_executed[1] == 2, "Both ISR should execute again(%d)(%d)", reg_int_executed[0], reg_int_executed[1]); /* trigger after irq unlocked */ trigger_irq(trig_vec1); trigger_irq(trig_vec2); zassert_true(reg_int_executed[0] == 3 && reg_int_executed[1] == 3, "Both ISR should execute again(%d)(%d)", reg_int_executed[0], reg_int_executed[1]); }