1 /* $NetBSD: cache_r10k.c,v 1.8 2016/07/13 21:25:15 macallan Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 Takao Shinohara. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /* 28 * Copyright 2001 Wasabi Systems, Inc. 29 * All rights reserved. 30 * 31 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. All advertising materials mentioning features or use of this software 42 * must display the following acknowledgement: 43 * This product includes software developed for the NetBSD Project by 44 * Wasabi Systems, Inc. 45 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 46 * or promote products derived from this software without specific prior 47 * written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 51 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 53 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 * POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62 #include <sys/param.h> 63 64 #include <mips/cpuregs.h> 65 #include <mips/cache.h> 66 #include <mips/cache_r4k.h> 67 #include <mips/cache_r10k.h> 68 69 /* 70 * Cache operations for R10000-style caches: 71 * 72 * 2-way, write-back 73 * primary cache: virtual index/physical tag 74 * secondary cache: physical index/physical tag 75 */ 76 77 __asm(".set mips3"); 78 79 #define round_line(x) (((x) + 64 - 1) & ~(64 - 1)) 80 #define trunc_line(x) ((x) & ~(64 - 1)) 81 82 void 83 r10k_icache_sync_all(void) 84 { 85 const struct mips_cache_info * const mci = &mips_cache_info; 86 vaddr_t va = MIPS_PHYS_TO_KSEG0(0); 87 vaddr_t eva = va + mci->mci_picache_way_size; 88 89 mips_dcache_wbinv_all(); 90 91 __asm volatile("sync"); 92 93 while (va < eva) { 94 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); 95 va++; 96 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); 97 va += 63; 98 } 99 } 100 101 void 102 r10k_icache_sync_range(register_t va, vsize_t size) 103 { 104 vaddr_t eva = round_line(va + size); 105 106 va = trunc_line(va); 107 108 mips_dcache_wb_range(va, (eva - va)); 109 110 __asm volatile("sync"); 111 112 while (va < eva) { 113 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); 114 va += 64; 115 } 116 } 117 118 void 119 r10k_icache_sync_range_index(vaddr_t va, vsize_t size) 120 { 121 const struct mips_cache_info * const mci = &mips_cache_info; 122 vaddr_t eva, orig_va; 123 124 orig_va = va; 125 126 eva = round_line(va + size); 127 va = trunc_line(va); 128 129 mips_dcache_wbinv_range_index(va, (eva - va)); 130 131 __asm volatile("sync"); 132 133 /* 134 * Since we're doing Index ops, we expect to not be able 135 * to access the address we've been given. So, get the 136 * bits that determine the cache index, and make a KSEG0 137 * address out of them. 138 */ 139 va = MIPS_PHYS_TO_KSEG0(orig_va & mci->mci_picache_way_mask); 140 141 eva = round_line(va + size); 142 va = trunc_line(va); 143 144 while (va < eva) { 145 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); 146 va++; 147 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); 148 va += 63; 149 } 150 } 151 152 #undef round_line 153 #undef trunc_line 154 155 #define round_line(x) (((x) + 32 - 1) & ~(32 - 1)) 156 #define trunc_line(x) ((x) & ~(32 - 1)) 157 158 void 159 r10k_pdcache_wbinv_all(void) 160 { 161 const struct mips_cache_info * const mci = &mips_cache_info; 162 vaddr_t va = MIPS_PHYS_TO_KSEG0(0); 163 vaddr_t eva = va + mci->mci_pdcache_way_size; 164 165 while (va < eva) { 166 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); 167 va++; 168 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); 169 va += 31; 170 } 171 } 172 173 void 174 r10k_pdcache_wbinv_range(register_t va, vsize_t size) 175 { 176 vaddr_t eva = round_line(va + size); 177 178 va = trunc_line(va); 179 180 while (va < eva) { 181 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); 182 va += 32; 183 } 184 } 185 186 void 187 r10k_pdcache_wbinv_range_index(vaddr_t va, vsize_t size) 188 { 189 const struct mips_cache_info * const mci = &mips_cache_info; 190 vaddr_t eva; 191 192 /* 193 * Since we're doing Index ops, we expect to not be able 194 * to access the address we've been given. So, get the 195 * bits that determine the cache index, and make a KSEG0 196 * address out of them. 197 */ 198 va = MIPS_PHYS_TO_KSEG0(va & mci->mci_pdcache_way_mask); 199 200 eva = round_line(va + size); 201 va = trunc_line(va); 202 203 while (va < eva) { 204 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); 205 va++; 206 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); 207 va += 31; 208 } 209 } 210 211 void 212 r10k_pdcache_inv_range(register_t va, vsize_t size) 213 { 214 vaddr_t eva = round_line(va + size); 215 216 va = trunc_line(va); 217 218 while (va < eva) { 219 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); 220 va += 32; 221 } 222 } 223 224 void 225 r10k_pdcache_wb_range(register_t va, vsize_t size) 226 { 227 vaddr_t eva = round_line(va + size); 228 229 va = trunc_line(va); 230 231 while (va < eva) { 232 /* R10000 does not support HitWriteBack operation */ 233 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); 234 va += 32; 235 } 236 } 237 238 #undef round_line 239 #undef trunc_line 240 241 #define round_line(x) (((x) + mci->mci_sdcache_line_size - 1) & ~(mci->mci_sdcache_line_size - 1)) 242 #define trunc_line(x) ((x) & ~(mci->mci_sdcache_line_size - 1)) 243 244 void 245 r10k_sdcache_wbinv_all(void) 246 { 247 const struct mips_cache_info * const mci = &mips_cache_info; 248 vaddr_t va = MIPS_PHYS_TO_KSEG0(0); 249 vaddr_t eva = va + mci->mci_sdcache_way_size; 250 vsize_t line_size = mci->mci_sdcache_line_size; 251 252 while (va < eva) { 253 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); 254 va++; 255 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); 256 va += line_size - 1; 257 } 258 } 259 260 void 261 r10k_sdcache_wbinv_range(register_t va, vsize_t size) 262 { 263 const struct mips_cache_info * const mci = &mips_cache_info; 264 vaddr_t eva = round_line(va + size); 265 vsize_t line_size = mci->mci_sdcache_line_size; 266 267 va = trunc_line(va); 268 269 while (va < eva) { 270 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); 271 va += line_size; 272 } 273 } 274 275 void 276 r10k_sdcache_wbinv_range_index(vaddr_t va, vsize_t size) 277 { 278 const struct mips_cache_info * const mci = &mips_cache_info; 279 vaddr_t eva; 280 vsize_t line_size = mci->mci_sdcache_line_size; 281 282 /* 283 * Since we're doing Index ops, we expect to not be able 284 * to access the address we've been given. So, get the 285 * bits that determine the cache index, and make a KSEG0 286 * address out of them. 287 */ 288 va = MIPS_PHYS_TO_KSEG0(va & mci->mci_sdcache_way_mask); 289 290 eva = round_line(va + size); 291 va = trunc_line(va); 292 293 while (va < eva) { 294 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); 295 va++; 296 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); 297 va += line_size - 1; 298 } 299 } 300 301 void 302 r10k_sdcache_inv_range(register_t va, vsize_t size) 303 { 304 const struct mips_cache_info * const mci = &mips_cache_info; 305 vaddr_t eva = round_line(va + size); 306 vsize_t line_size = mci->mci_sdcache_line_size; 307 308 va = trunc_line(va); 309 310 while (va < eva) { 311 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); 312 va += line_size; 313 } 314 } 315 316 void 317 r10k_sdcache_wb_range(register_t va, vsize_t size) 318 { 319 const struct mips_cache_info * const mci = &mips_cache_info; 320 vaddr_t eva = round_line(va + size); 321 vsize_t line_size = mci->mci_sdcache_line_size; 322 323 va = trunc_line(va); 324 325 while (va < eva) { 326 /* R10000 does not support HitWriteBack operation */ 327 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); 328 va += line_size; 329 } 330 } 331 332 #undef round_line 333 #undef trunc_line 334