#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ka780.c,v 1.35 2024/02/04 18:47:27 andvar Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <machine/nexus.h>
#include <machine/sid.h>
#include <machine/clock.h>
#include "ioconf.h"
#include "locators.h"
static void ka780_memerr(void);
static int ka780_mchk(void *);
static void ka780_conf(void);
static void ka780_attach_cpu(device_t);
static int getsort(int type);
static int mem_sbi_match(device_t, cfdata_t, void *);
static void mem_sbi_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(mem_sbi, sizeof(struct mem_softc),
mem_sbi_match, mem_sbi_attach, NULL, NULL);
int
mem_sbi_match(device_t parent, cfdata_t cf, void *aux)
{
struct sbi_attach_args * const sa = aux;
if (cf->cf_loc[SBICF_TR] != sa->sa_nexnum &&
cf->cf_loc[SBICF_TR] != SBICF_TR_DEFAULT)
return 0;
return getsort(sa->sa_type);
}
int
getsort(int type)
{
switch (type) {
case NEX_MEM4:
case NEX_MEM4I:
case NEX_MEM16:
case NEX_MEM16I:
return M780C;
case NEX_MEM64I:
case NEX_MEM64L:
case NEX_MEM64LI:
case NEX_MEM256I:
case NEX_MEM256L:
case NEX_MEM256LI:
return M780EL;
case NEX_MEM64U:
case NEX_MEM64UI:
case NEX_MEM256U:
case NEX_MEM256UI:
return M780EU;
default:
return M_NONE;
}
}
static const char * const ka780_devs[] = { "cpu", "sbi", NULL };
const struct cpu_dep ka780_calls = {
.cpu_mchk = ka780_mchk,
.cpu_memerr = ka780_memerr,
.cpu_conf = ka780_conf,
.cpu_gettime = generic_gettime,
.cpu_settime = generic_settime,
.cpu_vups = 2,
.cpu_scbsz = 5,
.cpu_devs = ka780_devs,
.cpu_attach_cpu = ka780_attach_cpu,
};
struct mcr780 {
int mc_reg[4];
};
#define M780_ICRD 0x40000000
#define M780_HIER 0x20000000
#define M780_ERLOG 0x10000000
#define M780C_INH(mcr) \
((mcr)->mc_reg[2] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
mtpr(0, PR_SBIER);
#define M780C_ENA(mcr) \
((mcr)->mc_reg[2] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
#define M780C_ERR(mcr) \
((mcr)->mc_reg[2] & (M780_ERLOG))
#define M780C_SYN(mcr) ((mcr)->mc_reg[2] & 0xff)
#define M780C_ADDR(mcr) (((mcr)->mc_reg[2] >> 8) & 0xfffff)
#define M780EL_INH(mcr) \
((mcr)->mc_reg[2] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
mtpr(0, PR_SBIER);
#define M780EL_ENA(mcr) \
((mcr)->mc_reg[2] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
#define M780EL_ERR(mcr) \
((mcr)->mc_reg[2] & (M780_ERLOG))
#define M780EL_SYN(mcr) ((mcr)->mc_reg[2] & 0x7f)
#define M780EL_ADDR(mcr) (((mcr)->mc_reg[2] >> 11) & 0x1ffff)
#define M780EU_INH(mcr) \
((mcr)->mc_reg[3] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
mtpr(0, PR_SBIER);
#define M780EU_ENA(mcr) \
((mcr)->mc_reg[3] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
#define M780EU_ERR(mcr) \
((mcr)->mc_reg[3] & (M780_ERLOG))
#define M780EU_SYN(mcr) ((mcr)->mc_reg[3] & 0x7f)
#define M780EU_ADDR(mcr) (((mcr)->mc_reg[3] >> 11) & 0x1ffff)
void
mem_sbi_attach(device_t parent, device_t self, void *aux)
{
struct sbi_attach_args * const sa = (struct sbi_attach_args *)aux;
struct mem_softc * const sc = device_private(self);
struct mcr780 * const mcr = (void *)sa->sa_ioh;
sc->sc_dev = self;
sc->sc_memaddr = (void *)sa->sa_ioh;
sc->sc_memtype = getsort(sa->sa_type);
sc->sc_memnr = sa->sa_type;
switch (sc->sc_memtype) {
case M780C:
aprint_normal(": standard");
M780C_ENA(mcr);
break;
case M780EL:
aprint_normal(": (el) ");
M780EL_ENA(mcr);
if (sc->sc_memnr != NEX_MEM64I && sc->sc_memnr != NEX_MEM256I)
break;
case M780EU:
aprint_normal(": (eu)");
M780EU_ENA(mcr);
break;
}
printf("\n");
}
#ifdef TRENDATA
const struct {
u_char m_syndrome;
char m_chip[4];
} memlogtab[] = {
{0x01, "C00"}, {0x02, "C01"}, {0x04, "C02"}, {0x08, "C03"},
{0x10, "C04"}, {0x19, "L01"}, {0x1A, "L02"}, {0x1C, "L04"},
{0x1F, "L07"}, {0x20, "C05"}, {0x38, "L00"}, {0x3B, "L03"},
{0x3D, "L05"}, {0x3E, "L06"}, {0x40, "C06"}, {0x49, "L09"},
{0x4A, "L10"}, {0x4c, "L12"}, {0x4F, "L15"}, {0x51, "L17"},
{0x52, "L18"}, {0x54, "L20"}, {0x57, "L23"}, {0x58, "L24"},
{0x5B, "L27"}, {0x5D, "L29"}, {0x5E, "L30"}, {0x68, "L08"},
{0x6B, "L11"}, {0x6D, "L13"}, {0x6E, "L14"}, {0x70, "L16"},
{0x73, "L19"}, {0x75, "L21"}, {0x76, "L22"}, {0x79, "L25"},
{0x7A, "L26"}, {0x7C, "L28"}, {0x7F, "L31"}, {0x80, "C07"},
{0x89, "U01"}, {0x8A, "U02"}, {0x8C, "U04"}, {0x8F, "U07"},
{0x91, "U09"}, {0x92, "U10"}, {0x94, "U12"}, {0x97, "U15"},
{0x98, "U16"}, {0x9B, "U19"}, {0x9D, "U21"}, {0x9E, "U22"},
{0xA8, "U00"}, {0xAB, "U03"}, {0xAD, "U05"}, {0xAE, "U06"},
{0xB0, "U08"}, {0xB3, "U11"}, {0xB5, "U13"}, {0xB6, "U14"},
{0xB9, "U17"}, {0xBA, "U18"}, {0xBC, "U20"}, {0xBF, "U23"},
{0xC1, "U25"}, {0xC2, "U26"}, {0xC4, "U28"}, {0xC7, "U31"},
{0xE0, "U24"}, {0xE3, "U27"}, {0xE5, "U29"}, {0xE6, "U30"}
};
static void
memlog(int m, struct mcr780 *mcr)
{
int i;
for (i = 0; i < __arraycount(memlogtab); i++)
if ((u_char)(M780C_SYN(mcr)) == memlogtab[i].m_syndrome) {
printf(
"mcr%d: replace %s chip in %s bank of memory"
" board %d (0-15)\n",
m, memlogtab[i].m_chip,
(M780C_ADDR(mcr) & 0x8000) ? "upper" : "lower",
(M780C_ADDR(mcr) >> 16));
return;
}
printf("mcr%d: multiple errors, not traceable\n", m);
}
#endif
void
ka780_memerr(void)
{
struct mem_softc *sc;
struct mcr780 *mcr;
int m;
for (m = 0; m < mem_cd.cd_ndevs; m++) {
sc = device_lookup_private(&mem_cd, m);
if (sc == NULL)
continue;
mcr = (struct mcr780 *)sc->sc_memaddr;
switch (sc->sc_memtype) {
case M780C:
if (M780C_ERR(mcr)) {
aprint_error_dev(sc->sc_dev,
"soft ecc addr %x syn %x\n",
M780C_ADDR(mcr), M780C_SYN(mcr));
#ifdef TRENDATA
memlog(m, mcr);
#endif
M780C_INH(mcr);
}
break;
case M780EL:
if (M780EL_ERR(mcr)) {
aprint_error_dev(sc->sc_dev,
"soft ecc addr %x syn %x\n",
M780EL_ADDR(mcr), M780EL_SYN(mcr));
M780EL_INH(mcr);
}
if (sc->sc_memnr != NEX_MEM64I &&
sc->sc_memnr != NEX_MEM256I)
break;
case M780EU:
if (M780EU_ERR(mcr)) {
aprint_error_dev(sc->sc_dev,
"soft ecc addr %x syn %x\n",
M780EU_ADDR(mcr), M780EU_SYN(mcr));
M780EU_INH(mcr);
}
break;
}
}
}
const char mc780[][3] = {
"0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"
};
struct mc780frame {
int mc8_bcnt;
int mc8_summary;
int mc8_cpues;
int mc8_upc;
int mc8_vaviba;
int mc8_dreg;
int mc8_tber0;
int mc8_tber1;
int mc8_timo;
int mc8_parity;
int mc8_sbier;
int mc8_pc;
int mc8_psl;
};
int
ka780_mchk(void *cmcf)
{
struct mc780frame * const mcf = (struct mc780frame *)cmcf;
int type = mcf->mc8_summary;
int sbifs;
printf("machine check %x: %s%s\n", type, mc780[type&0xf],
(type&0xf0) ? " abort" : " fault");
printf("\tcpues %x upc %x va/viba %x dreg %x tber %x %x\n",
mcf->mc8_cpues, mcf->mc8_upc, mcf->mc8_vaviba,
mcf->mc8_dreg, mcf->mc8_tber0, mcf->mc8_tber1);
sbifs = mfpr(PR_SBIFS);
printf("\ttimo %x parity %x sbier %x pc %x psl %x sbifs %x\n",
mcf->mc8_timo*4, mcf->mc8_parity, mcf->mc8_sbier,
mcf->mc8_pc, mcf->mc8_psl, sbifs);
mtpr(sbifs &~ 0x2000000, PR_SBIFS);
mtpr(mfpr(PR_SBIER) | 0x70c0, PR_SBIER);
return (MCHK_PANIC);
}
struct ka78x {
unsigned snr:12,
plant:3,
eco:8,
v785:1,
type:8;
};
void
ka780_conf(void)
{
mtpr(0x200000, PR_SBIMT);
}
void
ka780_attach_cpu(device_t self)
{
struct ka78x * const ka78 = (void *)&vax_cpudata;
aprint_normal(": KA%s, S/N %d(%d), hardware ECO level %d(%d)\n",
cpu_getmodel() + 7, ka78->snr, ka78->plant, ka78->eco >> 4, ka78->eco);
aprint_normal_dev(self, "4KB L1 cache");
if (mfpr(PR_ACCS) & 255) {
aprint_normal(", FPA present\n");
mtpr(0x8000, PR_ACCS);
} else
aprint_normal(", no FPA\n");
}