#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/filio.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/atomic.h>
#include <uvm/uvm_extern.h>
#include <machine/conf.h>
#include <machine/bus.h>
#include <machine/iomod.h>
#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <hppa/dev/cpudevs.h>
#include <hppa/dev/viper.h>
#define VIPER_HPA 0xfffbf000
struct l2_mioc {
u_int32_t pad[0x20];
u_int32_t mioc_control;
u_int32_t mioc_status;
u_int32_t pad1[6];
u_int32_t sltcv;
#define SLTCV_AVWL 0x00002000
#define SLTCV_UP4COUT 0x00001000
#define SLTCV_EDCEN 0x08000000
#define SLTCV_EDTAG 0x10000000
#define SLTCV_CHKTP 0x20000000
#define SLTCV_LOWPWR 0x40000000
#define SLTCV_ENABLE 0x80000000
#define SLTCV_BITS "\020\15avwl\16up4cout\24edcen\25edtag\26chktp\27lowpwr\30l2ena"
u_int32_t tagmask;
u_int32_t diagtag;
u_int32_t sltestat;
u_int32_t slteadd;
u_int32_t pad2[3];
u_int32_t mtcv;
u_int32_t ref;
u_int32_t pad3[4];
u_int32_t mderradd;
u_int32_t pad4;
u_int32_t dmaerr;
u_int32_t dioerr;
u_int32_t gsc_timeout;
u_int32_t hidmamem;
u_int32_t pad5[2];
u_int32_t memcomp[16];
u_int32_t memmask[16];
u_int32_t memtest;
u_int32_t pad6[0xf];
u_int32_t outchk;
u_int32_t pad7[0x168];
u_int32_t gsc15x_config;
};
struct mem_softc {
struct device sc_dev;
volatile struct vi_trs *sc_vp;
volatile struct l2_mioc *sc_l2;
};
int memmatch(struct device *, void *, void *);
void memattach(struct device *, struct device *, void *);
const struct cfattach mem_ca = {
sizeof(struct mem_softc), memmatch, memattach
};
struct cfdriver mem_cd = {
NULL, "mem", DV_DULL
};
caddr_t zeropage;
int
memmatch(struct device *parent, void *cfdata, void *aux)
{
struct confargs *ca = aux;
if (ca->ca_type.iodc_type != HPPA_TYPE_MEMORY ||
ca->ca_type.iodc_sv_model != HPPA_MEMORY_PDEP)
return 0;
return 1;
}
void
memattach(struct device *parent, struct device *self, void *aux)
{
struct pdc_iodc_minit pdc_minit PDC_ALIGNMENT;
struct mem_softc *sc = (struct mem_softc *)self;
struct confargs *ca = aux;
int err;
printf (":");
if (ca->ca_hpa == (hppa_hpa_t)VIPER_HPA) {
sc->sc_vp = (struct vi_trs *)
&((struct iomod *)ca->ca_hpa)->priv_trs;
printf(" viper rev %x,", sc->sc_vp->vi_status.hw_rev);
if (sc->sc_vp->vi_status.hw_rev == 0) {
u_int32_t vic;
int s, settimeout;
switch (cpu_hvers) {
case HPPA_BOARD_HP705:
case HPPA_BOARD_HP710:
case HPPA_BOARD_HP715_33:
case HPPA_BOARD_HP715S_33:
case HPPA_BOARD_HP715T_33:
case HPPA_BOARD_HP715_50:
case HPPA_BOARD_HP715S_50:
case HPPA_BOARD_HP715T_50:
case HPPA_BOARD_HP715_75:
case HPPA_BOARD_HP720:
case HPPA_BOARD_HP725_50:
case HPPA_BOARD_HP725_75:
case HPPA_BOARD_HP730_66:
case HPPA_BOARD_HP750_66:
settimeout = 1;
break;
default:
settimeout = 0;
break;
}
if (sc->sc_dev.dv_cfdata->cf_flags & 1)
settimeout = !settimeout;
#ifdef DEBUG
printf(" ctrl %b", VI_CTRL, VI_CTRL_BITS);
#endif
s = splhigh();
vic = VI_CTRL;
vic &= ~VI_CTRL_CORE_DEN;
vic &= ~VI_CTRL_SGC0_DEN;
vic &= ~VI_CTRL_SGC1_DEN;
vic |= VI_CTRL_EISA_DEN;
vic |= VI_CTRL_CORE_PRF;
if (settimeout && (vic & VI_CTRL_VSC_TOUT) == 0)
vic |= (850 << 19);
sc->sc_vp->vi_control = vic;
__asm volatile("stwas %1, 0(%0)"
:: "r" (&VI_CTRL), "r" (vic) : "memory");
splx(s);
#ifdef DEBUG
printf (" >> %b,", vic, VI_CTRL_BITS);
#endif
} else {
}
} else
sc->sc_vp = NULL;
if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_NINIT,
&pdc_minit, ca->ca_hpa, PAGE0->imm_spa_size)) < 0)
pdc_minit.max_spa = PAGE0->imm_max_mem;
printf(" size %d", pdc_minit.max_spa / (1024*1024));
if (pdc_minit.max_spa % (1024*1024))
printf(".%d", pdc_minit.max_spa % (1024*1024));
printf("MB");
if (cpu_type == hpcxl2) {
sc->sc_l2 = (struct l2_mioc *)ca->ca_hpa;
#ifdef DEBUG
printf(", sltcv %b", sc->sc_l2->sltcv, SLTCV_BITS);
#endif
if (sc->sc_l2->sltcv & SLTCV_ENABLE) {
u_int32_t tagmask = sc->sc_l2->tagmask >> 20;
printf(", %dMB L2 cache", tagmask + 1);
}
}
printf("\n");
}
void
viper_setintrwnd(u_int32_t mask)
{
struct mem_softc *sc;
sc = mem_cd.cd_devs[0];
if (sc->sc_vp)
sc->sc_vp->vi_intrwd = mask;
}
void
viper_eisa_en(void)
{
struct mem_softc *sc;
sc = mem_cd.cd_devs[0];
if (sc->sc_vp) {
u_int32_t vic;
int s;
s = splhigh();
vic = VI_CTRL;
vic &= ~VI_CTRL_EISA_DEN;
sc->sc_vp->vi_control = vic;
__asm volatile("stwas %1, 0(%0)"
:: "r" (&VI_CTRL), "r" (vic) : "memory");
splx(s);
}
}
int
mmopen(dev_t dev, int flag, int ioflag, struct proc *p)
{
extern int allowkmem;
switch (minor(dev)) {
case 0:
case 1:
if ((int)atomic_load_int(&securelevel) <= 0 ||
atomic_load_int(&allowkmem))
break;
return (EPERM);
case 2:
case 12:
break;
default:
return (ENXIO);
}
return (0);
}
int
mmclose(dev_t dev, int flag, int mode, struct proc *p)
{
return (0);
}
int
mmrw(dev_t dev, struct uio *uio, int flags)
{
struct iovec *iov;
vaddr_t v, o;
int error = 0;
size_t c;
while (uio->uio_resid > 0 && error == 0) {
iov = uio->uio_iov;
if (iov->iov_len == 0) {
uio->uio_iov++;
uio->uio_iovcnt--;
if (uio->uio_iovcnt < 0)
panic("mmrw");
continue;
}
switch (minor(dev)) {
case 0:
v = uio->uio_offset;
if (atop(v) > physmem) {
error = EFAULT;
continue;
}
c = ptoa(physmem) - v;
c = ulmin(c, uio->uio_resid);
error = uiomove((caddr_t)v, c, uio);
break;
case 1:
v = uio->uio_offset;
o = v & PGOFSET;
c = ulmin(uio->uio_resid, PAGE_SIZE - o);
if (atop(v) > physmem && !uvm_kernacc((caddr_t)v,
c, (uio->uio_rw == UIO_READ) ? B_READ : B_WRITE)) {
error = EFAULT;
continue;
}
error = uiomove((caddr_t)v, c, uio);
break;
case 2:
if (uio->uio_rw == UIO_WRITE)
uio->uio_resid = 0;
return (0);
case 12:
if (uio->uio_rw == UIO_WRITE) {
uio->uio_resid = 0;
return (0);
}
if (zeropage == NULL)
zeropage = malloc(PAGE_SIZE, M_TEMP,
M_WAITOK | M_ZERO);
c = ulmin(iov->iov_len, PAGE_SIZE);
error = uiomove(zeropage, c, uio);
break;
default:
return (ENXIO);
}
}
return (error);
}
paddr_t
mmmmap(dev_t dev, off_t off, int prot)
{
if (minor(dev) != 0)
return (-1);
#if 0
if (off < ptoa(firstusablepage) ||
off >= ptoa(lastusablepage + 1))
return (-1);
#endif
return (off);
}
int
mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
{
switch (cmd) {
case FIOASYNC:
return 0;
}
return (ENOTTY);
}