386 lines
9.1 KiB
C
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() {}
|