1 /* $OpenBSD: cache_octeon.c,v 1.13 2018/12/04 16:24:13 visa Exp $ */ 2 /* 3 * Copyright (c) 2010 Takuya ASADA. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 /* 18 * Copyright (c) 1998-2004 Opsycon AB (www.opsycon.se) 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 30 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 33 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <mips64/cache.h> 50 #include <machine/cpu.h> 51 52 #define SYNCI() \ 53 asm volatile( \ 54 ".set push\n" \ 55 ".set mips64r2\n" \ 56 ".word 0x041f0000\n" \ 57 "nop\n" \ 58 ".set pop") 59 60 void 61 Octeon_ConfigCache(struct cpu_info *ci) 62 { 63 uint32_t cfg; 64 uint32_t s, l, a; 65 66 switch (ci->ci_hw.type) { 67 default: 68 /* OCTEON and OCTEON Plus */ 69 70 cfg = cp0_get_config_1(); 71 72 /* 73 * Octeon L1 cache information does not follow the mips64 74 * standard encoding. 75 */ 76 77 a = (cfg >> 16) & 0x07; 78 l = (cfg >> 19) & 0x07; 79 s = (cfg >> 22) & 0x07; 80 ci->ci_l1inst.linesize = 2 << l; 81 ci->ci_l1inst.setsize = (64 << s) * ci->ci_l1inst.linesize; 82 if (a >= 1) 83 ci->ci_l1inst.sets = 1 << (a - 1); 84 else 85 ci->ci_l1inst.sets = 1; 86 ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize; 87 88 ci->ci_l1data.linesize = 128; 89 ci->ci_l1data.setsize = 2 * 128; 90 ci->ci_l1data.sets = 64; 91 ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize; 92 93 break; 94 95 case MIPS_CN61XX: 96 case MIPS_CN63XX: 97 case MIPS_CN66XX: 98 case MIPS_CN68XX: 99 /* OCTEON II */ 100 101 ci->ci_l1inst.linesize = 128; 102 ci->ci_l1inst.setsize = 8 * 128; 103 ci->ci_l1inst.sets = 37; 104 ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize; 105 106 ci->ci_l1data.linesize = 128; 107 ci->ci_l1data.setsize = 8 * 128; 108 ci->ci_l1data.sets = 32; 109 ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize; 110 111 break; 112 113 case MIPS_CN71XX: 114 case MIPS_CN73XX: 115 case MIPS_CN78XX: 116 /* OCTEON III */ 117 118 ci->ci_l1inst.linesize = 128; 119 ci->ci_l1inst.setsize = 16 * 128; 120 ci->ci_l1inst.sets = 39; 121 ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize; 122 123 ci->ci_l1data.linesize = 128; 124 ci->ci_l1data.setsize = 8 * 128; 125 ci->ci_l1data.sets = 32; 126 ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize; 127 128 break; 129 } 130 131 cfg = cp0_get_config_2(); 132 133 a = 1 + ((cfg >> 0) & 0x0f); 134 l = (cfg >> 4) & 0x0f; 135 s = (cfg >> 8) & 0x0f; 136 137 ci->ci_l2.linesize = 2 << l; 138 ci->ci_l2.sets = a; 139 ci->ci_l2.setsize = (64 << s) * ci->ci_l2.linesize; 140 ci->ci_l2.size = ci->ci_l2.sets * ci->ci_l2.setsize; 141 142 memset(&ci->ci_l3, 0, sizeof(struct cache_info)); 143 144 ci->ci_SyncCache = Octeon_SyncCache; 145 ci->ci_InvalidateICache = Octeon_InvalidateICache; 146 ci->ci_InvalidateICachePage = Octeon_InvalidateICachePage; 147 ci->ci_SyncICache = Octeon_SyncICache; 148 ci->ci_SyncDCachePage = Octeon_SyncDCachePage; 149 ci->ci_HitSyncDCachePage = Octeon_SyncDCachePage; 150 ci->ci_HitSyncDCache = Octeon_HitSyncDCache; 151 ci->ci_HitInvalidateDCache = Octeon_HitInvalidateDCache; 152 ci->ci_IOSyncDCache = Octeon_IOSyncDCache; 153 } 154 155 void 156 Octeon_SyncCache(struct cpu_info *ci) 157 { 158 mips_sync(); 159 } 160 161 void 162 Octeon_InvalidateICache(struct cpu_info *ci, vaddr_t va, size_t len) 163 { 164 /* A SYNCI flushes the entire icache on OCTEON */ 165 SYNCI(); 166 } 167 168 /* 169 * Register a given page for I$ invalidation. 170 */ 171 void 172 Octeon_InvalidateICachePage(struct cpu_info *ci, vaddr_t va) 173 { 174 /* 175 * Since there is apparently no way to operate on a subset of I$, 176 * all we need to do here is remember there are postponed flushes. 177 */ 178 ci->ci_cachepending_l1i = 1; 179 } 180 181 /* 182 * Perform postponed I$ invalidation. 183 */ 184 void 185 Octeon_SyncICache(struct cpu_info *ci) 186 { 187 if (ci->ci_cachepending_l1i != 0) { 188 SYNCI(); /* Octeon_InvalidateICache(ci, 0, PAGE_SIZE); */ 189 ci->ci_cachepending_l1i = 0; 190 } 191 } 192 193 void 194 Octeon_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) 195 { 196 } 197 198 void 199 Octeon_HitSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len) 200 { 201 } 202 203 void 204 Octeon_HitInvalidateDCache(struct cpu_info *ci, vaddr_t va, size_t len) 205 { 206 } 207 208 void 209 Octeon_IOSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len, int how) 210 { 211 switch (how) { 212 default: 213 case CACHE_SYNC_R: 214 break; 215 case CACHE_SYNC_W: /* writeback */ 216 case CACHE_SYNC_X: /* writeback and invalidate */ 217 mips_sync(); 218 break; 219 } 220 } 221 222 void 223 Octeon_lock_secondary_cache(struct cpu_info *ci, paddr_t _pa, size_t _sz) 224 { 225 size_t linesize = ci->ci_l2.linesize; 226 size_t sz; 227 paddr_t pa; 228 vaddr_t end, va; 229 230 pa = _pa & ~(linesize - 1); 231 sz = ((_pa + _sz + linesize - 1) & ~(linesize - 1)) - pa; 232 233 va = PHYS_TO_XKPHYS(pa, 0ul); 234 end = va + sz; 235 while (va < end) { 236 asm volatile ("cache 31, (%0)" : : "r" (va)); 237 va += linesize; 238 } 239 240 /* Wait for the lock operations to finish. */ 241 mips_sync(); 242 } 243 244 void 245 Octeon_unlock_secondary_cache(struct cpu_info *ci, paddr_t _pa, size_t _sz) 246 { 247 size_t linesize = ci->ci_l2.linesize; 248 size_t sz; 249 paddr_t pa; 250 vaddr_t end, va; 251 252 pa = _pa & ~(linesize - 1); 253 sz = ((_pa + _sz + linesize - 1) & ~(linesize - 1)) - pa; 254 255 va = PHYS_TO_XKPHYS(pa, 0ul); 256 end = va + sz; 257 while (va < end) { 258 asm volatile ("cache 23, (%0)" : : "r" (va)); 259 va += linesize; 260 } 261 } 262