cache-sh4.c revision 2277ab4a1df50e05bc732fe9488d4e902bb8399a
1/* 2 * arch/sh/mm/cache-sh4.c 3 * 4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka 5 * Copyright (C) 2001 - 2007 Paul Mundt 6 * Copyright (C) 2003 Richard Curnow 7 * Copyright (c) 2007 STMicroelectronics (R&D) Ltd. 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file "COPYING" in the main directory of this archive 11 * for more details. 12 */ 13#include <linux/init.h> 14#include <linux/mm.h> 15#include <linux/io.h> 16#include <linux/mutex.h> 17#include <linux/fs.h> 18#include <asm/mmu_context.h> 19#include <asm/cacheflush.h> 20 21/* 22 * The maximum number of pages we support up to when doing ranged dcache 23 * flushing. Anything exceeding this will simply flush the dcache in its 24 * entirety. 25 */ 26#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ 27#define MAX_ICACHE_PAGES 32 28 29static void __flush_dcache_segment_1way(unsigned long start, 30 unsigned long extent); 31static void __flush_dcache_segment_2way(unsigned long start, 32 unsigned long extent); 33static void __flush_dcache_segment_4way(unsigned long start, 34 unsigned long extent); 35 36static void __flush_cache_4096(unsigned long addr, unsigned long phys, 37 unsigned long exec_offset); 38 39/* 40 * This is initialised here to ensure that it is not placed in the BSS. If 41 * that were to happen, note that cache_init gets called before the BSS is 42 * cleared, so this would get nulled out which would be hopeless. 43 */ 44static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = 45 (void (*)(unsigned long, unsigned long))0xdeadbeef; 46 47static void compute_alias(struct cache_info *c) 48{ 49 c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); 50 c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0; 51} 52 53static void __init emit_cache_params(void) 54{ 55 printk("PVR=%08x CVR=%08x PRR=%08x\n", 56 ctrl_inl(CCN_PVR), 57 ctrl_inl(CCN_CVR), 58 ctrl_inl(CCN_PRR)); 59 printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n", 60 boot_cpu_data.icache.ways, 61 boot_cpu_data.icache.sets, 62 boot_cpu_data.icache.way_incr); 63 printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", 64 boot_cpu_data.icache.entry_mask, 65 boot_cpu_data.icache.alias_mask, 66 boot_cpu_data.icache.n_aliases); 67 printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n", 68 boot_cpu_data.dcache.ways, 69 boot_cpu_data.dcache.sets, 70 boot_cpu_data.dcache.way_incr); 71 printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", 72 boot_cpu_data.dcache.entry_mask, 73 boot_cpu_data.dcache.alias_mask, 74 boot_cpu_data.dcache.n_aliases); 75 76 /* 77 * Emit Secondary Cache parameters if the CPU has a probed L2. 78 */ 79 if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) { 80 printk("S-cache : n_ways=%d n_sets=%d way_incr=%d\n", 81 boot_cpu_data.scache.ways, 82 boot_cpu_data.scache.sets, 83 boot_cpu_data.scache.way_incr); 84 printk("S-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", 85 boot_cpu_data.scache.entry_mask, 86 boot_cpu_data.scache.alias_mask, 87 boot_cpu_data.scache.n_aliases); 88 } 89 90 if (!__flush_dcache_segment_fn) 91 panic("unknown number of cache ways\n"); 92} 93 94/* 95 * SH-4 has virtually indexed and physically tagged cache. 96 */ 97void __init p3_cache_init(void) 98{ 99 compute_alias(&boot_cpu_data.icache); 100 compute_alias(&boot_cpu_data.dcache); 101 compute_alias(&boot_cpu_data.scache); 102 103 switch (boot_cpu_data.dcache.ways) { 104 case 1: 105 __flush_dcache_segment_fn = __flush_dcache_segment_1way; 106 break; 107 case 2: 108 __flush_dcache_segment_fn = __flush_dcache_segment_2way; 109 break; 110 case 4: 111 __flush_dcache_segment_fn = __flush_dcache_segment_4way; 112 break; 113 default: 114 __flush_dcache_segment_fn = NULL; 115 break; 116 } 117 118 emit_cache_params(); 119} 120 121/* 122 * Write back the dirty D-caches, but not invalidate them. 123 * 124 * START: Virtual Address (U0, P1, or P3) 125 * SIZE: Size of the region. 126 */ 127void __flush_wback_region(void *start, int size) 128{ 129 unsigned long v; 130 unsigned long begin, end; 131 132 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 133 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 134 & ~(L1_CACHE_BYTES-1); 135 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 136 asm volatile("ocbwb %0" 137 : /* no output */ 138 : "m" (__m(v))); 139 } 140} 141 142/* 143 * Write back the dirty D-caches and invalidate them. 144 * 145 * START: Virtual Address (U0, P1, or P3) 146 * SIZE: Size of the region. 147 */ 148void __flush_purge_region(void *start, int size) 149{ 150 unsigned long v; 151 unsigned long begin, end; 152 153 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 154 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 155 & ~(L1_CACHE_BYTES-1); 156 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 157 asm volatile("ocbp %0" 158 : /* no output */ 159 : "m" (__m(v))); 160 } 161} 162 163/* 164 * No write back please 165 */ 166void __flush_invalidate_region(void *start, int size) 167{ 168 unsigned long v; 169 unsigned long begin, end; 170 171 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 172 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 173 & ~(L1_CACHE_BYTES-1); 174 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 175 asm volatile("ocbi %0" 176 : /* no output */ 177 : "m" (__m(v))); 178 } 179} 180 181/* 182 * Write back the range of D-cache, and purge the I-cache. 183 * 184 * Called from kernel/module.c:sys_init_module and routine for a.out format, 185 * signal handler code and kprobes code 186 */ 187void flush_icache_range(unsigned long start, unsigned long end) 188{ 189 int icacheaddr; 190 unsigned long flags, v; 191 int i; 192 193 /* If there are too many pages then just blow the caches */ 194 if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { 195 flush_cache_all(); 196 } else { 197 /* selectively flush d-cache then invalidate the i-cache */ 198 /* this is inefficient, so only use for small ranges */ 199 start &= ~(L1_CACHE_BYTES-1); 200 end += L1_CACHE_BYTES-1; 201 end &= ~(L1_CACHE_BYTES-1); 202 203 local_irq_save(flags); 204 jump_to_uncached(); 205 206 for (v = start; v < end; v+=L1_CACHE_BYTES) { 207 asm volatile("ocbwb %0" 208 : /* no output */ 209 : "m" (__m(v))); 210 211 icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( 212 v & cpu_data->icache.entry_mask); 213 214 for (i = 0; i < cpu_data->icache.ways; 215 i++, icacheaddr += cpu_data->icache.way_incr) 216 /* Clear i-cache line valid-bit */ 217 ctrl_outl(0, icacheaddr); 218 } 219 220 back_to_cached(); 221 local_irq_restore(flags); 222 } 223} 224 225static inline void flush_cache_4096(unsigned long start, 226 unsigned long phys) 227{ 228 unsigned long flags, exec_offset = 0; 229 230 /* 231 * All types of SH-4 require PC to be in P2 to operate on the I-cache. 232 * Some types of SH-4 require PC to be in P2 to operate on the D-cache. 233 */ 234 if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) || 235 (start < CACHE_OC_ADDRESS_ARRAY)) 236 exec_offset = 0x20000000; 237 238 local_irq_save(flags); 239 __flush_cache_4096(start | SH_CACHE_ASSOC, 240 P1SEGADDR(phys), exec_offset); 241 local_irq_restore(flags); 242} 243 244/* 245 * Write back & invalidate the D-cache of the page. 246 * (To avoid "alias" issues) 247 */ 248void flush_dcache_page(struct page *page) 249{ 250 struct address_space *mapping = page_mapping(page); 251 252#ifndef CONFIG_SMP 253 if (mapping && !mapping_mapped(mapping)) 254 set_bit(PG_dcache_dirty, &page->flags); 255 else 256#endif 257 { 258 unsigned long phys = PHYSADDR(page_address(page)); 259 unsigned long addr = CACHE_OC_ADDRESS_ARRAY; 260 int i, n; 261 262 /* Loop all the D-cache */ 263 n = boot_cpu_data.dcache.n_aliases; 264 for (i = 0; i < n; i++, addr += 4096) 265 flush_cache_4096(addr, phys); 266 } 267 268 wmb(); 269} 270 271/* TODO: Selective icache invalidation through IC address array.. */ 272static void __uses_jump_to_uncached flush_icache_all(void) 273{ 274 unsigned long flags, ccr; 275 276 local_irq_save(flags); 277 jump_to_uncached(); 278 279 /* Flush I-cache */ 280 ccr = ctrl_inl(CCR); 281 ccr |= CCR_CACHE_ICI; 282 ctrl_outl(ccr, CCR); 283 284 /* 285 * back_to_cached() will take care of the barrier for us, don't add 286 * another one! 287 */ 288 289 back_to_cached(); 290 local_irq_restore(flags); 291} 292 293void flush_dcache_all(void) 294{ 295 (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size); 296 wmb(); 297} 298 299void flush_cache_all(void) 300{ 301 flush_dcache_all(); 302 flush_icache_all(); 303} 304 305static void __flush_cache_mm(struct mm_struct *mm, unsigned long start, 306 unsigned long end) 307{ 308 unsigned long d = 0, p = start & PAGE_MASK; 309 unsigned long alias_mask = boot_cpu_data.dcache.alias_mask; 310 unsigned long n_aliases = boot_cpu_data.dcache.n_aliases; 311 unsigned long select_bit; 312 unsigned long all_aliases_mask; 313 unsigned long addr_offset; 314 pgd_t *dir; 315 pmd_t *pmd; 316 pud_t *pud; 317 pte_t *pte; 318 int i; 319 320 dir = pgd_offset(mm, p); 321 pud = pud_offset(dir, p); 322 pmd = pmd_offset(pud, p); 323 end = PAGE_ALIGN(end); 324 325 all_aliases_mask = (1 << n_aliases) - 1; 326 327 do { 328 if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { 329 p &= PMD_MASK; 330 p += PMD_SIZE; 331 pmd++; 332 333 continue; 334 } 335 336 pte = pte_offset_kernel(pmd, p); 337 338 do { 339 unsigned long phys; 340 pte_t entry = *pte; 341 342 if (!(pte_val(entry) & _PAGE_PRESENT)) { 343 pte++; 344 p += PAGE_SIZE; 345 continue; 346 } 347 348 phys = pte_val(entry) & PTE_PHYS_MASK; 349 350 if ((p ^ phys) & alias_mask) { 351 d |= 1 << ((p & alias_mask) >> PAGE_SHIFT); 352 d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT); 353 354 if (d == all_aliases_mask) 355 goto loop_exit; 356 } 357 358 pte++; 359 p += PAGE_SIZE; 360 } while (p < end && ((unsigned long)pte & ~PAGE_MASK)); 361 pmd++; 362 } while (p < end); 363 364loop_exit: 365 addr_offset = 0; 366 select_bit = 1; 367 368 for (i = 0; i < n_aliases; i++) { 369 if (d & select_bit) { 370 (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE); 371 wmb(); 372 } 373 374 select_bit <<= 1; 375 addr_offset += PAGE_SIZE; 376 } 377} 378 379/* 380 * Note : (RPC) since the caches are physically tagged, the only point 381 * of flush_cache_mm for SH-4 is to get rid of aliases from the 382 * D-cache. The assumption elsewhere, e.g. flush_cache_range, is that 383 * lines can stay resident so long as the virtual address they were 384 * accessed with (hence cache set) is in accord with the physical 385 * address (i.e. tag). It's no different here. So I reckon we don't 386 * need to flush the I-cache, since aliases don't matter for that. We 387 * should try that. 388 * 389 * Caller takes mm->mmap_sem. 390 */ 391void flush_cache_mm(struct mm_struct *mm) 392{ 393 /* 394 * If cache is only 4k-per-way, there are never any 'aliases'. Since 395 * the cache is physically tagged, the data can just be left in there. 396 */ 397 if (boot_cpu_data.dcache.n_aliases == 0) 398 return; 399 400 /* 401 * Don't bother groveling around the dcache for the VMA ranges 402 * if there are too many PTEs to make it worthwhile. 403 */ 404 if (mm->nr_ptes >= MAX_DCACHE_PAGES) 405 flush_dcache_all(); 406 else { 407 struct vm_area_struct *vma; 408 409 /* 410 * In this case there are reasonably sized ranges to flush, 411 * iterate through the VMA list and take care of any aliases. 412 */ 413 for (vma = mm->mmap; vma; vma = vma->vm_next) 414 __flush_cache_mm(mm, vma->vm_start, vma->vm_end); 415 } 416 417 /* Only touch the icache if one of the VMAs has VM_EXEC set. */ 418 if (mm->exec_vm) 419 flush_icache_all(); 420} 421 422/* 423 * Write back and invalidate I/D-caches for the page. 424 * 425 * ADDR: Virtual Address (U0 address) 426 * PFN: Physical page number 427 */ 428void flush_cache_page(struct vm_area_struct *vma, unsigned long address, 429 unsigned long pfn) 430{ 431 unsigned long phys = pfn << PAGE_SHIFT; 432 unsigned int alias_mask; 433 434 alias_mask = boot_cpu_data.dcache.alias_mask; 435 436 /* We only need to flush D-cache when we have alias */ 437 if ((address^phys) & alias_mask) { 438 /* Loop 4K of the D-cache */ 439 flush_cache_4096( 440 CACHE_OC_ADDRESS_ARRAY | (address & alias_mask), 441 phys); 442 /* Loop another 4K of the D-cache */ 443 flush_cache_4096( 444 CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask), 445 phys); 446 } 447 448 alias_mask = boot_cpu_data.icache.alias_mask; 449 if (vma->vm_flags & VM_EXEC) { 450 /* 451 * Evict entries from the portion of the cache from which code 452 * may have been executed at this address (virtual). There's 453 * no need to evict from the portion corresponding to the 454 * physical address as for the D-cache, because we know the 455 * kernel has never executed the code through its identity 456 * translation. 457 */ 458 flush_cache_4096( 459 CACHE_IC_ADDRESS_ARRAY | (address & alias_mask), 460 phys); 461 } 462} 463 464/* 465 * Write back and invalidate D-caches. 466 * 467 * START, END: Virtual Address (U0 address) 468 * 469 * NOTE: We need to flush the _physical_ page entry. 470 * Flushing the cache lines for U0 only isn't enough. 471 * We need to flush for P1 too, which may contain aliases. 472 */ 473void flush_cache_range(struct vm_area_struct *vma, unsigned long start, 474 unsigned long end) 475{ 476 /* 477 * If cache is only 4k-per-way, there are never any 'aliases'. Since 478 * the cache is physically tagged, the data can just be left in there. 479 */ 480 if (boot_cpu_data.dcache.n_aliases == 0) 481 return; 482 483 /* 484 * Don't bother with the lookup and alias check if we have a 485 * wide range to cover, just blow away the dcache in its 486 * entirety instead. -- PFM. 487 */ 488 if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES) 489 flush_dcache_all(); 490 else 491 __flush_cache_mm(vma->vm_mm, start, end); 492 493 if (vma->vm_flags & VM_EXEC) { 494 /* 495 * TODO: Is this required??? Need to look at how I-cache 496 * coherency is assured when new programs are loaded to see if 497 * this matters. 498 */ 499 flush_icache_all(); 500 } 501} 502 503/* 504 * flush_icache_user_range 505 * @vma: VMA of the process 506 * @page: page 507 * @addr: U0 address 508 * @len: length of the range (< page size) 509 */ 510void flush_icache_user_range(struct vm_area_struct *vma, 511 struct page *page, unsigned long addr, int len) 512{ 513 flush_cache_page(vma, addr, page_to_pfn(page)); 514 mb(); 515} 516 517/** 518 * __flush_cache_4096 519 * 520 * @addr: address in memory mapped cache array 521 * @phys: P1 address to flush (has to match tags if addr has 'A' bit 522 * set i.e. associative write) 523 * @exec_offset: set to 0x20000000 if flush has to be executed from P2 524 * region else 0x0 525 * 526 * The offset into the cache array implied by 'addr' selects the 527 * 'colour' of the virtual address range that will be flushed. The 528 * operation (purge/write-back) is selected by the lower 2 bits of 529 * 'phys'. 530 */ 531static void __flush_cache_4096(unsigned long addr, unsigned long phys, 532 unsigned long exec_offset) 533{ 534 int way_count; 535 unsigned long base_addr = addr; 536 struct cache_info *dcache; 537 unsigned long way_incr; 538 unsigned long a, ea, p; 539 unsigned long temp_pc; 540 541 dcache = &boot_cpu_data.dcache; 542 /* Write this way for better assembly. */ 543 way_count = dcache->ways; 544 way_incr = dcache->way_incr; 545 546 /* 547 * Apply exec_offset (i.e. branch to P2 if required.). 548 * 549 * FIXME: 550 * 551 * If I write "=r" for the (temp_pc), it puts this in r6 hence 552 * trashing exec_offset before it's been added on - why? Hence 553 * "=&r" as a 'workaround' 554 */ 555 asm volatile("mov.l 1f, %0\n\t" 556 "add %1, %0\n\t" 557 "jmp @%0\n\t" 558 "nop\n\t" 559 ".balign 4\n\t" 560 "1: .long 2f\n\t" 561 "2:\n" : "=&r" (temp_pc) : "r" (exec_offset)); 562 563 /* 564 * We know there will be >=1 iteration, so write as do-while to avoid 565 * pointless nead-of-loop check for 0 iterations. 566 */ 567 do { 568 ea = base_addr + PAGE_SIZE; 569 a = base_addr; 570 p = phys; 571 572 do { 573 *(volatile unsigned long *)a = p; 574 /* 575 * Next line: intentionally not p+32, saves an add, p 576 * will do since only the cache tag bits need to 577 * match. 578 */ 579 *(volatile unsigned long *)(a+32) = p; 580 a += 64; 581 p += 64; 582 } while (a < ea); 583 584 base_addr += way_incr; 585 } while (--way_count != 0); 586} 587 588/* 589 * Break the 1, 2 and 4 way variants of this out into separate functions to 590 * avoid nearly all the overhead of having the conditional stuff in the function 591 * bodies (+ the 1 and 2 way cases avoid saving any registers too). 592 */ 593static void __flush_dcache_segment_1way(unsigned long start, 594 unsigned long extent_per_way) 595{ 596 unsigned long orig_sr, sr_with_bl; 597 unsigned long base_addr; 598 unsigned long way_incr, linesz, way_size; 599 struct cache_info *dcache; 600 register unsigned long a0, a0e; 601 602 asm volatile("stc sr, %0" : "=r" (orig_sr)); 603 sr_with_bl = orig_sr | (1<<28); 604 base_addr = ((unsigned long)&empty_zero_page[0]); 605 606 /* 607 * The previous code aligned base_addr to 16k, i.e. the way_size of all 608 * existing SH-4 D-caches. Whilst I don't see a need to have this 609 * aligned to any better than the cache line size (which it will be 610 * anyway by construction), let's align it to at least the way_size of 611 * any existing or conceivable SH-4 D-cache. -- RPC 612 */ 613 base_addr = ((base_addr >> 16) << 16); 614 base_addr |= start; 615 616 dcache = &boot_cpu_data.dcache; 617 linesz = dcache->linesz; 618 way_incr = dcache->way_incr; 619 way_size = dcache->way_size; 620 621 a0 = base_addr; 622 a0e = base_addr + extent_per_way; 623 do { 624 asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); 625 asm volatile("movca.l r0, @%0\n\t" 626 "ocbi @%0" : : "r" (a0)); 627 a0 += linesz; 628 asm volatile("movca.l r0, @%0\n\t" 629 "ocbi @%0" : : "r" (a0)); 630 a0 += linesz; 631 asm volatile("movca.l r0, @%0\n\t" 632 "ocbi @%0" : : "r" (a0)); 633 a0 += linesz; 634 asm volatile("movca.l r0, @%0\n\t" 635 "ocbi @%0" : : "r" (a0)); 636 asm volatile("ldc %0, sr" : : "r" (orig_sr)); 637 a0 += linesz; 638 } while (a0 < a0e); 639} 640 641static void __flush_dcache_segment_2way(unsigned long start, 642 unsigned long extent_per_way) 643{ 644 unsigned long orig_sr, sr_with_bl; 645 unsigned long base_addr; 646 unsigned long way_incr, linesz, way_size; 647 struct cache_info *dcache; 648 register unsigned long a0, a1, a0e; 649 650 asm volatile("stc sr, %0" : "=r" (orig_sr)); 651 sr_with_bl = orig_sr | (1<<28); 652 base_addr = ((unsigned long)&empty_zero_page[0]); 653 654 /* See comment under 1-way above */ 655 base_addr = ((base_addr >> 16) << 16); 656 base_addr |= start; 657 658 dcache = &boot_cpu_data.dcache; 659 linesz = dcache->linesz; 660 way_incr = dcache->way_incr; 661 way_size = dcache->way_size; 662 663 a0 = base_addr; 664 a1 = a0 + way_incr; 665 a0e = base_addr + extent_per_way; 666 do { 667 asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); 668 asm volatile("movca.l r0, @%0\n\t" 669 "movca.l r0, @%1\n\t" 670 "ocbi @%0\n\t" 671 "ocbi @%1" : : 672 "r" (a0), "r" (a1)); 673 a0 += linesz; 674 a1 += linesz; 675 asm volatile("movca.l r0, @%0\n\t" 676 "movca.l r0, @%1\n\t" 677 "ocbi @%0\n\t" 678 "ocbi @%1" : : 679 "r" (a0), "r" (a1)); 680 a0 += linesz; 681 a1 += linesz; 682 asm volatile("movca.l r0, @%0\n\t" 683 "movca.l r0, @%1\n\t" 684 "ocbi @%0\n\t" 685 "ocbi @%1" : : 686 "r" (a0), "r" (a1)); 687 a0 += linesz; 688 a1 += linesz; 689 asm volatile("movca.l r0, @%0\n\t" 690 "movca.l r0, @%1\n\t" 691 "ocbi @%0\n\t" 692 "ocbi @%1" : : 693 "r" (a0), "r" (a1)); 694 asm volatile("ldc %0, sr" : : "r" (orig_sr)); 695 a0 += linesz; 696 a1 += linesz; 697 } while (a0 < a0e); 698} 699 700static void __flush_dcache_segment_4way(unsigned long start, 701 unsigned long extent_per_way) 702{ 703 unsigned long orig_sr, sr_with_bl; 704 unsigned long base_addr; 705 unsigned long way_incr, linesz, way_size; 706 struct cache_info *dcache; 707 register unsigned long a0, a1, a2, a3, a0e; 708 709 asm volatile("stc sr, %0" : "=r" (orig_sr)); 710 sr_with_bl = orig_sr | (1<<28); 711 base_addr = ((unsigned long)&empty_zero_page[0]); 712 713 /* See comment under 1-way above */ 714 base_addr = ((base_addr >> 16) << 16); 715 base_addr |= start; 716 717 dcache = &boot_cpu_data.dcache; 718 linesz = dcache->linesz; 719 way_incr = dcache->way_incr; 720 way_size = dcache->way_size; 721 722 a0 = base_addr; 723 a1 = a0 + way_incr; 724 a2 = a1 + way_incr; 725 a3 = a2 + way_incr; 726 a0e = base_addr + extent_per_way; 727 do { 728 asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); 729 asm volatile("movca.l r0, @%0\n\t" 730 "movca.l r0, @%1\n\t" 731 "movca.l r0, @%2\n\t" 732 "movca.l r0, @%3\n\t" 733 "ocbi @%0\n\t" 734 "ocbi @%1\n\t" 735 "ocbi @%2\n\t" 736 "ocbi @%3\n\t" : : 737 "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 738 a0 += linesz; 739 a1 += linesz; 740 a2 += linesz; 741 a3 += linesz; 742 asm volatile("movca.l r0, @%0\n\t" 743 "movca.l r0, @%1\n\t" 744 "movca.l r0, @%2\n\t" 745 "movca.l r0, @%3\n\t" 746 "ocbi @%0\n\t" 747 "ocbi @%1\n\t" 748 "ocbi @%2\n\t" 749 "ocbi @%3\n\t" : : 750 "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 751 a0 += linesz; 752 a1 += linesz; 753 a2 += linesz; 754 a3 += linesz; 755 asm volatile("movca.l r0, @%0\n\t" 756 "movca.l r0, @%1\n\t" 757 "movca.l r0, @%2\n\t" 758 "movca.l r0, @%3\n\t" 759 "ocbi @%0\n\t" 760 "ocbi @%1\n\t" 761 "ocbi @%2\n\t" 762 "ocbi @%3\n\t" : : 763 "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 764 a0 += linesz; 765 a1 += linesz; 766 a2 += linesz; 767 a3 += linesz; 768 asm volatile("movca.l r0, @%0\n\t" 769 "movca.l r0, @%1\n\t" 770 "movca.l r0, @%2\n\t" 771 "movca.l r0, @%3\n\t" 772 "ocbi @%0\n\t" 773 "ocbi @%1\n\t" 774 "ocbi @%2\n\t" 775 "ocbi @%3\n\t" : : 776 "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 777 asm volatile("ldc %0, sr" : : "r" (orig_sr)); 778 a0 += linesz; 779 a1 += linesz; 780 a2 += linesz; 781 a3 += linesz; 782 } while (a0 < a0e); 783} 784