1 /* $NetBSD: cache_ls2.c,v 1.5 2016/07/11 16:15:36 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas <matt (at) 3am-software.com>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: cache_ls2.c,v 1.5 2016/07/11 16:15:36 matt Exp $"); 34 35 #include <sys/param.h> 36 37 #include <mips/cache.h> 38 #include <mips/cache_ls2.h> 39 #include <mips/locore.h> 40 41 /* 42 * Cache operations for Loongson2-style caches: 43 * 44 * - 4-way set-associative 32b/l 45 * - Write-back 46 * - Primary is virtually indexed, physically tagged 47 * - Seconadry is physically indexed, physically tagged 48 */ 49 50 #define round_line(x) (((x) + 31) & ~31) 51 #define trunc_line(x) ((x) & ~31) 52 53 __asm(".set mips3"); 54 55 void 56 ls2_icache_sync_range(register_t va, vsize_t size) 57 { 58 struct mips_cache_info * const mci = &mips_cache_info; 59 const vaddr_t eva = round_line(va + size); 60 61 va = trunc_line(va); 62 63 if (va + mci->mci_picache_size <= eva) { 64 ls2_icache_sync_all(); 65 return; 66 } 67 68 for (; va + 8 * 32 <= eva; va += 8 * 32) { 69 cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_WB_INV); 70 cache_op_ls2_8line(va, CACHEOP_LS2_I_INDEX_INV); 71 } 72 73 for (; va < eva; va += 32) { 74 cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_WB_INV); 75 cache_op_ls2_line(va, CACHEOP_LS2_I_INDEX_INV); 76 } 77 78 __asm volatile("sync"); 79 } 80 81 void 82 ls2_icache_sync_range_index(vaddr_t va, vsize_t size) 83 { 84 vaddr_t eva; 85 struct mips_cache_info * const mci = &mips_cache_info; 86 87 /* 88 * Since we're doing Index ops, we expect to not be able 89 * to access the address we've been given. So, get the 90 * bits that determine the cache index, and make a KSEG0 91 * address out of them. 92 */ 93 94 va = MIPS_PHYS_TO_KSEG0(va & mci->mci_picache_way_mask); 95 eva = round_line(va + size); 96 va = trunc_line(va); 97 98 if (va + mci->mci_picache_way_size < eva) { 99 va = MIPS_PHYS_TO_KSEG0(0); 100 eva = mci->mci_picache_way_size; 101 } 102 103 for (; va + 8 * 32 <= eva; va += 8 * 32) { 104 cache_op_ls2_8line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV); 105 cache_op_ls2_8line(va, CACHEOP_LS2_I_INDEX_INV); 106 } 107 108 for (; va < eva; va += 32) { 109 cache_op_ls2_line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV); 110 cache_op_ls2_line(va, CACHEOP_LS2_I_INDEX_INV); 111 } 112 113 __asm volatile("sync"); 114 } 115 116 void 117 ls2_icache_sync_all(void) 118 { 119 struct mips_cache_info * const mci = &mips_cache_info; 120 ls2_icache_sync_range_index(0, mci->mci_picache_way_size); 121 } 122 123 void 124 ls2_pdcache_inv_range(register_t va, vsize_t size) 125 { 126 const vaddr_t eva = round_line(va + size); 127 128 va = trunc_line(va); 129 130 for (; va + 8 * 32 <= eva; va += 8 * 32) { 131 cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_INV); 132 } 133 134 for (; va < eva; va += 32) { 135 cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_INV); 136 } 137 138 __asm volatile("sync"); 139 } 140 141 void 142 ls2_pdcache_wbinv_range(register_t va, vsize_t size) 143 { 144 const vaddr_t eva = round_line(va + size); 145 146 va = trunc_line(va); 147 148 for (; va + 8 * 32 <= eva; va += 8 * 32) { 149 cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_WB_INV); 150 } 151 152 for (; va < eva; va += 32) { 153 cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_WB_INV); 154 } 155 156 __asm volatile("sync"); 157 } 158 159 void 160 ls2_pdcache_wb_range(register_t va, vsize_t size) 161 { 162 /* 163 * Alas, can't writeback without invalidating... 164 */ 165 ls2_pdcache_wbinv_range(va, size); 166 } 167 168 void 169 ls2_pdcache_wbinv_range_index(vaddr_t va, vsize_t size) 170 { 171 vaddr_t eva; 172 struct mips_cache_info * const mci = &mips_cache_info; 173 174 /* 175 * Since we're doing Index ops, we expect to not be able 176 * to access the address we've been given. So, get the 177 * bits that determine the cache index, and make a KSEG0 178 * address out of them. 179 */ 180 va = MIPS_PHYS_TO_KSEG0(va & mci->mci_pdcache_way_mask); 181 182 eva = round_line(va + size); 183 va = trunc_line(va); 184 185 if (va + mci->mci_pdcache_way_size > eva) { 186 va = MIPS_PHYS_TO_KSEG0(0); 187 eva = mci->mci_pdcache_way_size; 188 } 189 190 for (; va + 8 * 32 <= eva; va += 8 * 32) { 191 cache_op_ls2_8line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV); 192 } 193 194 for (; va < eva; va += 32) { 195 cache_op_ls2_line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV); 196 } 197 198 __asm volatile("sync"); 199 } 200 201 void 202 ls2_pdcache_wbinv_all(void) 203 { 204 struct mips_cache_info * const mci = &mips_cache_info; 205 ls2_pdcache_wbinv_range_index(0, mci->mci_pdcache_way_size); 206 } 207 208 /* 209 * Cache operations for secondary caches: 210 * 211 * - Direct-mapped 212 * - Write-back 213 * - Physically indexed, physically tagged 214 * 215 */ 216 217 void 218 ls2_sdcache_inv_range(register_t va, vsize_t size) 219 { 220 const vaddr_t eva = round_line(va + size); 221 222 va = trunc_line(va); 223 224 for (; va + 8 * 32 <= eva; va += 8 * 32) { 225 cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_INV); 226 cache_op_ls2_8line(va, CACHEOP_LS2_S_HIT_INV); 227 } 228 229 for (; va < eva; va += 32) { 230 cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_INV); 231 cache_op_ls2_line(va, CACHEOP_LS2_S_HIT_INV); 232 } 233 234 __asm volatile("sync"); 235 } 236 237 void 238 ls2_sdcache_wbinv_range(register_t va, vsize_t size) 239 { 240 const vaddr_t eva = round_line(va + size); 241 242 va = trunc_line(va); 243 244 for (; va + 8 * 32 <= eva; va += 8 * 32) { 245 cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_WB_INV); 246 cache_op_ls2_8line(va, CACHEOP_LS2_S_HIT_WB_INV); 247 } 248 249 for (; va < eva; va += 32) { 250 cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_WB_INV); 251 cache_op_ls2_line(va, CACHEOP_LS2_S_HIT_WB_INV); 252 } 253 254 __asm volatile("sync"); 255 } 256 257 void 258 ls2_sdcache_wb_range(register_t va, vsize_t size) 259 { 260 /* 261 * Alas, can't writeback without invalidating... 262 */ 263 ls2_sdcache_wbinv_range(va, size); 264 } 265 266 void 267 ls2_sdcache_wbinv_range_index(vaddr_t va, vsize_t size) 268 { 269 vaddr_t eva; 270 struct mips_cache_info * const mci = &mips_cache_info; 271 272 /* 273 * Since we're doing Index ops, we expect to not be able 274 * to access the address we've been given. So, get the 275 * bits that determine the cache index, and make a KSEG0 276 * address out of them. 277 */ 278 va = MIPS_PHYS_TO_KSEG0(va & mci->mci_sdcache_way_mask); 279 280 eva = round_line(va + size); 281 va = trunc_line(va); 282 283 if (va + mci->mci_sdcache_way_size > eva) { 284 va = MIPS_PHYS_TO_KSEG0(0); 285 eva = va + mci->mci_sdcache_way_size; 286 } 287 288 for (; va + 8 * 32 <= eva; va += 8 * 32) { 289 cache_op_ls2_8line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV); 290 cache_op_ls2_8line_4way(va, CACHEOP_LS2_S_INDEX_WB_INV); 291 } 292 293 for (; va < eva; va += 32) { 294 cache_op_ls2_line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV); 295 cache_op_ls2_line_4way(va, CACHEOP_LS2_S_INDEX_WB_INV); 296 } 297 298 __asm volatile("sync"); 299 } 300 301 void 302 ls2_sdcache_wbinv_all(void) 303 { 304 struct mips_cache_info * const mci = &mips_cache_info; 305 ls2_sdcache_wbinv_range_index(0, mci->mci_sdcache_way_size); 306 } 307