236 lines
6.7 KiB
C
236 lines
6.7 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|
|
#if defined(CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET)
|
|
#define TABLE_OFFSET CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET
|
|
#else
|
|
#define TABLE_OFFSET 0
|
|
#endif
|
|
|
|
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 + TABLE_OFFSET].isr == test_isr_0,
|
|
"wrong _sw_isr_table ISR at irq1");
|
|
zassert_true(!_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].arg,
|
|
"wrong _sw_isr_table argument at irq1");
|
|
zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].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 + TABLE_OFFSET].isr == z_shared_isr,
|
|
"wrong _sw_isr_table ISR at irq1");
|
|
zassert_true(_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].arg ==
|
|
&z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET],
|
|
"wrong _sw_isr_table argument at irq1");
|
|
zassert_true(z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].client_num == 2,
|
|
"wrong client number at irq1");
|
|
|
|
zassert_true(client_exists_at_index(test_isr_0, 0, fixture.irq1_table_idx + TABLE_OFFSET,
|
|
0),
|
|
"unexpected client data for irq1, index 0");
|
|
zassert_true(client_exists_at_index(test_isr_1, (void *)1,
|
|
fixture.irq1_table_idx + TABLE_OFFSET, 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 + TABLE_OFFSET].isr == test_isr_2,
|
|
"wrong _sw_isr_table ISR at irq2");
|
|
zassert_true(_sw_isr_table[fixture.irq2_table_idx + TABLE_OFFSET].arg == (void *)2,
|
|
"wrong _sw_isr_table argument at irq2");
|
|
zassert_true(!z_shared_sw_isr_table[fixture.irq2_table_idx + TABLE_OFFSET].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 + TABLE_OFFSET].isr == test_isr_1,
|
|
"wrong _sw_isr_table ISR at irq1");
|
|
zassert_true(_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].arg == (void *)1,
|
|
"wrong _sw_isr_table arg at irq1");
|
|
zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].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);
|