#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ka43.c,v 1.36 2017/05/22 16:46:15 ragge Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <machine/sid.h>
#include <machine/nexus.h>
#include <machine/vsbus.h>
#include <machine/ka43.h>
#include <machine/clock.h>
static void ka43_conf(void);
static void ka43_steal_pages(void);
static int ka43_mchk(void *);
static void ka43_memerr(void);
#if 0
static void ka43_clear_errors(void);
#endif
static int ka43_cache_init(void);
static int ka43_cache_reset(void);
static int ka43_cache_enable(void);
static int ka43_cache_disable(void);
static int ka43_cache_invalidate(void);
static void ka43_halt(void);
static void ka43_reboot(int);
static void ka43_clrf(void);
static const char * const ka43_devs[] = { "cpu", "vsbus", NULL };
const struct cpu_dep ka43_calls = {
.cpu_steal_pages = ka43_steal_pages,
.cpu_mchk = ka43_mchk,
.cpu_memerr = ka43_memerr,
.cpu_conf = ka43_conf,
.cpu_gettime = chip_gettime,
.cpu_settime = chip_settime,
.cpu_vups = 7,
.cpu_scbsz = 2,
.cpu_halt = ka43_halt,
.cpu_reboot = ka43_reboot,
.cpu_clrf = ka43_clrf,
.cpu_devs = ka43_devs,
.cpu_flags = CPU_RAISEIPL,
};
static volatile struct ka43_cpu *ka43_cpu = (void*)KA43_CPU_BASE;
static volatile u_int *ka43_creg = (void*)KA43_CH2_CREG;
static volatile u_int *ka43_ctag = (void*)KA43_CT2_BASE;
#define KA43_MC_RESTART 0x00008000
#define KA43_PSL_FPDONE 0x00010000
struct ka43_mcframe {
int mc43_bcnt;
int mc43_code;
int mc43_addr;
int mc43_viba;
int mc43_sisr;
int mc43_istate;
int mc43_sc;
int mc43_pc;
int mc43_psl;
};
static const char * const ka43_mctype[] = {
"no error (0)",
"FPA: protocol error",
"FPA: illegal opcode",
"FPA: operand parity error",
"FPA: unknown status",
"FPA: result parity error",
"unused (6)",
"unused (7)",
"MMU error (TLB miss)",
"MMU error (TLB hit)",
"HW interrupt at unused IPL",
"MOVCx impossible state",
"undefined trap code (i-box)",
"undefined control store address",
"unused (14)",
"unused (15)",
"PC tag or data parity error",
"data bus parity error",
"data bus error (NXM)",
"undefined data bus state",
};
#define MC43_MAX 19
static int ka43_error_count = 0;
int
ka43_mchk(void *addr)
{
struct ka43_mcframe *mcf = (void*)addr;
mtpr(0x00, PR_MCESR);
printf("machine check %d (0x%x)\n", mcf->mc43_code, mcf->mc43_code);
printf("reason: %s\n", ka43_mctype[mcf->mc43_code & 0xff]);
if (++ka43_error_count > 10) {
printf("error_count exceeded: %d\n", ka43_error_count);
return (-1);
}
if (mfpr(PR_PCSTS) & KA43_PCS_TRAP2) {
printf("TRAP2 (double error) in ka43_mchk.\n");
panic("unrecoverable state in ka43_mchk.");
return (-1);
}
if ((mcf->mc43_code & KA43_MC_RESTART) ||
(mcf->mc43_psl & KA43_PSL_FPDONE)) {
printf("ka43_mchk: recovering from machine-check.\n");
ka43_cache_reset();
return (0);
}
printf("ka43_mchk: unknown error state!\n");
return (-1);
}
void
ka43_memerr(void)
{
char sbuf[256];
printf("memory error!\n");
snprintb(sbuf, sizeof(sbuf), KA43_PCSTS_BITS, mfpr(PR_PCSTS));
printf("primary cache status: %s\n", sbuf);
snprintb(sbuf, sizeof(sbuf), KA43_SESR_BITS, *ka43_creg);
printf("secondary cache status: %s\n", sbuf);
}
int
ka43_cache_init(void)
{
return (ka43_cache_reset());
}
#if 0
void
ka43_clear_errors(void)
{
int val = *ka43_creg;
val |= KA43_SESR_SERR | KA43_SESR_LERR | KA43_SESR_CERR;
*ka43_creg = val;
}
#endif
int
ka43_cache_reset(void)
{
char sbuf[256];
ka43_cache_disable();
ka43_cache_invalidate();
ka43_cache_enable();
snprintb(sbuf, sizeof(sbuf), KA43_PCSTS_BITS, mfpr(PR_PCSTS));
printf("primary cache status: %s\n", sbuf);
snprintb(sbuf, sizeof(sbuf), KA43_SESR_BITS, *ka43_creg);
printf("secondary cache status: %s\n", sbuf);
return (0);
}
int
ka43_cache_disable(void)
{
int val;
mtpr(KA43_PCS_REFRESH, PR_PCSTS);
val = mfpr(PR_PCSTS);
mtpr(val, PR_PCSTS);
val = *ka43_creg & ~KA43_SESR_CENB;
*ka43_creg = val;
val = KA43_SESR_SERR | KA43_SESR_LERR | KA43_SESR_CERR;
*ka43_creg = val;
return (0);
}
int
ka43_cache_invalidate(void)
{
int i, val;
val = KA43_PCTAG_PARITY;
for (i = 0; i < 256; i++) {
mtpr(i*8, PR_PCIDX);
mtpr(val, PR_PCTAG);
}
val = KA43_PCS_FLUSH | KA43_PCS_REFRESH;
mtpr(val, PR_PCSTS);
val = 0xff;
for (i = 0; i < KA43_CT2_SIZE; i+= 4) {
ka43_ctag[i/4] = val;
}
return (0);
}
int
ka43_cache_enable(void)
{
volatile char *membase = (void*)0x80000000;
int i, val;
val = KA43_PCS_FLUSH | KA43_PCS_REFRESH;
mtpr(val, PR_PCSTS);
*ka43_creg = KA43_SESR_CENB;
for (i=0; i<128*1024; i++) {
val += membase[i];
}
val = KA43_PCS_ENABLE | KA43_PCS_REFRESH;
mtpr(val, PR_PCSTS);
return (0);
}
void
ka43_conf(void)
{
curcpu()->ci_cpustr = "Rigel, 2KB L1 cache, 128KB L2 cache";
ka43_cpu = (void *)vax_map_physmem(VS_REGS, 1);
ka43_creg = (void *)vax_map_physmem(KA43_CH2_CREG, 1);
ka43_ctag = (void *)vax_map_physmem(KA43_CT2_BASE,
(KA43_CT2_SIZE/VAX_NBPG));
ka43_cache_init();
clk_adrshift = 1;
clk_tweak = 2;
clk_page = (short *)vax_map_physmem(VS_CLOCK, 1);
}
void
ka43_steal_pages(void)
{
int val;
val = ka43_cpu->parctl & 0x03;
ka43_cpu->parctl = val;
}
void
ka43_clrf(void)
{
volatile struct ka43_clock *clk = (volatile void *)clk_page;
clk->req = 0;
}
void
ka43_halt(void)
{
volatile struct ka43_clock *clk = (volatile void *)clk_page;
clk->req = 3;
__asm("halt");
}
void
ka43_reboot(int arg)
{
volatile struct ka43_clock *clk = (volatile void *)clk_page;
clk->req = 2;
__asm("halt");
}