1 /* 2 * Cache control for MicroBlaze cache memories 3 * 4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> 5 * Copyright (C) 2007-2009 PetaLogix 6 * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com> 7 * 8 * This file is subject to the terms and conditions of the GNU General 9 * Public License. See the file COPYING in the main directory of this 10 * archive for more details. 11 */ 12 13 #include <asm/cacheflush.h> 14 #include <linux/cache.h> 15 #include <asm/cpuinfo.h> 16 #include <asm/pvr.h> 17 18 static inline void __invalidate_flush_icache(unsigned int addr) 19 { 20 __asm__ __volatile__ ("wic %0, r0;" \ 21 : : "r" (addr)); 22 } 23 24 static inline void __flush_dcache(unsigned int addr) 25 { 26 __asm__ __volatile__ ("wdc.flush %0, r0;" \ 27 : : "r" (addr)); 28 } 29 30 static inline void __invalidate_dcache(unsigned int baseaddr, 31 unsigned int offset) 32 { 33 __asm__ __volatile__ ("wdc.clear %0, %1;" \ 34 : : "r" (baseaddr), "r" (offset)); 35 } 36 37 static inline void __enable_icache_msr(void) 38 { 39 __asm__ __volatile__ (" msrset r0, %0; \ 40 nop; " \ 41 : : "i" (MSR_ICE) : "memory"); 42 } 43 44 static inline void __disable_icache_msr(void) 45 { 46 __asm__ __volatile__ (" msrclr r0, %0; \ 47 nop; " \ 48 : : "i" (MSR_ICE) : "memory"); 49 } 50 51 static inline void __enable_dcache_msr(void) 52 { 53 __asm__ __volatile__ (" msrset r0, %0; \ 54 nop; " \ 55 : \ 56 : "i" (MSR_DCE) \ 57 : "memory"); 58 } 59 60 static inline void __disable_dcache_msr(void) 61 { 62 __asm__ __volatile__ (" msrclr r0, %0; \ 63 nop; " \ 64 : \ 65 : "i" (MSR_DCE) \ 66 : "memory"); 67 } 68 69 static inline void __enable_icache_nomsr(void) 70 { 71 __asm__ __volatile__ (" mfs r12, rmsr; \ 72 nop; \ 73 ori r12, r12, %0; \ 74 mts rmsr, r12; \ 75 nop; " \ 76 : \ 77 : "i" (MSR_ICE) \ 78 : "memory", "r12"); 79 } 80 81 static inline void __disable_icache_nomsr(void) 82 { 83 __asm__ __volatile__ (" mfs r12, rmsr; \ 84 nop; \ 85 andi r12, r12, ~%0; \ 86 mts rmsr, r12; \ 87 nop; " \ 88 : \ 89 : "i" (MSR_ICE) \ 90 : "memory", "r12"); 91 } 92 93 static inline void __enable_dcache_nomsr(void) 94 { 95 __asm__ __volatile__ (" mfs r12, rmsr; \ 96 nop; \ 97 ori r12, r12, %0; \ 98 mts rmsr, r12; \ 99 nop; " \ 100 : \ 101 : "i" (MSR_DCE) \ 102 : "memory", "r12"); 103 } 104 105 static inline void __disable_dcache_nomsr(void) 106 { 107 __asm__ __volatile__ (" mfs r12, rmsr; \ 108 nop; \ 109 andi r12, r12, ~%0; \ 110 mts rmsr, r12; \ 111 nop; " \ 112 : \ 113 : "i" (MSR_DCE) \ 114 : "memory", "r12"); 115 } 116 117 118 /* Helper macro for computing the limits of cache range loops */ 119 #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \ 120 do { \ 121 int align = ~(cache_line_length - 1); \ 122 end = min(start + cache_size, end); \ 123 start &= align; \ 124 end = ((end & align) + cache_line_length); \ 125 } while (0); 126 127 /* 128 * Helper macro to loop over the specified cache_size/line_length and 129 * execute 'op' on that cacheline 130 */ 131 #define CACHE_ALL_LOOP(cache_size, line_length, op) \ 132 do { \ 133 unsigned int len = cache_size; \ 134 int step = -line_length; \ 135 BUG_ON(step >= 0); \ 136 \ 137 __asm__ __volatile__ (" 1: " #op " %0, r0; \ 138 bgtid %0, 1b; \ 139 addk %0, %0, %1; \ 140 " : : "r" (len), "r" (step) \ 141 : "memory"); \ 142 } while (0); 143 144 145 #define CACHE_ALL_LOOP2(cache_size, line_length, op) \ 146 do { \ 147 unsigned int len = cache_size; \ 148 int step = -line_length; \ 149 BUG_ON(step >= 0); \ 150 \ 151 __asm__ __volatile__ (" 1: " #op " r0, %0; \ 152 bgtid %0, 1b; \ 153 addk %0, %0, %1; \ 154 " : : "r" (len), "r" (step) \ 155 : "memory"); \ 156 } while (0); 157 158 /* for wdc.flush/clear */ 159 #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \ 160 do { \ 161 int step = -line_length; \ 162 int count = end - start; \ 163 BUG_ON(count <= 0); \ 164 \ 165 __asm__ __volatile__ (" 1: " #op " %0, %1; \ 166 bgtid %1, 1b; \ 167 addk %1, %1, %2; \ 168 " : : "r" (start), "r" (count), \ 169 "r" (step) : "memory"); \ 170 } while (0); 171 172 /* It is used only first parameter for OP - for wic, wdc */ 173 #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ 174 do { \ 175 int volatile temp; \ 176 BUG_ON(end - start <= 0); \ 177 \ 178 __asm__ __volatile__ (" 1: " #op " %1, r0; \ 179 cmpu %0, %1, %2; \ 180 bgtid %0, 1b; \ 181 addk %1, %1, %3; \ 182 " : : "r" (temp), "r" (start), "r" (end),\ 183 "r" (line_length) : "memory"); \ 184 } while (0); 185 186 static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end) 187 { 188 unsigned long flags; 189 190 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 191 (unsigned int)start, (unsigned int) end); 192 193 CACHE_LOOP_LIMITS(start, end, 194 cpuinfo.icache_line_length, cpuinfo.icache_size); 195 196 local_irq_save(flags); 197 __disable_icache_msr(); 198 199 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); 200 201 __enable_icache_msr(); 202 local_irq_restore(flags); 203 } 204 205 static void __flush_icache_range_nomsr_irq(unsigned long start, 206 unsigned long end) 207 { 208 unsigned long flags; 209 210 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 211 (unsigned int)start, (unsigned int) end); 212 213 CACHE_LOOP_LIMITS(start, end, 214 cpuinfo.icache_line_length, cpuinfo.icache_size); 215 216 local_irq_save(flags); 217 __disable_icache_nomsr(); 218 219 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); 220 221 __enable_icache_nomsr(); 222 local_irq_restore(flags); 223 } 224 225 static void __flush_icache_range_noirq(unsigned long start, 226 unsigned long end) 227 { 228 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 229 (unsigned int)start, (unsigned int) end); 230 231 CACHE_LOOP_LIMITS(start, end, 232 cpuinfo.icache_line_length, cpuinfo.icache_size); 233 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); 234 } 235 236 static void __flush_icache_all_msr_irq(void) 237 { 238 unsigned long flags; 239 240 pr_debug("%s\n", __func__); 241 242 local_irq_save(flags); 243 __disable_icache_msr(); 244 245 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); 246 247 __enable_icache_msr(); 248 local_irq_restore(flags); 249 } 250 251 static void __flush_icache_all_nomsr_irq(void) 252 { 253 unsigned long flags; 254 255 pr_debug("%s\n", __func__); 256 257 local_irq_save(flags); 258 __disable_icache_nomsr(); 259 260 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); 261 262 __enable_icache_nomsr(); 263 local_irq_restore(flags); 264 } 265 266 static void __flush_icache_all_noirq(void) 267 { 268 pr_debug("%s\n", __func__); 269 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); 270 } 271 272 static void __invalidate_dcache_all_msr_irq(void) 273 { 274 unsigned long flags; 275 276 pr_debug("%s\n", __func__); 277 278 local_irq_save(flags); 279 __disable_dcache_msr(); 280 281 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); 282 283 __enable_dcache_msr(); 284 local_irq_restore(flags); 285 } 286 287 static void __invalidate_dcache_all_nomsr_irq(void) 288 { 289 unsigned long flags; 290 291 pr_debug("%s\n", __func__); 292 293 local_irq_save(flags); 294 __disable_dcache_nomsr(); 295 296 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); 297 298 __enable_dcache_nomsr(); 299 local_irq_restore(flags); 300 } 301 302 static void __invalidate_dcache_all_noirq_wt(void) 303 { 304 pr_debug("%s\n", __func__); 305 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc) 306 } 307 308 /* FIXME this is weird - should be only wdc but not work 309 * MS: I am getting bus errors and other weird things */ 310 static void __invalidate_dcache_all_wb(void) 311 { 312 pr_debug("%s\n", __func__); 313 CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length, 314 wdc.clear) 315 } 316 317 static void __invalidate_dcache_range_wb(unsigned long start, 318 unsigned long end) 319 { 320 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 321 (unsigned int)start, (unsigned int) end); 322 323 CACHE_LOOP_LIMITS(start, end, 324 cpuinfo.dcache_line_length, cpuinfo.dcache_size); 325 CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear); 326 } 327 328 static void __invalidate_dcache_range_nomsr_wt(unsigned long start, 329 unsigned long end) 330 { 331 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 332 (unsigned int)start, (unsigned int) end); 333 CACHE_LOOP_LIMITS(start, end, 334 cpuinfo.dcache_line_length, cpuinfo.dcache_size); 335 336 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); 337 } 338 339 static void __invalidate_dcache_range_msr_irq_wt(unsigned long start, 340 unsigned long end) 341 { 342 unsigned long flags; 343 344 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 345 (unsigned int)start, (unsigned int) end); 346 CACHE_LOOP_LIMITS(start, end, 347 cpuinfo.dcache_line_length, cpuinfo.dcache_size); 348 349 local_irq_save(flags); 350 __disable_dcache_msr(); 351 352 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); 353 354 __enable_dcache_msr(); 355 local_irq_restore(flags); 356 } 357 358 static void __invalidate_dcache_range_nomsr_irq(unsigned long start, 359 unsigned long end) 360 { 361 unsigned long flags; 362 363 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 364 (unsigned int)start, (unsigned int) end); 365 366 CACHE_LOOP_LIMITS(start, end, 367 cpuinfo.dcache_line_length, cpuinfo.dcache_size); 368 369 local_irq_save(flags); 370 __disable_dcache_nomsr(); 371 372 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); 373 374 __enable_dcache_nomsr(); 375 local_irq_restore(flags); 376 } 377 378 static void __flush_dcache_all_wb(void) 379 { 380 pr_debug("%s\n", __func__); 381 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, 382 wdc.flush); 383 } 384 385 static void __flush_dcache_range_wb(unsigned long start, unsigned long end) 386 { 387 pr_debug("%s: start 0x%x, end 0x%x\n", __func__, 388 (unsigned int)start, (unsigned int) end); 389 390 CACHE_LOOP_LIMITS(start, end, 391 cpuinfo.dcache_line_length, cpuinfo.dcache_size); 392 CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush); 393 } 394 395 /* struct for wb caches and for wt caches */ 396 struct scache *mbc; 397 398 /* new wb cache model */ 399 const struct scache wb_msr = { 400 .ie = __enable_icache_msr, 401 .id = __disable_icache_msr, 402 .ifl = __flush_icache_all_noirq, 403 .iflr = __flush_icache_range_noirq, 404 .iin = __flush_icache_all_noirq, 405 .iinr = __flush_icache_range_noirq, 406 .de = __enable_dcache_msr, 407 .dd = __disable_dcache_msr, 408 .dfl = __flush_dcache_all_wb, 409 .dflr = __flush_dcache_range_wb, 410 .din = __invalidate_dcache_all_wb, 411 .dinr = __invalidate_dcache_range_wb, 412 }; 413 414 /* There is only difference in ie, id, de, dd functions */ 415 const struct scache wb_nomsr = { 416 .ie = __enable_icache_nomsr, 417 .id = __disable_icache_nomsr, 418 .ifl = __flush_icache_all_noirq, 419 .iflr = __flush_icache_range_noirq, 420 .iin = __flush_icache_all_noirq, 421 .iinr = __flush_icache_range_noirq, 422 .de = __enable_dcache_nomsr, 423 .dd = __disable_dcache_nomsr, 424 .dfl = __flush_dcache_all_wb, 425 .dflr = __flush_dcache_range_wb, 426 .din = __invalidate_dcache_all_wb, 427 .dinr = __invalidate_dcache_range_wb, 428 }; 429 430 /* Old wt cache model with disabling irq and turn off cache */ 431 const struct scache wt_msr = { 432 .ie = __enable_icache_msr, 433 .id = __disable_icache_msr, 434 .ifl = __flush_icache_all_msr_irq, 435 .iflr = __flush_icache_range_msr_irq, 436 .iin = __flush_icache_all_msr_irq, 437 .iinr = __flush_icache_range_msr_irq, 438 .de = __enable_dcache_msr, 439 .dd = __disable_dcache_msr, 440 .dfl = __invalidate_dcache_all_msr_irq, 441 .dflr = __invalidate_dcache_range_msr_irq_wt, 442 .din = __invalidate_dcache_all_msr_irq, 443 .dinr = __invalidate_dcache_range_msr_irq_wt, 444 }; 445 446 const struct scache wt_nomsr = { 447 .ie = __enable_icache_nomsr, 448 .id = __disable_icache_nomsr, 449 .ifl = __flush_icache_all_nomsr_irq, 450 .iflr = __flush_icache_range_nomsr_irq, 451 .iin = __flush_icache_all_nomsr_irq, 452 .iinr = __flush_icache_range_nomsr_irq, 453 .de = __enable_dcache_nomsr, 454 .dd = __disable_dcache_nomsr, 455 .dfl = __invalidate_dcache_all_nomsr_irq, 456 .dflr = __invalidate_dcache_range_nomsr_irq, 457 .din = __invalidate_dcache_all_nomsr_irq, 458 .dinr = __invalidate_dcache_range_nomsr_irq, 459 }; 460 461 /* New wt cache model for newer Microblaze versions */ 462 const struct scache wt_msr_noirq = { 463 .ie = __enable_icache_msr, 464 .id = __disable_icache_msr, 465 .ifl = __flush_icache_all_noirq, 466 .iflr = __flush_icache_range_noirq, 467 .iin = __flush_icache_all_noirq, 468 .iinr = __flush_icache_range_noirq, 469 .de = __enable_dcache_msr, 470 .dd = __disable_dcache_msr, 471 .dfl = __invalidate_dcache_all_noirq_wt, 472 .dflr = __invalidate_dcache_range_nomsr_wt, 473 .din = __invalidate_dcache_all_noirq_wt, 474 .dinr = __invalidate_dcache_range_nomsr_wt, 475 }; 476 477 const struct scache wt_nomsr_noirq = { 478 .ie = __enable_icache_nomsr, 479 .id = __disable_icache_nomsr, 480 .ifl = __flush_icache_all_noirq, 481 .iflr = __flush_icache_range_noirq, 482 .iin = __flush_icache_all_noirq, 483 .iinr = __flush_icache_range_noirq, 484 .de = __enable_dcache_nomsr, 485 .dd = __disable_dcache_nomsr, 486 .dfl = __invalidate_dcache_all_noirq_wt, 487 .dflr = __invalidate_dcache_range_nomsr_wt, 488 .din = __invalidate_dcache_all_noirq_wt, 489 .dinr = __invalidate_dcache_range_nomsr_wt, 490 }; 491 492 /* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */ 493 #define CPUVER_7_20_A 0x0c 494 #define CPUVER_7_20_D 0x0f 495 496 #define INFO(s) printk(KERN_INFO "cache: " s " \n"); 497 498 void microblaze_cache_init(void) 499 { 500 if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) { 501 if (cpuinfo.dcache_wb) { 502 INFO("wb_msr"); 503 mbc = (struct scache *)&wb_msr; 504 if (cpuinfo.ver_code < CPUVER_7_20_D) { 505 /* MS: problem with signal handling - hw bug */ 506 INFO("WB won't work properly"); 507 } 508 } else { 509 if (cpuinfo.ver_code >= CPUVER_7_20_A) { 510 INFO("wt_msr_noirq"); 511 mbc = (struct scache *)&wt_msr_noirq; 512 } else { 513 INFO("wt_msr"); 514 mbc = (struct scache *)&wt_msr; 515 } 516 } 517 } else { 518 if (cpuinfo.dcache_wb) { 519 INFO("wb_nomsr"); 520 mbc = (struct scache *)&wb_nomsr; 521 if (cpuinfo.ver_code < CPUVER_7_20_D) { 522 /* MS: problem with signal handling - hw bug */ 523 INFO("WB won't work properly"); 524 } 525 } else { 526 if (cpuinfo.ver_code >= CPUVER_7_20_A) { 527 INFO("wt_nomsr_noirq"); 528 mbc = (struct scache *)&wt_nomsr_noirq; 529 } else { 530 INFO("wt_nomsr"); 531 mbc = (struct scache *)&wt_nomsr; 532 } 533 } 534 } 535 } 536