blob: 7bc93df34df76bcf1c048c7995c45dc5cc04f4b8 [file] [log] [blame]
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <irq.h>
#include <tc_util.h>
#include <sw_isr_table.h>
extern uint32_t _irq_vector_table[];
#if defined(_ARCH_IRQ_DIRECT_CONNECT) && defined(CONFIG_GEN_IRQ_VECTOR_TABLE)
#define HAS_DIRECT_IRQS
#endif
#define ISR1_OFFSET 0
#define ISR2_OFFSET 1
#if defined(CONFIG_RISCV32) && !defined(CONFIG_SOC_RISCV32_PULPINO)
#define ISR3_OFFSET 1
#define ISR4_OFFSET 5
#define IRQ_LINE(offset) offset
#define TABLE_INDEX(offset) offset
#define TRIG_CHECK_SIZE 6
#else
#define ISR3_OFFSET 2
#define ISR4_OFFSET 3
#define IRQ_LINE(offset) (CONFIG_NUM_IRQS - ((offset) + 1))
#define TABLE_INDEX(offset) (IRQ_TABLE_SIZE - ((offset) + 1))
#define TRIG_CHECK_SIZE 4
#endif
#define ISR3_ARG 0xb01dface
#define ISR4_ARG 0xca55e77e
static volatile int trigger_check[TRIG_CHECK_SIZE];
#if defined(CONFIG_ARM)
#include <arch/arm/cortex_m/cmsis.h>
void trigger_irq(int irq)
{
#if defined(CONFIG_SOC_TI_LM3S6965_QEMU)
/* QEMU does not simulate the STIR register: this is a workaround */
NVIC_SetPendingIRQ(irq);
#else
NVIC->STIR = irq;
#endif
}
#elif defined(CONFIG_RISCV32) && !defined(CONFIG_SOC_RISCV32_PULPINO)
void trigger_irq(int irq)
{
uint32_t mip;
__asm__ volatile ("csrrs %0, mip, %1\n"
: "=r" (mip)
: "r" (1 << irq));
}
#else
/* So far, Nios II does not support this */
#define NO_TRIGGER_FROM_SW
#endif
#ifdef HAS_DIRECT_IRQS
ISR_DIRECT_DECLARE(isr1)
{
printk("isr1 ran\n");
trigger_check[ISR1_OFFSET]++;
return 0;
}
ISR_DIRECT_DECLARE(isr2)
{
printk("isr2 ran\n");
trigger_check[ISR2_OFFSET]++;
return 1;
}
#endif
void isr3(void *param)
{
printk("isr3 ran with parameter %p\n", param);
trigger_check[ISR3_OFFSET]++;
}
void isr4(void *param)
{
printk("isr4 ran with parameter %p\n", param);
trigger_check[ISR4_OFFSET]++;
}
int test_irq(int offset)
{
#ifndef NO_TRIGGER_FROM_SW
TC_PRINT("triggering irq %d\n", IRQ_LINE(offset));
trigger_irq(IRQ_LINE(offset));
if (trigger_check[offset] != 1) {
TC_PRINT("interrupt %d didn't run once, ran %d times\n",
IRQ_LINE(offset),
trigger_check[offset]);
return -1;
}
#else
/* This arch doesn't support triggering interrupts from software */
ARG_UNUSED(offset);
#endif
return 0;
}
#ifdef HAS_DIRECT_IRQS
static int check_vector(void *isr, int offset)
{
TC_PRINT("Checking _irq_vector_table entry %d for irq %d\n",
TABLE_INDEX(offset), IRQ_LINE(offset));
if (_irq_vector_table[TABLE_INDEX(offset)] != (uint32_t)isr) {
TC_PRINT("bad entry %d in vector table\n", TABLE_INDEX(offset));
return -1;
}
if (test_irq(offset)) {
return -1;
}
return 0;
}
#endif
#ifdef CONFIG_GEN_SW_ISR_TABLE
static int check_sw_isr(void *isr, uint32_t arg, int offset)
{
struct _isr_table_entry *e = &_sw_isr_table[TABLE_INDEX(offset)];
#ifdef CONFIG_GEN_IRQ_VECTOR_TABLE
void *v = (void *)_irq_vector_table[TABLE_INDEX(offset)];
#endif
TC_PRINT("Checking _sw_isr_table entry %d for irq %d\n",
TABLE_INDEX(offset), IRQ_LINE(offset));
if (e->arg != (void *)arg) {
TC_PRINT("bad argument in SW isr table\n");
TC_PRINT("expected %p got %p\n", (void *)arg, e->arg);
return -1;
}
if (e->isr != isr) {
TC_PRINT("Bad ISR in SW isr table\n");
TC_PRINT("expected %p got %p\n", (void *)isr, e->isr);
return -1;
}
#ifdef CONFIG_GEN_IRQ_VECTOR_TABLE
if (v != _isr_wrapper) {
TC_PRINT("Vector does not point to _isr_wrapper\n");
TC_PRINT("expected %p got %p\n", _isr_wrapper, v);
return -1;
}
#endif
if (test_irq(offset)) {
return -1;
}
return 0;
}
#endif
void main(void)
{
int rv;
TC_START("Test gen_isr_tables");
TC_PRINT("IRQ configuration (total lines %d):\n", CONFIG_NUM_IRQS);
#ifdef HAS_DIRECT_IRQS
IRQ_DIRECT_CONNECT(IRQ_LINE(ISR1_OFFSET), 0, isr1, 0);
IRQ_DIRECT_CONNECT(IRQ_LINE(ISR2_OFFSET), 0, isr2, 0);
irq_enable(IRQ_LINE(ISR1_OFFSET));
irq_enable(IRQ_LINE(ISR2_OFFSET));
TC_PRINT("isr1 isr=%p irq=%d\n", isr1, IRQ_LINE(ISR1_OFFSET));
TC_PRINT("isr2 isr=%p irq=%d\n", isr2, IRQ_LINE(ISR2_OFFSET));
if (check_vector(isr1, ISR1_OFFSET)) {
rv = TC_FAIL;
goto done;
}
if (check_vector(isr2, ISR2_OFFSET)) {
rv = TC_FAIL;
goto done;
}
#endif
#ifdef CONFIG_GEN_SW_ISR_TABLE
IRQ_CONNECT(IRQ_LINE(ISR3_OFFSET), 1, isr3, ISR3_ARG, 0);
IRQ_CONNECT(IRQ_LINE(ISR4_OFFSET), 2, isr4, ISR4_ARG, 0);
irq_enable(IRQ_LINE(ISR3_OFFSET));
irq_enable(IRQ_LINE(ISR4_OFFSET));
TC_PRINT("isr3 isr=%p irq=%d param=%p\n", isr3, IRQ_LINE(ISR3_OFFSET),
(void *)ISR3_ARG);
TC_PRINT("isr4 isr=%p irq=%d param=%p\n", isr4, IRQ_LINE(ISR4_OFFSET),
(void *)ISR4_ARG);
TC_PRINT("_sw_isr_table at location %p\n", _sw_isr_table);
if (check_sw_isr(isr3, ISR3_ARG, ISR3_OFFSET)) {
rv = TC_FAIL;
goto done;
}
if (check_sw_isr(isr4, ISR4_ARG, ISR4_OFFSET)) {
rv = TC_FAIL;
goto done;
}
#endif
rv = TC_PASS;
done:
TC_END_RESULT(rv);
TC_END_REPORT(rv);
}