1 /* $NetBSD: cache_mipsNN.c,v 1.16 2016/07/11 16:15:36 matt Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: cache_mipsNN.c,v 1.16 2016/07/11 16:15:36 matt Exp $"); 40 41 #include <sys/param.h> 42 43 #include <mips/locore.h> 44 #include <mips/cache.h> 45 #include <mips/cache_r4k.h> 46 #include <mips/cache_mipsNN.h> 47 #include <mips/mipsNN.h> 48 49 #include <uvm/uvm_extern.h> 50 51 #define round_line(x,n) (((x) + (n) - 1) & -(n)) 52 #define trunc_line(x,n) ((x) & -(n)) 53 54 void 55 mipsNN_cache_init(uint32_t config, uint32_t config1) 56 { 57 /* nothing to do */ 58 } 59 60 void 61 mipsNN_picache_sync_all(void) 62 { 63 struct mips_cache_info * const mci = &mips_cache_info; 64 65 /* 66 * Since we're hitting the whole thing, we don't have to 67 * worry about the N different "ways". 68 */ 69 mips_intern_dcache_sync_all(); 70 mips_intern_icache_sync_range_index(MIPS_KSEG0_START, 71 mci->mci_picache_size); 72 } 73 74 void 75 mipsNN_pdcache_wbinv_all(void) 76 { 77 struct mips_cache_info * const mci = &mips_cache_info; 78 79 /* 80 * Since we're hitting the whole thing, we don't have to 81 * worry about the N different "ways". 82 */ 83 mips_intern_pdcache_wbinv_range_index(MIPS_KSEG0_START, 84 mci->mci_pdcache_size); 85 } 86 87 void 88 mipsNN_sdcache_wbinv_all(void) 89 { 90 struct mips_cache_info * const mci = &mips_cache_info; 91 92 /* 93 * Since we're hitting the whole thing, we don't have to 94 * worry about the N different "ways". 95 */ 96 mips_intern_sdcache_wbinv_range_index(MIPS_KSEG0_START, 97 mci->mci_sdcache_size); 98 } 99 100 void 101 mipsNN_picache_sync_range(register_t va, vsize_t size) 102 { 103 104 mips_intern_dcache_sync_range(va, size); 105 mips_intern_icache_sync_range(va, size); 106 } 107 108 void 109 mipsNN_picache_sync_range_index(vaddr_t va, vsize_t size) 110 { 111 struct mips_cache_info * const mci = &mips_cache_info; 112 const size_t ways = mci->mci_picache_ways; 113 const size_t line_size = mci->mci_picache_line_size; 114 const size_t way_size = mci->mci_picache_way_size; 115 const size_t way_mask = way_size - 1; 116 vaddr_t eva; 117 118 /* 119 * Since we're doing Index ops, we expect to not be able 120 * to access the address we've been given. So, get the 121 * bits that determine the cache index, and make a KSEG0 122 * address out of them. 123 */ 124 va = MIPS_PHYS_TO_KSEG0(va & way_mask); 125 126 eva = round_line(va + size, line_size); 127 va = trunc_line(va, line_size); 128 size = eva - va; 129 130 /* 131 * If we are going to flush more than is in a way (or the stride 132 * need for that way), we are flushing everything. 133 */ 134 if (size >= way_size) { 135 mipsNN_picache_sync_all(); 136 return; 137 } 138 139 for (size_t way = 0; way < ways; way++) { 140 mips_intern_dcache_sync_range_index(va, size); 141 mips_intern_icache_sync_range_index(va, size); 142 va += way_size; 143 eva += way_size; 144 } 145 } 146 147 void 148 mipsNN_pdcache_wbinv_range_index(vaddr_t va, vsize_t size) 149 { 150 struct mips_cache_info * const mci = &mips_cache_info; 151 const size_t ways = mci->mci_pdcache_ways; 152 const size_t line_size = mci->mci_pdcache_line_size; 153 const vaddr_t way_size = mci->mci_pdcache_way_size; 154 const vaddr_t way_mask = way_size - 1; 155 vaddr_t eva; 156 157 /* 158 * Since we're doing Index ops, we expect to not be able 159 * to access the address we've been given. So, get the 160 * bits that determine the cache index, and make a KSEG0 161 * address out of them. 162 */ 163 va = MIPS_PHYS_TO_KSEG0(va & way_mask); 164 eva = round_line(va + size, line_size); 165 va = trunc_line(va, line_size); 166 size = eva - va; 167 168 /* 169 * If we are going to flush more than is in a way, we are flushing 170 * everything. 171 */ 172 if (size >= way_size) { 173 mips_intern_pdcache_wbinv_range_index(MIPS_KSEG0_START, 174 mci->mci_pdcache_size); 175 return; 176 } 177 178 /* 179 * Invalidate each way. If the address range wraps past the end of 180 * the way, we will be invalidating in two ways but eventually things 181 * work out since the last way will wrap into the first way. 182 */ 183 for (size_t way = 0; way < ways; way++) { 184 mips_intern_pdcache_wbinv_range_index(va, size); 185 va += way_size; 186 eva += way_size; 187 } 188 } 189 190 void 191 mipsNN_sdcache_wbinv_range_index(vaddr_t va, vsize_t size) 192 { 193 struct mips_cache_info * const mci = &mips_cache_info; 194 const size_t ways = mci->mci_sdcache_ways; 195 const size_t line_size = mci->mci_sdcache_line_size; 196 const vaddr_t way_size = mci->mci_sdcache_way_size; 197 const vaddr_t way_mask = way_size - 1; 198 vaddr_t eva; 199 200 /* 201 * Since we're doing Index ops, we expect to not be able 202 * to access the address we've been given. So, get the 203 * bits that determine the cache index, and make a KSEG0 204 * address out of them. 205 */ 206 va = MIPS_PHYS_TO_KSEG0(va & way_mask); 207 eva = round_line(va + size, line_size); 208 va = trunc_line(va, line_size); 209 size = eva - va; 210 211 /* 212 * If we are going to flush more than is in a way, we are flushing 213 * everything. 214 */ 215 if (size >= way_size) { 216 mips_intern_sdcache_wbinv_range_index(MIPS_KSEG0_START, 217 mci->mci_sdcache_size); 218 return; 219 } 220 221 /* 222 * Invalidate each way. If the address range wraps past the end of 223 * the way, we will be invalidating in two ways but eventually things 224 * work out since the last way will wrap into the first way. 225 */ 226 for (size_t way = 0; way < ways; way++) { 227 mips_intern_sdcache_wbinv_range_index(va, size); 228 va += way_size; 229 eva += way_size; 230 } 231 } 232