You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
microwatt/tests/xics/xics.c

333 lines
5.5 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "console.h"
#include "xics.h"
#undef DEBUG
//#define DEBUG 1
void delay(void)
{
static volatile int i;
for (i = 0; i < 16; ++i)
__asm__ volatile("" : : : "memory");
}
void print_number(unsigned int i) // only for i = 0-999
{
unsigned int j, k, m;
bool zeros = false;
k = 1000000000;
for (m = 0; m < 10 ; m++) {
j = i/k;
if (m == 9) zeros = true;
if (zeros || (j != 0)) {
putchar(48 + j);
zeros = true;
}
i = i % k;
k = k / 10;
}
}
#ifdef DEBUG
#define DEBUG_STR "\nDEBUG: "
void debug_print(int i)
{
puts(DEBUG_STR);
print_number(i);
puts("\n");
}
#define debug_puts(a) puts(a)
#else
#define debug_puts(a)
#define debug_print(i)
#endif
#define ASSERT_FAIL "() ASSERT_FAILURE!\n "
#define assert(cond) \
if (!(cond)) { \
puts(__FILE__); \
putchar(':'); \
print_number(__LINE__); \
putchar(':'); \
puts(__FUNCTION__);\
puts(ASSERT_FAIL); \
__asm__ ("attn"); \
}
volatile uint64_t isrs_run;
#define ISR_IPI 0x0000000000000001
#define ISR_UART 0x0000000000000002
#define ISR_SPURIOUS 0x0000000000000004
#define IPI "IPI\n"
void ipi_isr(void) {
debug_puts(IPI);
isrs_run |= ISR_IPI;
icp_write8(XICS_MFRR, 0xff);
}
#define UART "UART\n"
void uart_isr(void) {
debug_puts(UART);
potato_uart_irq_dis(); // disable interrupt to ack it
isrs_run |= ISR_UART;
}
// The hardware doesn't support this but it's part of XICS so add it.
#define SPURIOUS "SPURIOUS\n"
void spurious_isr(void) {
debug_puts(SPURIOUS);
isrs_run |= ISR_SPURIOUS;
}
struct isr_op {
void (*func)(void);
int source_id;
};
struct isr_op isr_table[] = {
{ .func = ipi_isr, .source_id = 2 },
{ .func = uart_isr, .source_id = 16 },
{ .func = spurious_isr, .source_id = 0 },
{ .func = NULL, .source_id = 0 }
};
bool ipi_running;
#define ISR "ISR XISR="
#define PRIO " PRIO="
#define CPPR " CPPR="
void isr(void)
{
struct isr_op *op;
uint32_t xirr;
assert(!ipi_running); // check we aren't reentrant
ipi_running = true;
xirr = icp_read32(XICS_XIRR); // read hardware irq source
#ifdef DEBUG
puts(ISR);
print_number(xirr & 0xff);
puts(PRIO);
print_number(xirr >> 24);
puts(CPPR);
print_number(icp_read8(XICS_XIRR_POLL));
puts("\n");
#endif
op = isr_table;
while (1) {
assert(op->func); // didn't find isr
if (op->source_id == (xirr & 0x00ffffff)) {
op->func();
break;
}
op++;
}
icp_write32(XICS_XIRR, xirr); // EOI
ipi_running = false;
}
/*****************************************/
int xics_test_0(void)
{
uint32_t v0, v1;
v0 = ics_read_xive(0);
v1 = ics_read_xive(1);
#ifdef DEBUG
puts("\n");
puts("xive(0) bfr: ");
print_number(v0);
puts("\n");
puts("xive(1) bfr: ");
print_number(v1);
puts("\n");
#endif
assert(v0 = 0xff);
assert(v1 = 0xff);
ics_write_xive(0xa, 0);
ics_write_xive(0x5, 1);
v0 = ics_read_xive(0);
v1 = ics_read_xive(1);
#ifdef DEBUG
puts("\n");
puts("xive(0) aft: ");
print_number(v0);
puts("\n");
puts("xive(1) aft: ");
print_number(v1);
puts("\n");
#endif
assert(v0 = 0xa);
assert(v1 = 0x5);
ics_write_xive(0xff, 0);
ics_write_xive(0xff, 1);
v0 = ics_read_xive(0);
v1 = ics_read_xive(1);
assert(v0 = 0xff);
assert(v1 = 0xff);
return 0;
}
int xics_test_1(void)
{
// setup
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
// trigger two interrupts
potato_uart_irq_en(); // cause serial interrupt
ics_write_xive(0x6, 0); // set source to prio 6
icp_write8(XICS_MFRR, 0x04); // cause ipi interrupt at prio 5
// still masked, so shouldn't happen yet
delay();
assert(isrs_run == 0);
// unmask IPI only
icp_write8(XICS_XIRR, 0x6);
delay();
assert(isrs_run == ISR_IPI);
// unmask UART
icp_write8(XICS_XIRR, 0x7);
delay();
assert(isrs_run == (ISR_IPI | ISR_UART));
// cleanup
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
potato_uart_irq_dis();
ics_write_xive(0, 0xff);
isrs_run = 0;
return 0;
}
int xics_test_2(void)
{
// setup
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
icp_write8(XICS_XIRR, 0xff); // allow all interrupts
// should be none pending
delay();
assert(isrs_run == 0);
// trigger both
potato_uart_irq_en(); // cause 0x500 interrupt
icp_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
delay();
assert(isrs_run == (ISR_IPI | ISR_UART));
// cleanup
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
potato_uart_irq_dis();
isrs_run = 0;
return 0;
}
void mtmsrd(uint64_t val)
{
__asm__ volatile("mtmsrd %0" : : "r" (val));
}
int xics_test_3(void)
{
// setup
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
// trigger interrupts with MSR[EE]=0 and show they are not run
mtmsrd(0x9000000000000003); // EE off
icp_write8(XICS_XIRR, 0xff); // allow all interrupts
// trigger an IPI
icp_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
delay();
assert(isrs_run == 0);
mtmsrd(0x9000000000008003); // EE on
delay();
assert(isrs_run == ISR_IPI);
// cleanup
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
return 0;
}
#define TEST "Test "
#define PASS "PASS\n"
#define FAIL "FAIL\n"
int (*tests[])(void) = {
xics_test_0,
xics_test_1,
xics_test_2,
xics_test_3,
NULL
};
int main(void)
{
int fail = 0;
int i = 0;
int (*t)(void);
potato_uart_init();
ipi_running = false;
/* run the tests */
while (1) {
t = tests[i];
if (!t)
break;
puts(TEST);
print_number(i);
putchar(':');
if (t() != 0) {
fail = 1;
puts(FAIL);
} else
puts(PASS);
i++;
}
return fail;
}