1 /* $NetBSD: cache_octeon.c,v 1.4 2020/06/06 14:30:44 simonb Exp $ */ 2 3 #include <sys/cdefs.h> 4 __KERNEL_RCSID(0, "$NetBSD: cache_octeon.c,v 1.4 2020/06/06 14:30:44 simonb Exp $"); 5 6 #include <sys/param.h> 7 #include <sys/systm.h> 8 9 #include <mips/locore.h> 10 #include <mips/cache.h> 11 #include <mips/cache_octeon.h> 12 13 #define SYNC __asm volatile("sync") 14 15 #ifdef OCTEON_ICACHE_DEBUG 16 int octeon_cache_debug = 0; 17 #define ICACHE_DEBUG_PRINTF(x) \ 18 if (__predict_false(octeon_cache_debug != 0)) \ 19 printf x; 20 #else 21 #define ICACHE_DEBUG_PRINTF(x) /* nothing */ 22 #endif 23 24 25 static inline void 26 mips_synci(vaddr_t va) 27 { 28 29 __asm __volatile("synci 0(%0)" :: "r"(va)); 30 } 31 32 void 33 octeon_icache_sync_all(void) 34 { 35 36 ICACHE_DEBUG_PRINTF(("%s\n", __func__)); 37 mips_synci(MIPS_KSEG0_START); 38 SYNC; 39 } 40 void 41 octeon_icache_sync_range(register_t va, vsize_t size) 42 { 43 44 ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxREGISTER", size=%#"PRIxVSIZE"\n", 45 __func__, va, size)); 46 mips_synci(MIPS_KSEG0_START); 47 SYNC; 48 } 49 50 void 51 octeon_icache_sync_range_index(vaddr_t va, vsize_t size) 52 { 53 54 ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxVADDR", size=%#"PRIxVSIZE"\n", 55 __func__, va, size)); 56 mips_synci(MIPS_KSEG0_START); 57 SYNC; 58 } 59 60 void 61 octeon_pdcache_inv_all(void) 62 { 63 64 ICACHE_DEBUG_PRINTF(("%s\n", __func__)); 65 cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D); 66 SYNC; 67 } 68 69 void 70 octeon_pdcache_inv_range(register_t va, vsize_t size) 71 { 72 73 ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxREGISTER", size=%#"PRIxVSIZE"\n", 74 __func__, va, size)); 75 cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D); 76 SYNC; 77 } 78 79 void 80 octeon_pdcache_inv_range_index(vaddr_t va, vsize_t size) 81 { 82 83 ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxVADDR", size=%#"PRIxVSIZE"\n", 84 __func__, va, size)); 85 cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D); 86 SYNC; 87 } 88 89 /* ---- debug dump */ 90 91 #ifdef OCTEON_ICACHE_DEBUG 92 93 /* XXX does the following even make sense for Octeon II/III? */ 94 95 /* icache: 16KB, 2ways */ 96 97 #define OCTEON_ICACHE_VA_WAY(_va) (((_va) & __BITS(14, 13)) >> 13) 98 #define OCTEON_ICACHE_VA_INDEX(_va) (((_va) & __BITS(12, 7)) >> 7) 99 #define OCTEON_ICACHE_VA_WORD(_va) (((_va) & __BITS( 6, 3)) >> 3) 100 101 #define OCTEON_ICACHE_TAGLO_R(_taglo) (((_taglo) & __BITS(63, 62)) >> 62) 102 #define OCTEON_ICACHE_TAGLO_ASID(_taglo) (((_taglo) & __BITS(59, 52)) >> 52) 103 #define OCTEON_ICACHE_TAGLO_TAG(_taglo) (((_taglo) & __BITS(48, 13)) >> 13) 104 #define OCTEON_ICACHE_TAGLO_INDEX(_taglo) (((_taglo) & __BITS(12, 7)) >> 7) 105 #define OCTEON_ICACHE_TAGLO_G(_taglo) (((_taglo) & __BITS( 1, 1)) >> 1) 106 #define OCTEON_ICACHE_TAGLO_VALID(_taglo) (((_taglo) & __BITS( 0, 0)) >> 0) 107 108 /* dcache: 8KB, 64ways */ 109 110 #define OCTEON_DCACHE_VA_WAY(_va) (((_va) & __BITS(12, 7)) >> 7) 111 #define OCTEON_DCACHE_VA_WORD(_va) (((_va) & __BITS( 6, 3)) >> 3) 112 113 #define OCTEON_DCACHE_TAGLO_R(_taglo) (((_taglo) & __BITS(63, 62)) >> 62) 114 #define OCTEON_DCACHE_TAGLO_ASID(_taglo) (((_taglo) & __BITS(59, 52)) >> 52) 115 #define OCTEON_DCACHE_TAGLO_TAG(_taglo) (((_taglo) & __BITS(48, 7)) >> 7) 116 #define OCTEON_DCACHE_TAGLO_G(_taglo) (((_taglo) & __BITS( 1, 1)) >> 1) 117 #define OCTEON_DCACHE_TAGLO_VALID(_taglo) (((_taglo) & __BITS( 0, 0)) >> 0) 118 119 #define OCTEON_DCACHE_TAGHI_PTAG(_taghi) (((_taghi) & __BITS(35, 7)) >> 7) 120 #define OCTEON_DCACHE_TAGHI_VALID(_taghi) (((_taghi) & __BITS( 0, 0)) >> 0) 121 122 void octeon_icache_dump_all(void); 123 void octeon_icache_dump_way(int); 124 void octeon_icache_dump_index(int, int); 125 void octeon_icache_dump_va(register_t); 126 void octeon_dcache_dump_all(void); 127 void octeon_dcache_dump_way(int); 128 void octeon_dcache_dump_index(int, int); 129 void octeon_dcache_dump_va(register_t); 130 131 void 132 octeon_icache_dump_all(void) 133 { 134 /* way = (0 .. 3) */ 135 const int maxway = 2; /* XXX 2 << (14 - 13 + 1) == 4? */ 136 int way; 137 138 for (way = 0; way < maxway; way++) 139 octeon_icache_dump_way(way); 140 } 141 142 void 143 octeon_icache_dump_way(int way) 144 { 145 /* index = (0 .. 127) */ 146 const int maxindex = 64; /* XXX 2 << (12 - 7 + 1) == 128? */; 147 int index; 148 149 for (index = 0; index < maxindex; index++) 150 octeon_icache_dump_index(way, index); 151 } 152 153 void 154 octeon_icache_dump_index(int way, int index) 155 { 156 const vaddr_t va = (way << 13) | (index << 7); 157 158 octeon_icache_dump_va(va); 159 } 160 161 void 162 octeon_icache_dump_va(register_t va) 163 { 164 uint64_t taglo, datalo, datahi; 165 166 /* icache */ 167 __asm __volatile ( 168 " .set push \n" 169 " .set noreorder \n" 170 " .set arch=octeon \n" 171 " cache 4, 0(%[va]) \n" 172 " dmfc0 %[taglo], $28, 0 \n" 173 " dmfc0 %[datalo], $28, 1 \n" 174 " dmfc0 %[datahi], $29, 1 \n" 175 " .set pop \n" 176 : [taglo] "=r" (taglo), 177 [datalo] "=r" (datalo), 178 [datahi] "=r" (datahi) 179 : [va] "r" (va)); 180 181 printf("%s: va=%08x " 182 "(way=%01x, index=%02x"/* ", word=%01d" */"), " 183 "taglo=%016"PRIx64" " 184 "(R=%01"PRIx64", asid=%02"PRIx64", tag=%09"PRIx64", index=%02"PRIx64", G=%01"PRIx64", valid=%01"PRIx64"), " 185 "datahi=%01"PRIx64", datalo=%016"PRIx64"" 186 "\n", 187 __func__, 188 (int)((taglo) & __BITS(48, 7)), /* (int)va */ 189 (int)OCTEON_ICACHE_VA_WAY(va), 190 (int)OCTEON_ICACHE_VA_INDEX(va), 191 /* (int)OCTEON_ICACHE_VA_WORD(va), */ 192 taglo, 193 OCTEON_ICACHE_TAGLO_R(taglo), 194 OCTEON_ICACHE_TAGLO_ASID(taglo), 195 OCTEON_ICACHE_TAGLO_TAG(taglo), 196 OCTEON_ICACHE_TAGLO_INDEX(taglo), 197 OCTEON_ICACHE_TAGLO_G(taglo), 198 OCTEON_ICACHE_TAGLO_VALID(taglo), 199 datahi, datalo); 200 } 201 202 void 203 octeon_dcache_dump_all(void) 204 { 205 /* way = (0 .. 63) */ 206 const int maxway = 64; 207 int way; 208 209 for (way = 0; way < maxway; way++) 210 octeon_dcache_dump_way(way); 211 } 212 213 void 214 octeon_dcache_dump_way(int way) 215 { 216 /* index = (0 .. 0) */ 217 const int maxindex = 1; 218 int index; 219 220 for (index = 0; index < maxindex; index++) 221 octeon_dcache_dump_index(way, index); 222 } 223 224 void 225 octeon_dcache_dump_index(int way, int index) 226 { 227 const vaddr_t va = (way << 7); /* no index in dcache */ 228 229 octeon_dcache_dump_va(va); 230 } 231 232 void 233 octeon_dcache_dump_va(register_t va) 234 { 235 uint64_t taglo, taghi, datalo, datahi; 236 237 /* dcache */ 238 __asm __volatile ( 239 " .set push \n" 240 " .set noreorder \n" 241 " .set arch=octeon \n" 242 " cache 5, 0(%[va]) \n" 243 " dmfc0 %[taglo], $28, 2 \n" 244 " dmfc0 %[taghi], $29, 2 \n" 245 " dmfc0 %[datalo], $28, 3 \n" 246 " dmfc0 %[datahi], $29, 3 \n" 247 " .set pop \n" 248 : [taglo] "=r" (taglo), 249 [taghi] "=r" (taghi), 250 [datalo] "=r" (datalo), 251 [datahi] "=r" (datahi) 252 : [va] "r" (va)); 253 254 printf("%s: va=%08x " 255 "(way=%02x"/* ", word=%01d" */"), " 256 "taglo=%016"PRIx64" " 257 "(R=%01"PRIx64", asid=%02"PRIx64", tag=%09"PRIx64", G=%01"PRIx64", valid=%01"PRIx64"), " 258 "taghi=%016"PRIx64" " 259 "(ptag=%08"PRIx64", valid=%01"PRIx64"), " 260 "datahi=%02"PRIx64", datalo=%016"PRIx64"" 261 "\n", 262 __func__, 263 (int)((taglo) & __BITS(48, 13)), /* (int)va */ 264 (int)OCTEON_DCACHE_VA_WAY(va), 265 /* (int)OCTEON_DCACHE_VA_WORD(va), */ 266 taglo, 267 OCTEON_DCACHE_TAGLO_R(taglo), 268 OCTEON_DCACHE_TAGLO_ASID(taglo), 269 OCTEON_DCACHE_TAGLO_TAG(taglo), 270 OCTEON_DCACHE_TAGLO_G(taglo), 271 OCTEON_DCACHE_TAGLO_VALID(taglo), 272 taghi, 273 OCTEON_DCACHE_TAGHI_PTAG(taghi), 274 OCTEON_DCACHE_TAGHI_VALID(taghi), 275 datahi, datalo); 276 } 277 278 #endif /* OCTEON_ICACHE_DEBUG */ 279