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