BSD 4_4 release
[unix-history] / usr / src / sys / sparc / sparc / cache.c
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)cache.c 8.1 (Berkeley) 7/19/93
*
* from: $Header: cache.c,v 1.10 93/07/18 06:23:51 torek Exp $ (LBL)
*/
/*
* Cache routines.
*
* TODO:
* - rework range flush
*/
#include <sys/param.h>
#include <machine/ctlreg.h>
#include <machine/pte.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/cache.h>
enum vactype vactype;
struct cachestats cachestats;
/*
* Enable the cache.
* We need to clear out the valid bits first.
*/
void
cache_enable()
{
register u_int i, lim, ls;
i = AC_CACHETAGS;
lim = i + cacheinfo.c_totalsize;
ls = cacheinfo.c_linesize;
for (; i < lim; i += ls)
sta(i, ASI_CONTROL, 0);
stba(AC_SYSENABLE, ASI_CONTROL,
lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_CACHE);
cacheinfo.c_enabled = 1;
printf("cache enabled\n");
}
/*
* Flush the current context from the cache.
*
* This is done by writing to each cache line in the `flush context'
* address space (or, for hardware flush, once to each page in the
* hardware flush space, for all cache pages).
*/
void
cache_flush_context()
{
register char *p;
register int i, ls;
cachestats.cs_ncxflush++;
p = (char *)0; /* addresses 0..cacheinfo.c_totalsize will do fine */
if (cacheinfo.c_hwflush) {
ls = NBPG;
i = cacheinfo.c_totalsize >> PGSHIFT;
for (; --i >= 0; p += ls)
sta(p, ASI_HWFLUSHCTX, 0);
} else {
ls = cacheinfo.c_linesize;
i = cacheinfo.c_totalsize >> cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
sta(p, ASI_FLUSHCTX, 0);
}
}
/*
* Flush the given virtual segment from the cache.
*
* This is also done by writing to each cache line, except that
* now the addresses must include the virtual segment number, and
* we use the `flush segment' space.
*
* Again, for hardware, we just write each page (in hw-flush space).
*/
void
cache_flush_segment(vseg)
register int vseg;
{
register int i, ls;
register char *p;
cachestats.cs_nsgflush++;
p = (char *)VSTOVA(vseg); /* seg..seg+sz rather than 0..sz */
if (cacheinfo.c_hwflush) {
ls = NBPG;
i = cacheinfo.c_totalsize >> PGSHIFT;
for (; --i >= 0; p += ls)
sta(p, ASI_HWFLUSHSEG, 0);
} else {
ls = cacheinfo.c_linesize;
i = cacheinfo.c_totalsize >> cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
sta(p, ASI_FLUSHSEG, 0);
}
}
/*
* Flush the given virtual page from the cache.
* (va is the actual address, and must be aligned on a page boundary.)
* Again we write to each cache line.
*/
void
cache_flush_page(va)
int va;
{
register int i, ls;
register char *p;
cachestats.cs_npgflush++;
p = (char *)va;
if (cacheinfo.c_hwflush)
sta(p, ASI_HWFLUSHPG, 0);
else {
ls = cacheinfo.c_linesize;
i = NBPG >> cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
sta(p, ASI_FLUSHPG, 0);
}
}
/*
* Flush a range of virtual addresses (in the current context).
* The first byte is at (base&~PGOFSET) and the last one is just
* before byte (base+len).
*
* We choose the best of (context,segment,page) here.
*/
void
cache_flush(base, len)
caddr_t base;
register u_int len;
{
register int i, ls, baseoff;
register char *p;
/*
* Figure out how much must be flushed.
*
* If we need to do 16 pages, we can do a segment in the same
* number of loop iterations. We can also do the context. If
* we would need to do two segments, do the whole context.
* This might not be ideal (e.g., fsck likes to do 65536-byte
* reads, which might not necessarily be aligned).
*
* We could try to be sneaky here and use the direct mapping
* to avoid flushing things `below' the start and `above' the
* ending address (rather than rounding to whole pages and
* segments), but I did not want to debug that now and it is
* not clear it would help much.
*
* (XXX the magic number 16 is now wrong, must review policy)
*/
baseoff = (int)base & PGOFSET;
i = (baseoff + len + PGOFSET) >> PGSHIFT;
cachestats.cs_nraflush++;
#ifdef notyet
cachestats.cs_ra[min(i, MAXCACHERANGE)]++;
#endif
if (i <= 15) {
/* cache_flush_page, for i pages */
p = (char *)((int)base & ~baseoff);
if (cacheinfo.c_hwflush) {
for (; --i >= 0; p += NBPG)
sta(p, ASI_HWFLUSHPG, 0);
} else {
ls = cacheinfo.c_linesize;
i <<= PGSHIFT - cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
sta(p, ASI_FLUSHPG, 0);
}
return;
}
baseoff = (u_int)base & SGOFSET;
i = (baseoff + len + SGOFSET) >> SGSHIFT;
if (i == 1)
cache_flush_segment(VA_VSEG(base));
else
cache_flush_context();
}