#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: memreg.c,v 1.45 2012/07/29 00:04:05 matt Exp $");
#include "opt_sparc_arch.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/device.h>
#include <machine/autoconf.h>
#include <machine/ctlreg.h>
#include <sparc/sparc/memreg.h>
#include <sparc/sparc/vaddrs.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/cpuvar.h>
#include <machine/pte.h>
#include <machine/reg.h>
#include <machine/trap.h>
volatile u_int *par_err_reg;
static int memregmatch_mainbus(device_t, cfdata_t, void *);
static int memregmatch_obio(device_t, cfdata_t, void *);
static void memregattach_mainbus(device_t, device_t, void *);
static void memregattach_obio(device_t, device_t, void *);
CFATTACH_DECL_NEW(memreg_mainbus, 0,
memregmatch_mainbus, memregattach_mainbus, NULL, NULL);
CFATTACH_DECL_NEW(memreg_obio, 0,
memregmatch_obio, memregattach_obio, NULL, NULL);
#if defined(SUN4M)
static void hardmemerr4m(unsigned, u_int, u_int, u_int, u_int);
#endif
static int
memregmatch_mainbus(device_t parent, cfdata_t cf, void *aux)
{
struct mainbus_attach_args *ma = aux;
return (strcmp("memory-error", ma->ma_name) == 0);
}
static int
memregmatch_obio(device_t parent, cfdata_t cf, void *aux)
{
union obio_attach_args *uoba = aux;
if (uoba->uoba_isobio4 == 0)
return (strcmp("memory-error", uoba->uoba_sbus.sa_name) == 0);
if (!CPU_ISSUN4) {
printf("memregmatch_obio: attach args mixed up\n");
return (0);
}
return (1);
}
static void
memregattach_mainbus(device_t parent, device_t self, void *aux)
{
struct mainbus_attach_args *ma = aux;
bus_space_handle_t bh;
printf("\n");
if (ma->ma_promvaddr != 0) {
par_err_reg = (volatile int *)ma->ma_promvaddr;
return;
}
if (bus_space_map(ma->ma_bustag,
ma->ma_paddr,
sizeof(par_err_reg),
BUS_SPACE_MAP_LINEAR,
&bh) != 0) {
printf("memregattach_mainbus: can't map register\n");
return;
}
par_err_reg = (volatile int *)bh;
}
static void
memregattach_obio(device_t parent, device_t self, void *aux)
{
union obio_attach_args *uoba = aux;
bus_space_handle_t bh;
if (uoba->uoba_isobio4 == 0) {
struct sbus_attach_args *sa = &uoba->uoba_sbus;
if (sa->sa_promvaddr != 0) {
par_err_reg = (volatile int *)sa->sa_promvaddr;
return;
}
if (sbus_bus_map(sa->sa_bustag,
sa->sa_slot, sa->sa_offset,
sizeof(par_err_reg),
BUS_SPACE_MAP_LINEAR, &bh) != 0) {
printf("memregattach_obio: can't map register\n");
return;
}
par_err_reg = (volatile int *)bh;
}
if (par_err_reg == NULL)
panic("memregattach");
printf("\n");
}
void
memerr4_4c(unsigned int issync,
u_int ser, u_int sva, u_int aer, u_int ava,
struct trapframe *tf)
{
char bits[64];
u_int pte;
snprintb(bits, sizeof(bits), SER_BITS, ser);
printf("%ssync mem arr: ser=%s sva=0x%x ",
issync ? "" : "a", bits, sva);
snprintb(bits, sizeof(bits), AER_BITS, aer & 0xff);
printf("aer=%s ava=0x%x\n", bits, ava);
pte = getpte4(sva);
if ((pte & PG_V) != 0 && (pte & PG_TYPE) == PG_OBMEM) {
u_int pa = (pte & PG_PFNUM) << PGSHIFT;
printf(" spa=0x%x, module location: %s\n", pa,
prom_pa_location(pa, 0));
}
pte = getpte4(ava);
if ((pte & PG_V) != 0 && (pte & PG_TYPE) == PG_OBMEM) {
u_int pa = (pte & PG_PFNUM) << PGSHIFT;
printf(" apa=0x%x, module location: %s\n", pa,
prom_pa_location(pa, 0));
}
if (par_err_reg) {
snprintb(bits, sizeof(bits), PER_BITS, *par_err_reg);
printf("parity error register = %s\n", bits);
}
panic("memory error");
}
#if defined(SUN4M)
static void
hardmemerr4m(unsigned type, u_int sfsr, u_int sfva, u_int afsr, u_int afva)
{
char bits[64];
printf("memory fault: type %d", type);
snprintb(bits, sizeof(bits), SFSR_BITS, sfsr);
printf("sfsr=%s sfva=0x%x\n", bits, sfva);
if (afsr != 0) {
snprintb(bits, sizeof(bits), AFSR_BITS, afsr);
printf("; afsr=%s afva=0x%x%x\n", bits,
(afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
}
if ((sfsr & SFSR_FT) == SFSR_FT_NONE && (afsr & AFSR_AFO) == 0)
return;
panic("hard memory error");
}
static int addrold = (int) 0xdeadbeef;
static int addroldtop = (int) 0xdeadbeef;
static int oldtype = -1;
void
hypersparc_memerr(unsigned type, u_int sfsr, u_int sfva, struct trapframe *tf)
{
u_int afsr;
u_int afva;
KERNEL_LOCK(1, NULL);
(*cpuinfo.get_asyncflt)(&afsr, &afva);
if ((afsr & AFSR_AFO) != 0) {
printf("HyperSPARC async cache memory failure at phys 0x%x%x\n",
(afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
if (afva == addrold && (afsr & AFSR_AFA) == addroldtop)
goto hard;
oldtype = -1;
addrold = afva;
addroldtop = afsr & AFSR_AFA;
}
out:
KERNEL_UNLOCK_ONE(NULL);
return;
hard:
hardmemerr4m(type, sfsr, sfva, afsr, afva);
goto out;
}
void
viking_memerr(unsigned type, u_int sfsr, u_int sfva, struct trapframe *tf)
{
u_int afsr=0;
u_int afva=0;
KERNEL_LOCK(1, NULL);
if (type == T_STOREBUFFAULT) {
printf("store buffer copy-back failure at 0x%x. Retrying...\n",
sfva);
if (oldtype == T_STOREBUFFAULT || addrold == sfva)
goto hard;
oldtype = T_STOREBUFFAULT;
addrold = sfva;
sta(SRMMU_PCR, ASI_SRMMU,
lda(SRMMU_PCR, ASI_SRMMU) | VIKING_PCR_SB);
} else if (type == T_DATAFAULT && (sfsr & SFSR_FAV) == 0) {
printf("warning: got data fault with no faulting address."
" Ignoring.\n");
if (oldtype == T_DATAFAULT)
goto hard;
oldtype = T_DATAFAULT;
}
out:
KERNEL_UNLOCK_ONE(NULL);
return;
hard:
hardmemerr4m(type, sfsr, sfva, afsr, afva);
goto out;
}
void
memerr4m(unsigned type, u_int sfsr, u_int sfva, struct trapframe *tf)
{
u_int afsr;
u_int afva;
KERNEL_LOCK(1, NULL);
if ((*cpuinfo.get_asyncflt)(&afsr, &afva) != 0)
afsr = afva = 0;
hardmemerr4m(type, sfsr, sfva, afsr, afva);
KERNEL_UNLOCK_ONE(NULL);
}
#endif