Files
Arquivotheca.SunOS-4.1.4/sys/sun4m/module_ross.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

386 lines
9.1 KiB
C

#ident "@(#)module_ross.c 1.1 94/10/31 SMI"
/*
* Copyright (c) 1990 by Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <machine/module.h>
/*
* Support for modules based on the
* Cypress CY604/CY605 memory management unit
*
* To enable this module, declare this near the top of module_conf.c:
*
* extern int ross_module_identify();
* extern void ross_module_setup();
*
* and add this line to the module_info table in module_conf.c:
*
* { ross_module_identify, ross_module_setup },
*/
extern u_int swapl();
extern void mmu_flushpagectx();
extern void vac_pagectxflush();
#ifndef MULTIPROCESSOR
#define xc_attention()
#define xc_dismissed()
#else MULTIPROCESSOR
extern xc_attention();
extern xc_dismissed();
#endif MULTIPROCESSOR
int ross_test_mcr = 0;
#define ROSS_VERSE
#ifdef ROSS_VERSE
/*
* If ROSS_VERSE is defined, ross_verse shows whether
* we are running on a vers=0xE (A.3) Cy7C605.
* If so, we must not use copyback mode.
*/
int ross_verse = 0;
#endif
#define ROSS_NOASI
#ifdef ROSS_NOASI
#define ROSS_VERSD
#ifdef ROSS_VERSD
/*
* If ROSS_VERSD is defined, ross_verse shows whether
* we are running on a vers=0xD (A.5) Cy7C605.
* If so, we must not use ASI-based flushes.
*/
int ross_versd = 0;
#endif ROSS_VERSD
/*
* If ross_noasi is turned on,
* avoid using ASI-based flushes.
*/
int ross_noasi = 0;
#endif ROSS_NOASI
#define ROSS_VERSC
#ifndef lint
extern void ross_mmu_getasyncflt();
extern u_int ross_pte_rmw();
#else lint
void ross_mmu_getasyncflt(){}
u_int ross_pte_rmw(p,a,o) u_int *p,a,o;
{ return swapl((*p&~a)|o,p);}
#endif lint
extern u_int ross_pte_offon();
extern void ross_module_wkaround();
#ifdef MULTIPROCESSOR
extern u_int (*mp_pte_offon)();
#endif MULTIPROCESSOR
void
ross_vac_init()
{
static int calls = 0;
static u_int setbits = 0;
static u_int clrbits = 0;
extern int vac_copyback;
extern char *vac_mode;
extern void ross_vac_init_asm();
extern u_int mmu_getcr();
if (!calls++) {
#ifdef ROSS_VERSE
if (ross_verse) {
printf("WARNING: Rev A.3 cache controller detected\n");
printf("WORKAROUND: avoiding copyback cache mode\n");
}
#endif ROSS_VERSE
if (vac_copyback)
setbits = 0x400;
else
clrbits = 0x400;
}
ross_vac_init_asm(clrbits, setbits);
if (mmu_getcr() & 0x400)
vac_mode = "COPYBACK";
else
vac_mode = "WRITETHRU";
}
#ifndef lint
extern void ross_vac_flushall();
extern void ross_vac_usrflush();
extern void ross_vac_ctxflush();
extern void ross_vac_rgnflush();
extern void ross_vac_segflush();
extern void ross_vac_pageflush();
extern void ross_vac_pagectxflush();
extern void ross_vac_flush();
extern void ross_cache_on();
#else lint
void ross_vac_init_asm(c,s) u_int c, s; { vac_copyback = c ^ s; }
void ross_vac_flushall(){}
void ross_vac_usrflush(){}
void ross_vac_ctxflush(){}
void ross_vac_rgnflush(){}
void ross_vac_segflush(){}
void ross_vac_pageflush(){}
void ross_vac_pagectxflush(){}
void ross_vac_flush(){}
void ross_cache_on(){}
#endif lint
/*
* PSR IMPL PSR REV MCR IMPL MCR REV CPU TYPE
* -------- ------- -------- ------- --------
* 0x1 0x1 0x1 0x{0..F} Ross
*/
int
ross_module_identify(mcr)
int mcr;
{
/* XXX - how to recognise from psr? hypersparc support? */
if (((mcr >> 24) & 0xf0) == 0x10)
return (1);
return (0);
}
void /*ARGSUSED*/
ross_module_setup(mcr)
register int mcr;
{
register int vers;
#ifdef ROSS_NOASI
extern void ross_na_module_setup();
#endif ROSS_NOASI
extern int cpuid;
if (ross_test_mcr) {
prom_printf("ross_module_setup: pretending mcr is %x, not %x\n",
ross_test_mcr, mcr);
mcr = ross_test_mcr;
}
vers = (mcr >> 24) & 0xF;
v_mmu_getasyncflt = ross_mmu_getasyncflt;
v_vac_init = ross_vac_init;
v_vac_flushall = ross_vac_flushall;
v_vac_usrflush = ross_vac_usrflush;
v_vac_ctxflush = ross_vac_ctxflush;
v_vac_rgnflush = ross_vac_rgnflush;
v_vac_segflush = ross_vac_segflush;
v_vac_pageflush = ross_vac_pageflush;
v_vac_pagectxflush = ross_vac_pagectxflush;
v_vac_flush = ross_vac_flush;
v_cache_on = ross_cache_on;
v_pte_offon = ross_pte_offon;
v_module_wkaround = ross_module_wkaround;
#ifdef MULTIPROCESSOR
mp_pte_offon = ross_pte_offon;
#endif MULTIPROCESSOR
#ifdef ROSS_VERSE
if (vers == 0xE) {
ross_verse = 1;
vac_copyback = 0;
} else
ross_verse = 0;
#endif ROSS_VERSE
#ifdef ROSS_NOASI
#ifdef ROSS_VERSD
if (vers == 0xD) {
ross_versd = 1;
ross_noasi = 1;
} else
ross_versd = 0;
#endif ROSS_VERSD
if (ross_noasi)
ross_na_module_setup(mcr);
#endif ROSS_NOASI
}
#ifdef ROSS_NOASI
/************************************************************************
* Ross "no-asi" support
*
* replace flush entries with routines that avoid using
* the ASI-based flush code.
*/
void
ross_noasi_vac_init()
{
static int calls = 0;
if (!calls++) {
#ifdef ROSS_VERSD
if (ross_versd)
printf("WARNING: Rev A.5 cache controller detected\n");
#endif ROSS_VERSD
printf("WORKAROUND: avoiding ASI-based cache flushes\n");
}
ross_vac_init();
}
#ifndef lint
extern void ross_noasi_vac_usrflush();
extern void ross_noasi_vac_ctxflush();
extern void ross_noasi_vac_rgnflush();
extern void ross_noasi_vac_segflush();
extern void ross_noasi_vac_pageflush();
extern void ross_noasi_vac_pagectxflush();
extern void ross_noasi_vac_flush();
#else lint
void ross_noasi_vac_usrflush(){}
void ross_noasi_vac_ctxflush(){}
void ross_noasi_vac_rgnflush(){}
void ross_noasi_vac_segflush(){}
void ross_noasi_vac_pageflush(){}
void ross_noasi_vac_pagectxflush(){}
void ross_noasi_vac_flush(){}
#endif lint
void /*ARGSUSED*/
ross_na_module_setup(mcr)
register int mcr;
{
v_vac_init = ross_noasi_vac_init;
v_vac_usrflush = ross_noasi_vac_usrflush;
v_vac_ctxflush = ross_noasi_vac_ctxflush;
v_vac_rgnflush = ross_noasi_vac_rgnflush;
v_vac_segflush = ross_noasi_vac_segflush;
v_vac_pageflush = ross_noasi_vac_pageflush;
v_vac_pagectxflush = ross_noasi_vac_pagectxflush;
v_vac_flush = ross_noasi_vac_flush;
}
#endif ROSS_NOASI
#include <machine/vm_hat.h>
#include <vm/as.h>
/*
* ross_pte_offon: change some bits in a specified pte,
* keeping the VAC and TLB consistant.
*
* This is the bottom level of manipulation for PTEs,
* and it knows all the right things to do to flush
* all the right caches. Further, it is safe in the face
* of an MMU doing a read-modify-write cycle to set
* the REF or MOD bits.
*/
unsigned
ross_pte_offon(ptpe, aval, oval)
union ptpe *ptpe;
unsigned aval;
unsigned oval;
{
unsigned rpte;
unsigned wpte;
unsigned *ppte;
struct pte *pte;
addr_t vaddr;
struct ptbl *ptbl;
struct as *as;
struct ctx *ctx;
u_int cno;
/*
* If the ptpe address is NULL, we have nothing to do.
*/
if (!ptpe)
return 0;
ppte = &ptpe->ptpe_int;
rpte = *ppte;
wpte = (rpte & ~aval) | oval;
/*
* Early Exit Options: If no change, just return.
*/
if (wpte == rpte)
return rpte;
/*
* Fast Update Options: If the old PTE was not valid,
* then no flush is needed: update and return.
*/
if ((rpte & PTE_ETYPEMASK) != MMU_ET_PTE)
return ross_pte_rmw(ppte, aval, oval);
pte = &ptpe->pte;
ptbl = ptetoptbl(pte);
vaddr = ptetovaddr(pte);
/*
* Decide which context this mapping
* is active inside. If the vaddr is a
* kernel address, force context zero;
* otherwise, peel the address space and
* context used by the ptbl.
*
* Fast Update Option:
* If there is no address space or
* there is no context, then this
* mapping must not be active, so
* we just update and return.
*/
if ((unsigned)vaddr >= (unsigned)KERNELBASE)
cno = 0;
else if (((as = ptbl->ptbl_as) == NULL) ||
((ctx = as->a_hat.hat_ctx) == NULL))
return ross_pte_rmw(ppte, aval, oval);
else
cno = ctx->c_num;
/*
* The Cy7C605 has this silly bug: if it takes a TLB hit on a
* translation that is clean while doing a write, and during
* the M-bit update cycle discovers that the PTE is invalid or
* unwritable, it keeps some "hidden state" that it needs to
* do an update cycle; on the next TLB walk, it writes
* whatever PTE it finds back after reading it, then does one
* junk request cycle to the MBus and sends trash back to the
* CPU. So, we can't allow any CPU to take a TLB hit on a
* valid writable clean TLB entry if the memory image of that
* PTE has been changed to be invalid or nonwritable.
*
* So, if the PTE starts out clean/valid/writable and we are
* invalidating or decreasing access, we must prevent the TLB
* hit by capturing the remote CPUs.
*
* XXX - for some reason, if we do not always capture, the
* system watchdogs on occasion. methinks there are more
* problems here than we thought.
*/
xc_attention();
rpte = ross_pte_rmw(ppte, aval, oval);
mmu_flushpagectx(vaddr, cno);
#ifdef VAC
#define REQUIRE_VAC_FLUSH (PTE_PFN_MASK|PTE_CE_MASK|PTE_ETYPEMASK)
if ((vac) && /* if using a VAC and */
(rpte & PTE_CE_MASK) && /* page was cacheable and */
((rpte & REQUIRE_VAC_FLUSH) != /* we changed physical page, */
(wpte & REQUIRE_VAC_FLUSH))) /* decached, or demapped, */
vac_pagectxflush (vaddr, cno); /* flush data from VAC */
#endif
xc_dismissed();
return rpte;
}
/*
* At this time no module specific workaround for ROSS
* Heh, Heh!!!
*/
void
ross_module_wkaround() {}