1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. 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 Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)cache.c 8.2 (Berkeley) 10/30/93 17 * 18 * from: $Header: cache.c,v 1.12 93/10/31 05:27:47 torek Exp $ (LBL) 19 */ 20 21 /* 22 * Cache routines. 23 * 24 * TODO: 25 * - rework range flush 26 */ 27 28 #include <sys/param.h> 29 30 #include <machine/ctlreg.h> 31 #include <machine/pte.h> 32 33 #include <sparc/sparc/asm.h> 34 #include <sparc/sparc/cache.h> 35 36 enum vactype vactype; 37 struct cachestats cachestats; 38 39 /* 40 * Enable the cache. 41 * We need to clear out the valid bits first. 42 */ 43 void 44 cache_enable() 45 { 46 register u_int i, lim, ls, ts; 47 48 ls = cacheinfo.c_linesize; 49 ts = cacheinfo.c_totalsize; 50 for (i = AC_CACHETAGS, lim = i + ts; i < lim; i += ls) 51 sta(i, ASI_CONTROL, 0); 52 53 stba(AC_SYSENABLE, ASI_CONTROL, 54 lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_CACHE); 55 cacheinfo.c_enabled = 1; 56 57 printf("%d byte (%d/line) write-through %cw flush cache enabled\n", 58 ts, ls, cacheinfo.c_hwflush ? 'h' : 's'); 59 } 60 61 62 /* 63 * Flush the current context from the cache. 64 * 65 * This is done by writing to each cache line in the `flush context' 66 * address space (or, for hardware flush, once to each page in the 67 * hardware flush space, for all cache pages). 68 */ 69 void 70 cache_flush_context() 71 { 72 register char *p; 73 register int i, ls; 74 75 cachestats.cs_ncxflush++; 76 p = (char *)0; /* addresses 0..cacheinfo.c_totalsize will do fine */ 77 if (cacheinfo.c_hwflush) { 78 ls = NBPG; 79 i = cacheinfo.c_totalsize >> PGSHIFT; 80 for (; --i >= 0; p += ls) 81 sta(p, ASI_HWFLUSHCTX, 0); 82 } else { 83 ls = cacheinfo.c_linesize; 84 i = cacheinfo.c_totalsize >> cacheinfo.c_l2linesize; 85 for (; --i >= 0; p += ls) 86 sta(p, ASI_FLUSHCTX, 0); 87 } 88 } 89 90 /* 91 * Flush the given virtual segment from the cache. 92 * 93 * This is also done by writing to each cache line, except that 94 * now the addresses must include the virtual segment number, and 95 * we use the `flush segment' space. 96 * 97 * Again, for hardware, we just write each page (in hw-flush space). 98 */ 99 void 100 cache_flush_segment(vseg) 101 register int vseg; 102 { 103 register int i, ls; 104 register char *p; 105 106 cachestats.cs_nsgflush++; 107 p = (char *)VSTOVA(vseg); /* seg..seg+sz rather than 0..sz */ 108 if (cacheinfo.c_hwflush) { 109 ls = NBPG; 110 i = cacheinfo.c_totalsize >> PGSHIFT; 111 for (; --i >= 0; p += ls) 112 sta(p, ASI_HWFLUSHSEG, 0); 113 } else { 114 ls = cacheinfo.c_linesize; 115 i = cacheinfo.c_totalsize >> cacheinfo.c_l2linesize; 116 for (; --i >= 0; p += ls) 117 sta(p, ASI_FLUSHSEG, 0); 118 } 119 } 120 121 /* 122 * Flush the given virtual page from the cache. 123 * (va is the actual address, and must be aligned on a page boundary.) 124 * Again we write to each cache line. 125 */ 126 void 127 cache_flush_page(va) 128 int va; 129 { 130 register int i, ls; 131 register char *p; 132 133 cachestats.cs_npgflush++; 134 p = (char *)va; 135 if (cacheinfo.c_hwflush) 136 sta(p, ASI_HWFLUSHPG, 0); 137 else { 138 ls = cacheinfo.c_linesize; 139 i = NBPG >> cacheinfo.c_l2linesize; 140 for (; --i >= 0; p += ls) 141 sta(p, ASI_FLUSHPG, 0); 142 } 143 } 144 145 /* 146 * Flush a range of virtual addresses (in the current context). 147 * The first byte is at (base&~PGOFSET) and the last one is just 148 * before byte (base+len). 149 * 150 * We choose the best of (context,segment,page) here. 151 */ 152 void 153 cache_flush(base, len) 154 caddr_t base; 155 register u_int len; 156 { 157 register int i, ls, baseoff; 158 register char *p; 159 160 /* 161 * Figure out how much must be flushed. 162 * 163 * If we need to do 16 pages, we can do a segment in the same 164 * number of loop iterations. We can also do the context. If 165 * we would need to do two segments, do the whole context. 166 * This might not be ideal (e.g., fsck likes to do 65536-byte 167 * reads, which might not necessarily be aligned). 168 * 169 * We could try to be sneaky here and use the direct mapping 170 * to avoid flushing things `below' the start and `above' the 171 * ending address (rather than rounding to whole pages and 172 * segments), but I did not want to debug that now and it is 173 * not clear it would help much. 174 * 175 * (XXX the magic number 16 is now wrong, must review policy) 176 */ 177 baseoff = (int)base & PGOFSET; 178 i = (baseoff + len + PGOFSET) >> PGSHIFT; 179 180 cachestats.cs_nraflush++; 181 #ifdef notyet 182 cachestats.cs_ra[min(i, MAXCACHERANGE)]++; 183 #endif 184 185 if (i <= 15) { 186 /* cache_flush_page, for i pages */ 187 p = (char *)((int)base & ~baseoff); 188 if (cacheinfo.c_hwflush) { 189 for (; --i >= 0; p += NBPG) 190 sta(p, ASI_HWFLUSHPG, 0); 191 } else { 192 ls = cacheinfo.c_linesize; 193 i <<= PGSHIFT - cacheinfo.c_l2linesize; 194 for (; --i >= 0; p += ls) 195 sta(p, ASI_FLUSHPG, 0); 196 } 197 return; 198 } 199 baseoff = (u_int)base & SGOFSET; 200 i = (baseoff + len + SGOFSET) >> SGSHIFT; 201 if (i == 1) 202 cache_flush_segment(VA_VSEG(base)); 203 else 204 cache_flush_context(); 205 } 206