blob: 44d59f77aac5cc6fc7439588bc453ad48d8b6638 [file] [log] [blame]
/*
* Copyright (c) 2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/interrupt_util.h>
#include <zephyr/irq.h>
/*
* 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]);
}