11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * arch/sh/mm/cache-sh3.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Niibe Yutaka 51da177e4SLinus Torvalds * Copyright (C) 2002 Paul Mundt 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Released under the terms of the GNU GPL v2.0. 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/mman.h> 121da177e4SLinus Torvalds #include <linux/mm.h> 131da177e4SLinus Torvalds #include <linux/threads.h> 141da177e4SLinus Torvalds #include <asm/addrspace.h> 151da177e4SLinus Torvalds #include <asm/page.h> 161da177e4SLinus Torvalds #include <asm/pgtable.h> 171da177e4SLinus Torvalds #include <asm/processor.h> 181da177e4SLinus Torvalds #include <asm/cache.h> 191da177e4SLinus Torvalds #include <asm/io.h> 20*7c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 211da177e4SLinus Torvalds #include <asm/pgalloc.h> 221da177e4SLinus Torvalds #include <asm/mmu_context.h> 231da177e4SLinus Torvalds #include <asm/cacheflush.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds /* 261da177e4SLinus Torvalds * Write back the dirty D-caches, but not invalidate them. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * Is this really worth it, or should we just alias this routine 291da177e4SLinus Torvalds * to __flush_purge_region too? 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds * START: Virtual Address (U0, P1, or P3) 321da177e4SLinus Torvalds * SIZE: Size of the region. 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds 3579f1c9daSPaul Mundt static void sh3__flush_wback_region(void *start, int size) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds unsigned long v, j; 381da177e4SLinus Torvalds unsigned long begin, end; 391da177e4SLinus Torvalds unsigned long flags; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 421da177e4SLinus Torvalds end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 431da177e4SLinus Torvalds & ~(L1_CACHE_BYTES-1); 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds for (v = begin; v < end; v+=L1_CACHE_BYTES) { 461da177e4SLinus Torvalds unsigned long addrstart = CACHE_OC_ADDRESS_ARRAY; 4711c19656SPaul Mundt for (j = 0; j < current_cpu_data.dcache.ways; j++) { 481da177e4SLinus Torvalds unsigned long data, addr, p; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds p = __pa(v); 5111c19656SPaul Mundt addr = addrstart | (v & current_cpu_data.dcache.entry_mask); 521da177e4SLinus Torvalds local_irq_save(flags); 539d56dd3bSPaul Mundt data = __raw_readl(addr); 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds if ((data & CACHE_PHYSADDR_MASK) == 561da177e4SLinus Torvalds (p & CACHE_PHYSADDR_MASK)) { 571da177e4SLinus Torvalds data &= ~SH_CACHE_UPDATED; 589d56dd3bSPaul Mundt __raw_writel(data, addr); 591da177e4SLinus Torvalds local_irq_restore(flags); 601da177e4SLinus Torvalds break; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds local_irq_restore(flags); 6311c19656SPaul Mundt addrstart += current_cpu_data.dcache.way_incr; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds /* 691da177e4SLinus Torvalds * Write back the dirty D-caches and invalidate them. 701da177e4SLinus Torvalds * 711da177e4SLinus Torvalds * START: Virtual Address (U0, P1, or P3) 721da177e4SLinus Torvalds * SIZE: Size of the region. 731da177e4SLinus Torvalds */ 7479f1c9daSPaul Mundt static void sh3__flush_purge_region(void *start, int size) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds unsigned long v; 771da177e4SLinus Torvalds unsigned long begin, end; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 801da177e4SLinus Torvalds end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 811da177e4SLinus Torvalds & ~(L1_CACHE_BYTES-1); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds for (v = begin; v < end; v+=L1_CACHE_BYTES) { 841da177e4SLinus Torvalds unsigned long data, addr; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds data = (v & 0xfffffc00); /* _Virtual_ address, ~U, ~V */ 871da177e4SLinus Torvalds addr = CACHE_OC_ADDRESS_ARRAY | 8811c19656SPaul Mundt (v & current_cpu_data.dcache.entry_mask) | SH_CACHE_ASSOC; 899d56dd3bSPaul Mundt __raw_writel(data, addr); 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 9379f1c9daSPaul Mundt void __init sh3_cache_init(void) 9479f1c9daSPaul Mundt { 9579f1c9daSPaul Mundt __flush_wback_region = sh3__flush_wback_region; 9679f1c9daSPaul Mundt __flush_purge_region = sh3__flush_purge_region; 9779f1c9daSPaul Mundt 981da177e4SLinus Torvalds /* 991da177e4SLinus Torvalds * No write back please 1001da177e4SLinus Torvalds * 10179f1c9daSPaul Mundt * Except I don't think there's any way to avoid the writeback. 10279f1c9daSPaul Mundt * So we just alias it to sh3__flush_purge_region(). dwmw2. 1031da177e4SLinus Torvalds */ 10479f1c9daSPaul Mundt __flush_invalidate_region = sh3__flush_purge_region; 10579f1c9daSPaul Mundt } 106