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 60void 61Octeon_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 155void 156Octeon_SyncCache(struct cpu_info *ci) 157{ 158 mips_sync(); 159} 160 161void 162Octeon_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 */ 171void 172Octeon_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 */ 184void 185Octeon_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 193void 194Octeon_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) 195{ 196} 197 198void 199Octeon_HitSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len) 200{ 201} 202 203void 204Octeon_HitInvalidateDCache(struct cpu_info *ci, vaddr_t va, size_t len) 205{ 206} 207 208void 209Octeon_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 222void 223Octeon_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 244void 245Octeon_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