blob: db7bc1a688ce52afb0b4a36a3e1f131f387a111e [file] [log] [blame]
/*
* Copyright 2023 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "test_shared_irq.h"
struct shared_irq_fixture {
unsigned int irq1;
unsigned int irq2;
unsigned int irq1_table_idx;
unsigned int irq2_table_idx;
unsigned int irq_priority;
};
static struct shared_irq_fixture fixture;
static void reset_test_vector(void)
{
int i;
for (i = 0; i < TEST_VECTOR_SIZE; i++) {
test_vector[i] = 0;
}
}
static void dynamic_shared_irq_suite_after(void *data)
{
ARG_UNUSED(data);
/* note: no need to check the state of the SW ISR tables after
* all these disconnect operations. If there's something wrong
* it should be detected by dynamic_shared_irq_suite_before().
*/
arch_irq_disconnect_dynamic(fixture.irq1, fixture.irq_priority,
test_isr_0, 0, 0);
arch_irq_disconnect_dynamic(fixture.irq1, fixture.irq_priority,
test_isr_1, (void *)1, 0);
arch_irq_disconnect_dynamic(fixture.irq2, fixture.irq_priority,
test_isr_2, (void *)2, 0);
}
static void dummy_isr(const void *data)
{
ARG_UNUSED(data);
test_vector[0] = TEST_DUMMY_ISR_VAL;
}
static unsigned int get_irq_slot(unsigned int start)
{
unsigned int i, table_idx;
for (i = start; i <= CONFIG_GEN_IRQ_START_VECTOR + CONFIG_NUM_IRQS - 1; i++) {
table_idx = i - CONFIG_GEN_IRQ_START_VECTOR;
if (_sw_isr_table[table_idx].isr == &z_irq_spurious) {
test_vector[0] = 0;
/* check to see if we can trigger this IRQ */
arch_irq_connect_dynamic(i, IRQ_PRIORITY, dummy_isr,
NULL, 0);
irq_enable(i);
trigger_irq(i);
/* wait a bit */
k_busy_wait(100);
if (test_vector[0] == TEST_DUMMY_ISR_VAL) {
/* found a valid INTID */
irq_disable(i);
arch_irq_disconnect_dynamic(i, IRQ_PRIORITY,
dummy_isr, NULL, 0);
return i;
}
}
}
return TEST_INVALID_IRQ;
}
static void *dynamic_shared_irq_suite_setup(void)
{
fixture.irq1 = get_irq_slot(CONFIG_GEN_IRQ_START_VECTOR);
zassert_true(fixture.irq1 != TEST_INVALID_IRQ,
"no suitable value found for irq1");
fixture.irq2 = get_irq_slot(fixture.irq1 + 1);
zassert_true(fixture.irq2 != TEST_INVALID_IRQ,
"no suitable value found for irq2");
fixture.irq_priority = IRQ_PRIORITY;
fixture.irq1_table_idx = fixture.irq1 - CONFIG_GEN_IRQ_START_VECTOR;
fixture.irq2_table_idx = fixture.irq2 - CONFIG_GEN_IRQ_START_VECTOR;
return NULL;
}
static void dynamic_shared_irq_suite_before(void *data)
{
ARG_UNUSED(data);
arch_irq_connect_dynamic(fixture.irq1, fixture.irq_priority,
test_isr_0, 0, 0);
zassert_true(_sw_isr_table[fixture.irq1_table_idx].isr == test_isr_0,
"wrong _sw_isr_table ISR at irq1");
zassert_true(!_sw_isr_table[fixture.irq1_table_idx].arg,
"wrong _sw_isr_table argument at irq1");
zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx].client_num,
"wrong client number at irq1");
arch_irq_connect_dynamic(fixture.irq1, fixture.irq_priority,
test_isr_1, (void *)1, 0);
zassert_true(_sw_isr_table[fixture.irq1_table_idx].isr == z_shared_isr,
"wrong _sw_isr_table ISR at irq1");
zassert_true(_sw_isr_table[fixture.irq1_table_idx].arg ==
&z_shared_sw_isr_table[fixture.irq1_table_idx],
"wrong _sw_isr_table argument at irq1");
zassert_true(z_shared_sw_isr_table[fixture.irq1_table_idx].client_num == 2,
"wrong client number at irq1");
zassert_true(client_exists_at_index(test_isr_0, 0, fixture.irq1_table_idx, 0),
"unexpected client data for irq1, index 0");
zassert_true(client_exists_at_index(test_isr_1, (void *)1, fixture.irq1_table_idx, 1),
"unexpected client data for irq1, index 1");
arch_irq_connect_dynamic(fixture.irq2, fixture.irq_priority,
test_isr_2, (void *)2, 0);
zassert_true(_sw_isr_table[fixture.irq2_table_idx].isr == test_isr_2,
"wrong _sw_isr_table ISR at irq2");
zassert_true(_sw_isr_table[fixture.irq2_table_idx].arg == (void *)2,
"wrong _sw_isr_table argument at irq2");
zassert_true(!z_shared_sw_isr_table[fixture.irq2_table_idx].client_num,
"wrong client number at irq2");
reset_test_vector();
}
/**
* @brief Test writing to a vector with a shared interrupt
*
* @ingroup kernel_interrupt_tests
*
* @details This tests if interrupts are dynamically shared successfully
* (i.e: multiple ISR/arg pairs are called whenever the interrupt
* they were registered for is triggered).
*/
ZTEST(shared_irq_feature, test_dynamic_shared_irq_write)
{
int i;
irq_enable(fixture.irq1);
irq_enable(fixture.irq2);
trigger_irq(fixture.irq1);
trigger_irq(fixture.irq2);
/* wait 5ms before checking the results */
k_busy_wait(5000);
for (i = 0; i < TEST_VECTOR_SIZE; i++) {
zassert_true(test_vector[i] == result_vector[i],
"wrong test_vector value at %d: 0x%x vs 0x%x",
i, test_vector[i], result_vector[i]);
}
irq_disable(fixture.irq1);
irq_disable(fixture.irq2);
}
/**
* @brief Test writing to a vector after an ISR/arg disconnect.
*
* @ingroup kernel_interrupt_tests
*
* @details This tests if ISR/arg pairs are disconnected successfully
* and the interrupts are "unshared" whenever a single ISR/arg pair is
* left.
*/
ZTEST(shared_irq_feature, test_dynamic_shared_irq_disconnect_write)
{
int i;
/* remove test_isr_0/NULL pair. After this statement we expect
* irq1 to be unshared.
*/
arch_irq_disconnect_dynamic(fixture.irq1, fixture.irq_priority,
test_isr_0, 0, 0);
zassert_true(_sw_isr_table[fixture.irq1_table_idx].isr == test_isr_1,
"wrong _sw_isr_table ISR at irq1");
zassert_true(_sw_isr_table[fixture.irq1_table_idx].arg == (void *)1,
"wrong _sw_isr_table arg at irq1");
zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx].client_num,
"wrong client number at irq1");
irq_enable(fixture.irq1);
trigger_irq(fixture.irq1);
/* wait 5ms before checking the results */
k_busy_wait(5000);
for (i = 0; i < TEST_VECTOR_SIZE; i++) {
if (i == 1) {
zassert_true(test_vector[i] == result_vector[i],
"wrong test_vector at %d: 0x%x vs 0x%x",
i, test_vector[i], result_vector[i]);
continue;
}
zassert_true(!test_vector[i],
"wrong test_vector value at %d: 0x%x vs 0x%x",
i, test_vector[i], result_vector[i]);
}
irq_disable(fixture.irq1);
}
ZTEST_SUITE(shared_irq_feature, NULL,
dynamic_shared_irq_suite_setup,
dynamic_shared_irq_suite_before,
dynamic_shared_irq_suite_after,
NULL);