#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ka820.c,v 1.58 2022/03/03 06:28:26 riastradh Exp $");
#include "opt_multiprocessor.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <machine/ka820.h>
#include <machine/nexus.h>
#include <machine/clock.h>
#include <machine/scb.h>
#include <machine/mainbus.h>
#include <dev/cons.h>
#include <dev/bi/bireg.h>
#include <dev/bi/bivar.h>
#include <vax/vax/crx.h>
#include "ioconf.h"
#include "locators.h"
struct ka820port *ka820port_ptr;
struct rx50device *rx50device_ptr;
static volatile struct ka820clock *ka820_clkpage;
static int mastercpu;
static int ka820_match(device_t, cfdata_t, void *);
static void ka820_attach(device_t, device_t, void*);
static void ka820_memerr(void);
static void ka820_conf(void);
static int ka820_mchk(void *);
static int ka820_gettime(struct timeval *);
static void ka820_settime(struct timeval *);
static void rxcdintr(void *);
static void vaxbierr(void *);
static const char * const ka820_devs[] = { "bi", NULL };
const struct cpu_dep ka820_calls = {
.cpu_mchk = ka820_mchk,
.cpu_memerr = ka820_memerr,
.cpu_conf = ka820_conf,
.cpu_gettime = ka820_gettime,
.cpu_settime = ka820_settime,
.cpu_devs = ka820_devs,
.cpu_vups = 3,
.cpu_scbsz = 5,
};
#if defined(MULTIPROCESSOR)
static void ka820_startslave(struct cpu_info *);
static void ka820_send_ipi(struct cpu_info *);
static void ka820_txrx(int, const char *, ...) __printflike(2, 3);
static void ka820_sendstr(int, const char *);
static void ka820_sergeant(int);
static int rxchar(void);
static void ka820_putc(int);
static void ka820_cnintr(void);
static void ka820_ipintr(void *);
cons_decl(gen);
const struct cpu_mp_dep ka820_mp_dep = {
.cpu_startslave = ka820_startslave,
.cpu_send_ipi = ka820_send_ipi,
.cpu_cnintr = ka820_cnintr,
};
#endif
CFATTACH_DECL_NEW(cpu_bi, 0,
ka820_match, ka820_attach, NULL, NULL);
#ifdef notyet
extern struct pte BRAMmap[];
extern struct pte EEPROMmap[];
char bootram[KA820_BRPAGES * VAX_NBPG];
char eeprom[KA820_EEPAGES * VAX_NBPG];
#endif
static int
ka820_match(device_t parent, cfdata_t cf, void *aux)
{
struct bi_attach_args * const ba = aux;
if (bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) != BIDT_KA820)
return 0;
if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT &&
cf->cf_loc[BICF_NODE] != ba->ba_nodenr)
return 0;
return 1;
}
static void
ka820_attach(device_t parent, device_t self, void *aux)
{
struct bi_attach_args * const ba = aux;
struct cpu_info *ci;
char c;
int csr;
u_short rev;
rev = bus_space_read_4(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) >> 16;
c = rev & 0x8000 ? '5' : '0';
mastercpu = mfpr(PR_BINID);
cpu_setmodel("VAX 82%c0", c);
printf(": ka82%c (%s) CPU rev %d, u patch rev %d, sec patch %d\n",
c, mastercpu == ba->ba_nodenr ? "master" : "slave",
((rev >> 11) & 15), ((rev >> 1) &1023), rev & 1);
bus_space_write_4(ba->ba_iot, ba->ba_ioh,
BIREG_IPINTRMSK, BIIPINTR_MASK);
#if defined(MULTIPROCESSOR)
if (ba->ba_nodenr != mastercpu) {
v_putc = ka820_putc;
cpu_slavesetup(self, ba->ba_nodenr);
return;
}
#endif
ci = curcpu();
device_set_private(self, ci);
ci->ci_slotid = ba->ba_nodenr;
ci->ci_cpuid = device_unit(self);
ci->ci_dev = self;
#if defined(MULTIPROCESSOR)
scb_vecalloc(KA820_INT_IPINTR, ka820_ipintr, ci, SCB_ISTACK, NULL);
#endif
ka820port_ptr = (void *)vax_map_physmem(KA820_PORTADDR, 1);
csr = ka820port_ptr->csr;
csr &= ~KA820PORT_RSTHALT;
csr |= KA820PORT_CONSCLR | KA820PORT_CRDCLR | KA820PORT_CONSEN |
KA820PORT_RXIE;
ka820port_ptr->csr = csr;
bus_space_write_4(ba->ba_iot, ba->ba_ioh,
BIREG_INTRDES, ba->ba_intcpu);
bus_space_write_4(ba->ba_iot, ba->ba_ioh, BIREG_VAXBICSR,
bus_space_read_4(ba->ba_iot, ba->ba_ioh, BIREG_VAXBICSR) |
BICSR_SEIE | BICSR_HEIE);
}
void
ka820_conf(void)
{
ka820_clkpage = (void *)vax_map_physmem(KA820_CLOCKADDR, 1);
mtpr(0, PR_CADR);
scb_vecalloc(KA820_INT_RXCD, rxcdintr, NULL, SCB_ISTACK, NULL);
scb_vecalloc(0x50, vaxbierr, NULL, SCB_ISTACK, NULL);
scb_vecalloc(SCB_RX50, crxintr, NULL, SCB_ISTACK, NULL);
rx50device_ptr = (void *)vax_map_physmem(KA820_RX50ADDR, 1);
#if defined(MULTIPROCESSOR)
mp_dep_call = &ka820_mp_dep;
#endif
}
void
vaxbierr(void *arg)
{
if (cold == 0)
panic("vaxbierr");
}
#ifdef notdef
struct ms820regs {
struct biiregs biic;
u_long ms_gpr[4];
int ms_csr1;
int ms_csr2;
};
#endif
#define MEMRD(reg) bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
#define MEMWR(reg, val) bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
#define MSREG_CSR1 0x100
#define MSREG_CSR2 0x104
#define MS1_ERRSUM 0x80000000
#define MS1_ECCDIAG 0x40000000
#define MS1_ECCDISABLE 0x20000000
#define MS1_MSIZEMASK 0x1ffc0000
#define MS1_RAMTYMASK 0x00030000
#define MS1_RAMTY64K 0x00000000
#define MS1_RAMTY256K 0x00010000
#define MS1_RAMTY1MB 0x00020000
#define MS1_CRDINH 0x00008000
#define MS1_MEMVALID 0x00004000
#define MS1_INTLK 0x00002000
#define MS1_BROKE 0x00001000
#define MS1_MBZ 0x00000880
#define MS1_MWRITEERR 0x00000400
#define MS1_CNTLERR 0x00000200
#define MS1_INTLV 0x00000100
#define MS1_DIAGC 0x0000007f
#define MS2_RDSERR 0x80000000
#define MS2_HIERR 0x40000000
#define MS2_CRDERR 0x20000000
#define MS2_ADRSERR 0x10000000
#define MS2_MBZ 0x0f000080
#define MS2_ADDR 0x00fffe00
#define MS2_INTLVADDR 0x00000100
#define MS2_SYN 0x0000007f
static int ms820_match(device_t, cfdata_t, void *);
static void ms820_attach(device_t, device_t, void*);
struct mem_bi_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
};
CFATTACH_DECL_NEW(mem_bi, sizeof(struct mem_bi_softc),
ms820_match, ms820_attach, NULL, NULL);
static int
ms820_match(device_t parent, cfdata_t cf, void *aux)
{
struct bi_attach_args * const ba = aux;
if (bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) != BIDT_MS820)
return 0;
if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT &&
cf->cf_loc[BICF_NODE] != ba->ba_nodenr)
return 0;
return 1;
}
static void
ms820_attach(device_t parent, device_t self, void *aux)
{
struct mem_bi_softc * const sc = device_private(self);
struct bi_attach_args * const ba = aux;
sc->sc_dev = self;
sc->sc_iot = ba->ba_iot;
sc->sc_ioh = ba->ba_ioh;
if ((MEMRD(BIREG_VAXBICSR) & BICSR_STS) == 0)
aprint_error(": failed self test\n");
else
aprint_normal(": size %dMB, %s chips\n", ((MEMRD(MSREG_CSR1) &
MS1_MSIZEMASK) >> 20), (MEMRD(MSREG_CSR1) & MS1_RAMTYMASK
? MEMRD(MSREG_CSR1) & MS1_RAMTY256K ? "256K":"1M":"64K"));
MEMWR(BIREG_INTRDES, ba->ba_intcpu);
MEMWR(BIREG_VAXBICSR, MEMRD(BIREG_VAXBICSR) | BICSR_SEIE | BICSR_HEIE);
MEMWR(MSREG_CSR1, MS1_MWRITEERR | MS1_CNTLERR);
MEMWR(MSREG_CSR2, MS2_RDSERR | MS2_HIERR | MS2_CRDERR | MS2_ADRSERR);
}
static void
ka820_memerr(void)
{
struct mem_bi_softc *sc;
int m, hard, csr1, csr2;
const char *type;
static const char b1[] = "\20\40ERRSUM\37ECCDIAG\36ECCDISABLE\20CRDINH\17VALID\
\16INTLK\15BROKE\13MWRITEERR\12CNTLERR\11INTLV";
static const char b2[] = "\20\40RDS\37HIERR\36CRD\35ADRS";
char sbuf[sizeof(b1) + 64], sbuf2[sizeof(b2) + 64];
for (m = 0; m < mem_cd.cd_ndevs; m++) {
sc = device_lookup_private(&mem_cd, m);
if (sc == NULL)
continue;
csr1 = MEMRD(MSREG_CSR1);
csr2 = MEMRD(MSREG_CSR2);
snprintb(sbuf, sizeof(sbuf), b1, csr1);
snprintb(sbuf2, sizeof(sbuf2), b2, csr2);
aprint_error_dev(sc->sc_dev, "csr1=%s csr2=%s\n", sbuf, sbuf2);
if ((csr1 & MS1_ERRSUM) == 0)
continue;
hard = 1;
if (csr1 & MS1_BROKE)
type = "broke";
else if (csr1 & MS1_CNTLERR)
type = "cntl err";
else if (csr2 & MS2_ADRSERR)
type = "address parity err";
else if (csr2 & MS2_RDSERR)
type = "rds err";
else if (csr2 & MS2_CRDERR) {
hard = 0;
type = "";
} else
type = "mysterious error";
aprint_error_dev(sc->sc_dev, "%s%s%s addr %x bank %x syn %x\n",
hard ? "hard error: " : "soft ecc",
type, csr2 & MS2_HIERR ? " (+ other rds or crd err)" : "",
((csr2 & MS2_ADDR) + MEMRD(BIREG_SADR)) >> 9,
(csr2 & MS2_INTLVADDR) != 0, csr2 & MS2_SYN);
MEMWR(MSREG_CSR1, csr1 | MS1_CRDINH);
MEMWR(MSREG_CSR2, csr2);
}
}
const char * const mc8200[] = {
"cpu bad ipl", "ucode lost err",
"ucode par err", "DAL par err",
"BI bus err", "BTB tag par",
"cache tag par",
};
#define MC8200_BADIPL 0x01
#define MC8200_UERR 0x02
#define MC8200_UPAR 0x04
#define MC8200_DPAR 0x08
#define MC8200_BIERR 0x10
#define MC8200_BTAGPAR 0x20
#define MC8200_CTAGPAR 0x40
struct mc8200frame {
int mc82_bcnt;
int mc82_summary;
int mc82_param1;
int mc82_va;
int mc82_vap;
int mc82_ma;
int mc82_status;
int mc82_epc;
int mc82_upc;
int mc82_pc;
int mc82_psl;
};
static int
ka820_mchk(void *cmcf)
{
struct mc8200frame *mcf = (struct mc8200frame *)cmcf;
int i, type = mcf->mc82_summary;
if (cold && type == MC8200_BIERR) {
mtpr(PR_MCESR, 0xf);
return (MCHK_RECOVERED);
}
printf("machine check %x: ", type);
for (i = 0; i < sizeof (mc8200) / sizeof (mc8200[0]); i++)
if (type & (1 << i))
printf(" %s,", mc8200[i]);
printf(" param1 %x\n", mcf->mc82_param1);
printf(
"\tva %x va' %x ma %x pc %x psl %x\n\tstatus %x errpc %x upc %x\n",
mcf->mc82_va, mcf->mc82_vap, mcf->mc82_ma,
mcf->mc82_pc, mcf->mc82_psl,
mcf->mc82_status, mcf->mc82_epc, mcf->mc82_upc);
return (MCHK_PANIC);
}
#if defined(MULTIPROCESSOR)
#define RXBUF 80
static char rxbuf[RXBUF];
static int got = 0, taken = 0;
static int expect = 0;
#endif
static void
rxcdintr(void *arg)
{
int c = mfpr(PR_RXCD);
if (c == 0)
return;
#if defined(MULTIPROCESSOR)
if (expect == ((c >> 8) & 0xf))
rxbuf[got++] = c & 0xff;
if (got == RXBUF)
got = 0;
#endif
}
#if defined(MULTIPROCESSOR)
int
rxchar(void)
{
int ret;
if (got == taken)
return 0;
ret = rxbuf[taken++];
if (taken == RXBUF)
taken = 0;
return ret;
}
#endif
int
ka820_gettime(struct timeval *tvp)
{
struct clock_ymdhms c;
int s;
while (ka820_clkpage->csr0 & KA820CLK_0_BUSY)
;
s = splhigh();
c.dt_sec = ka820_clkpage->sec;
c.dt_min = ka820_clkpage->min;
c.dt_hour = ka820_clkpage->hr;
c.dt_wday = ka820_clkpage->dayofwk;
c.dt_day = ka820_clkpage->day;
c.dt_mon = ka820_clkpage->mon;
c.dt_year = ka820_clkpage->yr;
splx(s);
c.dt_sec = ((c.dt_sec << 7) | (c.dt_sec >> 1)) & 0377;
c.dt_min = ((c.dt_min << 7) | (c.dt_min >> 1)) & 0377;
c.dt_hour = ((c.dt_hour << 7) | (c.dt_hour >> 1)) & 0377;
c.dt_wday = ((c.dt_wday << 7) | (c.dt_wday >> 1)) & 0377;
c.dt_day = ((c.dt_day << 7) | (c.dt_day >> 1)) & 0377;
c.dt_mon = ((c.dt_mon << 7) | (c.dt_mon >> 1)) & 0377;
c.dt_year = ((c.dt_year << 7) | (c.dt_year >> 1)) & 0377;
tvp->tv_sec = clock_ymdhms_to_secs(&c);
return 0;
}
void
ka820_settime(struct timeval *tvp)
{
struct clock_ymdhms c;
clock_secs_to_ymdhms(tvp->tv_sec, &c);
ka820_clkpage->csr1 = KA820CLK_1_SET;
ka820_clkpage->sec = ((c.dt_sec << 1) | (c.dt_sec >> 7)) & 0377;
ka820_clkpage->min = ((c.dt_min << 1) | (c.dt_min >> 7)) & 0377;
ka820_clkpage->hr = ((c.dt_hour << 1) | (c.dt_hour >> 7)) & 0377;
ka820_clkpage->dayofwk = ((c.dt_wday << 1) | (c.dt_wday >> 7)) & 0377;
ka820_clkpage->day = ((c.dt_day << 1) | (c.dt_day >> 7)) & 0377;
ka820_clkpage->mon = ((c.dt_mon << 1) | (c.dt_mon >> 7)) & 0377;
ka820_clkpage->yr = ((c.dt_year << 1) | (c.dt_year >> 7)) & 0377;
ka820_clkpage->csr1 = KA820CLK_1_GO;
}
#if defined(MULTIPROCESSOR)
static void
ka820_startslave(struct cpu_info *ci)
{
const struct pcb *pcb = lwp_getpcb(ci->ci_onproc);
const int id = ci->ci_slotid;
int i;
expect = id;
for (i = 0; i < 10000; i++)
if (rxchar())
i = 0;
ka820_txrx(id, "\020");
ka820_txrx(id, "I\r");
ka820_txrx(id, "D/I 4 %x\r", (int)ci->ci_istack);
ka820_txrx(id, "D/I C %x\r", mfpr(PR_SBR));
ka820_txrx(id, "D/I D %x\r", mfpr(PR_SLR));
ka820_txrx(id, "D/I 10 %x\r", (int)pcb->pcb_paddr);
ka820_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));
ka820_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN));
ka820_txrx(id, "S %x\r", (int)&vax_mp_tramp);
expect = 0;
for (i = 0; i < 10000; i++)
if (ci->ci_flags & CI_RUNNING)
break;
if (i == 10000)
aprint_error_dev(ci->ci_dev, "(ID %d) failed starting??\n", id);
}
void
ka820_txrx(int id, const char *fmt, ...)
{
char buf[20];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
ka820_sendstr(id, buf);
ka820_sergeant(id);
}
static void
ka820_sendchr(int chr)
{
__asm volatile("1:;mtpr %0,$92;bvs 1b" :: "g"(chr));
}
void
ka820_sendstr(int id, const char *buf)
{
u_int utchr;
int ch, i;
while (*buf) {
utchr = *buf | id << 8;
ka820_sendchr(utchr);
buf++;
i = 30000;
while ((ch = rxchar()) == 0 && --i)
;
if (ch == 0)
continue;
}
}
void
ka820_sergeant(int id)
{
int i, ch, nserg;
nserg = 0;
for (i = 0; i < 30000; i++) {
if ((ch = rxchar()) == 0)
continue;
if (ch == '>')
nserg++;
else
nserg = 0;
i = 0;
if (nserg == 3)
break;
}
}
static volatile int ch = 0;
void
ka820_putc(int c)
{
if (curcpu()->ci_flags & CI_MASTERCPU) {
gencnputc(0, c);
return;
}
ch = c;
cpu_send_ipi(IPI_DEST_MASTER, IPI_SEND_CNCHAR);
while (ch != 0)
;
}
void
ka820_cnintr(void)
{
if (ch != 0)
gencnputc(0, ch);
ch = 0;
}
void
ka820_send_ipi(struct cpu_info *ci)
{
mtpr(1 << ci->ci_cpuid, PR_IPIR);
}
void
ka820_ipintr(void *arg)
{
cpu_handle_ipi();
}
#endif