#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ka750.c,v 1.47 2017/05/22 16:46:15 ragge Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <machine/ka750.h>
#include <machine/clock.h>
#include <machine/sid.h>
#include <vax/vax/gencons.h>
#include "locators.h"
void ctuattach(void);
static void ka750_clrf(void);
static void ka750_conf(void);
static void ka750_memerr(void);
static int ka750_mchk(void *);
static void ka750_attach_cpu(device_t);
static const char * const ka750_devs[] = { "cpu", "cmi", NULL };
const struct cpu_dep ka750_calls = {
.cpu_mchk = ka750_mchk,
.cpu_memerr = ka750_memerr,
.cpu_conf = ka750_conf,
.cpu_gettime = generic_gettime,
.cpu_settime = generic_settime,
.cpu_vups = 1,
.cpu_scbsz = 4,
.cpu_clrf = ka750_clrf,
.cpu_devs = ka750_devs,
.cpu_attach_cpu = ka750_attach_cpu,
};
static void *mcraddr[4];
void
ka750_conf(void)
{
if (mfpr(PR_TODR) == 0) {
mtpr(1, PR_TODR);
printf("WARNING: TODR battery broken\n");
}
ctuattach();
}
void
ka750_attach_cpu(device_t self)
{
aprint_normal(": KA750, 4KB L1 cache, hardware/ucode rev %d/%d, ",
V750HARDW(vax_cpudata), V750UCODE(vax_cpudata));
if (mfpr(PR_ACCS) & 255) {
aprint_normal("FPA present\n");
mtpr(0x8000, PR_ACCS);
} else {
aprint_normal("no FPA\n");
}
}
static int ka750_memmatch(device_t, cfdata_t, void *);
static void ka750_memenable(device_t, device_t, void *);
CFATTACH_DECL_NEW(mem_cmi, 0,
ka750_memmatch, ka750_memenable, NULL, NULL);
int
ka750_memmatch(device_t parent, cfdata_t cf, void *aux)
{
struct sbi_attach_args * const sa = aux;
if (cf->cf_loc[CMICF_TR] != sa->sa_nexnum &&
cf->cf_loc[CMICF_TR] > CMICF_TR_DEFAULT)
return 0;
if (sa->sa_type != NEX_MEM16)
return 0;
return 1;
}
struct mcr750 {
int mc_err;
int mc_inh;
int mc_inf;
};
#define M750_ICRD 0x10000000
#define M750_UNCORR 0xc0000000
#define M750_CORERR 0x20000000
#define M750_INH(mcr) ((mcr)->mc_inh = 0)
#define M750_ENA(mcr) ((mcr)->mc_err = (M750_UNCORR|M750_CORERR), \
(mcr)->mc_inh = M750_ICRD)
#define M750_ERR(mcr) ((mcr)->mc_err & (M750_UNCORR|M750_CORERR))
#define M750_SYN(err) ((err) & 0x7f)
#define M750_ADDR(err) (((err) >> 9) & 0x7fff)
void
ka750_memenable(device_t parent, device_t self, void *aux)
{
struct sbi_attach_args * const sa = aux;
struct mcr750 * const mcr = (struct mcr750 *)sa->sa_ioh;
int k, l, m, cardinfo;
mcraddr[device_unit(self)] = (void *)sa->sa_ioh;
cardinfo = mcr->mc_inf;
switch ((cardinfo >> 24) & 3) {
case 0: printf(": L0011 ");
break;
case 1: printf(": L0016 ");
m = cardinfo & 0xaaaa;
for (k = l = 0; k < 16; k++){
if (m & 1)
l++;
m >>= 1;
}
printf("with %d M8750",l);
break;
case 3: printf(": L0022 ");
m = cardinfo & 0x5555;
for (k = l = 0; k < 16; k++) {
if (m & 1)
l++;
m>>=1;
}
printf("with %d M7199",l);
m = cardinfo & 0xaaaa;
if (m) {
for (k = l = 0; k < 16; k++) {
if (m & 1)
l++;
m >>= 1;
}
printf(" and %d M8750",l);
}
break;
}
printf("\n");
M750_ENA((struct mcr750 *)mcraddr[0]);
}
void
ka750_memerr(void)
{
struct mcr750 * const mcr = (struct mcr750 *)mcraddr[0];
int err;
if (M750_ERR(mcr)) {
err = mcr->mc_err;
printf("mcr0: %s", err & M750_UNCORR ?
"hard error" : "soft ecc");
printf(" addr %x syn %x\n", M750_ADDR(err), M750_SYN(err));
M750_INH(mcr);
}
}
const char mc750[][3] = {
"0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"
};
struct mc750frame {
int mc5_bcnt;
int mc5_summary;
int mc5_va;
int mc5_errpc;
int mc5_mdr;
int mc5_svmode;
int mc5_rdtimo;
int mc5_tbgpar;
int mc5_cacherr;
int mc5_buserr;
int mc5_mcesr;
int mc5_pc;
int mc5_psl;
};
#define MC750_TBERR 2
#define MC750_TBPAR 4
int
ka750_mchk(void *cmcf)
{
register struct mc750frame *mcf = (struct mc750frame *)cmcf;
register int type = mcf->mc5_summary;
int mcsr = mfpr(PR_MCSR);
printf("machine check %x: %s%s\n", type, mc750[type&0xf],
(type&0xf0) ? " abort" : " fault");
printf(
"\tva %x errpc %x mdr %x smr %x rdtimo %x tbgpar %x cacherr %x\n",
mcf->mc5_va, mcf->mc5_errpc, mcf->mc5_mdr, mcf->mc5_svmode,
mcf->mc5_rdtimo, mcf->mc5_tbgpar, mcf->mc5_cacherr);
printf("\tbuserr %x mcesr %x pc %x psl %x mcsr %x\n",
mcf->mc5_buserr, mcf->mc5_mcesr, mcf->mc5_pc, mcf->mc5_psl,
mcsr);
mtpr(0, PR_TBIA);
mtpr(0xf, PR_MCESR);
if (type == MC750_TBERR && (mcf->mc5_mcesr&0xe) == MC750_TBPAR) {
printf("tbuf par: flushing and returning\n");
return (MCHK_RECOVERED);
}
return (MCHK_PANIC);
}
void
ka750_clrf(void)
{
int s = splhigh();
#define WAIT while ((mfpr(PR_TXCS) & GC_RDY) == 0) ;
WAIT;
mtpr(GC_CWFL|GC_CONS, PR_TXDB);
WAIT;
mtpr(GC_CCFL|GC_CONS, PR_TXDB);
WAIT;
splx(s);
}