xref: /original-bsd/sys/sparc/sparc/cache.c (revision e0851aa6)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * All advertising materials mentioning features or use of this software
10  * must display the following acknowledgement:
11  *	This product includes software developed by the University of
12  *	California, Lawrence Berkeley Laboratories.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)cache.c	7.3 (Berkeley) 10/11/92
17  *
18  * from: $Header: cache.c,v 1.5 92/06/17 05:21:56 torek Exp $ (LBL)
19  */
20 
21 /*
22  * Cache routines.
23  */
24 
25 #include <sys/param.h>
26 
27 #include <machine/pte.h>
28 
29 #include <sparc/sparc/asm.h>
30 #include <sparc/sparc/cache.h>
31 #include <sparc/sparc/ctlreg.h>
32 
33 enum vactype vactype;
34 
35 /*
36  * Enable the cache.
37  * We need to clear out the valid bits first.
38  */
39 void
40 cache_enable()
41 {
42 	register int i;
43 
44 	for (i = AC_CACHETAGS; i < AC_CACHETAGS + 4096 * 4; i += 4)
45 		sta(i, ASI_CONTROL, 0);
46 
47 	vactype = VAC_WRITETHROUGH;		/* XXX must be set per cpu */
48 	stba(AC_SYSENABLE, ASI_CONTROL,
49 	    lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_CACHE);
50 	printf("cache enabled\n");
51 }
52 
53 
54 /*
55  * Flush the current context from the cache.
56  *
57  * This is done by writing to each cache line in the `flush context'
58  * address space.  Cache lines are 16 bytes, hence the declaration of `p'.
59  */
60 void
61 cache_flush_context()
62 {
63 	register int i;
64 	register char (*p)[16];
65 
66 	p = 0;
67 	for (i = 0x1000; --i >= 0; p++)
68 		sta(p, ASI_FLUSHCTX, 0);
69 }
70 
71 /*
72  * Flush the given virtual segment from the cache.
73  *
74  * This is also done by writing to each cache line, except that
75  * now the addresses must include the virtual segment number, and
76  * we use the `flush segment' space.
77  */
78 void
79 cache_flush_segment(vseg)
80 	register int vseg;
81 {
82 	register int i;
83 	register char (*p)[16];
84 
85 	p = (char (*)[16])VSTOVA(vseg);
86 	for (i = 0x1000; --i >= 0; p++)
87 		sta(p, ASI_FLUSHSEG, 0);
88 }
89 
90 /*
91  * Flush the given virtual page from the cache.
92  * (va is the actual address, and must be aligned on a page boundary.)
93  * Again we write to each cache line.
94  */
95 void
96 cache_flush_page(va)
97 	int va;
98 {
99 	register int i;
100 	register char (*p)[16];
101 
102 	p = (char (*)[16])va;
103 	for (i = NBPG >> 4; --i >= 0; p++)
104 		sta(p, ASI_FLUSHPG, 0);
105 }
106 
107 /*
108  * Flush a range of virtual addresses (in the current context).
109  * The first byte is at (base&~PGOFSET) and the last one is just
110  * before byte (base+len).
111  *
112  * We choose the best of (context,segment,page) here.
113  */
114 void
115 cache_flush(base, len)
116 	caddr_t base;
117 	register u_int len;
118 {
119 	register int i, baseoff;
120 	register char (*p)[16];
121 
122 	/*
123 	 * Figure out how much must be flushed.
124 	 *
125 	 * If we need to do 16 pages, we can do a segment in the same
126 	 * number of loop iterations.  We can also do the context.  If
127 	 * we would need to do two segments, do the whole context.
128 	 * This might not be ideal (e.g., fsck likes to do 65536-byte
129 	 * reads, which might not necessarily be aligned).
130 	 *
131 	 * We could try to be sneaky here and use the direct mapping
132 	 * to avoid flushing things `below' the start and `above' the
133 	 * ending address (rather than rounding to whole pages and
134 	 * segments), but I did not want to debug that now and it is
135 	 * not clear it would help much.
136 	 */
137 	baseoff = (int)base & PGOFSET;
138 	i = (baseoff + len + PGOFSET) >> PGSHIFT;
139 	if (i <= 15) {
140 		/* cache_flush_page, for i pages */
141 		p = (char (*)[16])((int)base & ~baseoff);
142 		for (i <<= PGSHIFT - 4; --i >= 0; p++)
143 			sta(p, ASI_FLUSHPG, 0);
144 		return;
145 	}
146 	baseoff = (u_int)base & SGOFSET;
147 	i = (baseoff + len + SGOFSET) >> SGSHIFT;
148 	if (i == 1) {
149 		/* cache_flush_segment */
150 		p = (char (*)[16])((int)base & ~baseoff);
151 		for (i = 0x1000; --i >= 0; p++)
152 			sta(p, ASI_FLUSHSEG, 0);
153 		return;
154 	}
155 	/* cache_flush_context */
156 	p = 0;
157 	for (i = 0x1000; --i >= 0; p++)
158 		sta(p, ASI_FLUSHCTX, 0);
159 }
160