cache-sh4.c revision e7b8b7f16edc9b363573eadf2ab2683473626071
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arch/sh/mm/cache-sh4.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999, 2000, 2002 Niibe Yutaka 5d10040f7eb808cd984b563d1cf727a1020990a2ePaul Mundt * Copyright (C) 2001 - 2007 Paul Mundt 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Richard Curnow 709b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith * Copyright (c) 2007 STMicroelectronics (R&D) Ltd. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for more details. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 1552e27782e1c4afa1feca0fdf194d279595e0431cPaul Mundt#include <linux/io.h> 1652e27782e1c4afa1feca0fdf194d279595e0431cPaul Mundt#include <linux/mutex.h> 172277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt#include <linux/fs.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mmu_context.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cacheflush.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt/* 2228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * The maximum number of pages we support up to when doing ranged dcache 2328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * flushing. Anything exceeding this will simply flush the dcache in its 2428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * entirety. 2528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt */ 2628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ 2709b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith#define MAX_ICACHE_PAGES 32 2828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 29b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_dcache_segment_1way(unsigned long start, 30b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long extent); 31b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_dcache_segment_2way(unsigned long start, 32b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long extent); 33b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_dcache_segment_4way(unsigned long start, 34b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long extent); 35b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 36b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_cache_4096(unsigned long addr, unsigned long phys, 37a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt unsigned long exec_offset); 38b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 39b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow/* 40b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * This is initialised here to ensure that it is not placed in the BSS. If 41b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * that were to happen, note that cache_init gets called before the BSS is 42b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * cleared, so this would get nulled out which would be hopeless. 43b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 44b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = 45b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow (void (*)(unsigned long, unsigned long))0xdeadbeef; 46b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 47b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void compute_alias(struct cache_info *c) 48b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow{ 49b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); 50d10040f7eb808cd984b563d1cf727a1020990a2ePaul Mundt c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0; 51b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow} 52b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 53b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __init emit_cache_params(void) 54b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow{ 55b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow printk("PVR=%08x CVR=%08x PRR=%08x\n", 56b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow ctrl_inl(CCN_PVR), 57b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow ctrl_inl(CCN_CVR), 58b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow ctrl_inl(CCN_PRR)); 59b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n", 607ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.icache.ways, 617ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.icache.sets, 627ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.icache.way_incr); 63b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", 647ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.icache.entry_mask, 657ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.icache.alias_mask, 667ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.icache.n_aliases); 67b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n", 687ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.dcache.ways, 697ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.dcache.sets, 707ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.dcache.way_incr); 71b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", 727ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.dcache.entry_mask, 737ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.dcache.alias_mask, 747ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt boot_cpu_data.dcache.n_aliases); 75b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 76ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt /* 77ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt * Emit Secondary Cache parameters if the CPU has a probed L2. 78ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt */ 79ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) { 80ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt printk("S-cache : n_ways=%d n_sets=%d way_incr=%d\n", 81ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt boot_cpu_data.scache.ways, 82ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt boot_cpu_data.scache.sets, 83ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt boot_cpu_data.scache.way_incr); 84ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt printk("S-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", 85ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt boot_cpu_data.scache.entry_mask, 86ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt boot_cpu_data.scache.alias_mask, 87ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt boot_cpu_data.scache.n_aliases); 88ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt } 89ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt 90b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow if (!__flush_dcache_segment_fn) 91b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow panic("unknown number of cache ways\n"); 92b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow} 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SH-4 has virtually indexed and physically tagged cache. 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init p3_cache_init(void) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 997ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt compute_alias(&boot_cpu_data.icache); 1007ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt compute_alias(&boot_cpu_data.dcache); 101ab27f62002f4dc8f759c1ec069024d8173e5dea0Paul Mundt compute_alias(&boot_cpu_data.scache); 102b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 1037ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt switch (boot_cpu_data.dcache.ways) { 104b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow case 1: 105b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow __flush_dcache_segment_fn = __flush_dcache_segment_1way; 106b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow break; 107b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow case 2: 108b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow __flush_dcache_segment_fn = __flush_dcache_segment_2way; 109b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow break; 110b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow case 4: 111b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow __flush_dcache_segment_fn = __flush_dcache_segment_4way; 112b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow break; 113b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow default: 114b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow __flush_dcache_segment_fn = NULL; 115b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow break; 116b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } 117b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 118b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow emit_cache_params(); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write back the range of D-cache, and purge the I-cache. 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12409b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith * Called from kernel/module.c:sys_init_module and routine for a.out format, 12509b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith * signal handler code and kprobes code 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid flush_icache_range(unsigned long start, unsigned long end) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12909b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith int icacheaddr; 13009b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith unsigned long flags, v; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13309b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith /* If there are too many pages then just blow the caches */ 13409b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { 13509b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith flush_cache_all(); 13609b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith } else { 13709b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith /* selectively flush d-cache then invalidate the i-cache */ 13809b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith /* this is inefficient, so only use for small ranges */ 13909b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith start &= ~(L1_CACHE_BYTES-1); 14009b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith end += L1_CACHE_BYTES-1; 14109b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith end &= ~(L1_CACHE_BYTES-1); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14309b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith local_irq_save(flags); 14409b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith jump_to_uncached(); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14609b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith for (v = start; v < end; v+=L1_CACHE_BYTES) { 14709b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith asm volatile("ocbwb %0" 14809b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith : /* no output */ 14909b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith : "m" (__m(v))); 150b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 15109b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( 15209b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith v & cpu_data->icache.entry_mask); 153b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 15409b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith for (i = 0; i < cpu_data->icache.ways; 15509b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith i++, icacheaddr += cpu_data->icache.way_incr) 15609b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith /* Clear i-cache line valid-bit */ 15709b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith ctrl_outl(0, icacheaddr); 15809b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith } 15909b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith 16009b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith back_to_cached(); 16109b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith local_irq_restore(flags); 16209b5a10c1944214a6008712bfa92b29f00b84a1aChris Smith } 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void flush_cache_4096(unsigned long start, 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long phys) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16833573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt unsigned long flags, exec_offset = 0; 16933573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 171b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * All types of SH-4 require PC to be in P2 to operate on the I-cache. 172b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * Some types of SH-4 require PC to be in P2 to operate on the D-cache. 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1747ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) || 17533573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt (start < CACHE_OC_ADDRESS_ARRAY)) 176510c72ad2dd4e05e6908755f51ac89482c6eb987Paul Mundt exec_offset = 0x20000000; 17733573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt 17833573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt local_irq_save(flags); 17933573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt __flush_cache_4096(start | SH_CACHE_ASSOC, 18033573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt P1SEGADDR(phys), exec_offset); 18133573c0e3243aaa38b6ad96942de85a1b713c2ffPaul Mundt local_irq_restore(flags); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write back & invalidate the D-cache of the page. 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (To avoid "alias" issues) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid flush_dcache_page(struct page *page) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1902277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt struct address_space *mapping = page_mapping(page); 1912277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt 1922277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt#ifndef CONFIG_SMP 1932277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt if (mapping && !mapping_mapped(mapping)) 1942277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt set_bit(PG_dcache_dirty, &page->flags); 1952277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt else 1962277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt#endif 1972277ab4a1df50e05bc732fe9488d4e902bb8399aPaul Mundt { 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long phys = PHYSADDR(page_address(page)); 199b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long addr = CACHE_OC_ADDRESS_ARRAY; 200b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow int i, n; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Loop all the D-cache */ 2037ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt n = boot_cpu_data.dcache.n_aliases; 204510c72ad2dd4e05e6908755f51ac89482c6eb987Paul Mundt for (i = 0; i < n; i++, addr += 4096) 205b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow flush_cache_4096(addr, phys); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 207fdfc74f9fcebdda14609159d5010b758a9409acfPaul Mundt 208fdfc74f9fcebdda14609159d5010b758a9409acfPaul Mundt wmb(); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt/* TODO: Selective icache invalidation through IC address array.. */ 212205a3b4328de1c8ddd99ddd5092bed1344068213Paul Mundtstatic void __uses_jump_to_uncached flush_icache_all(void) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags, ccr; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 217cbaa118ecfd99fc5ed7adbd9c34a30e1c05e3c93Stuart Menefy jump_to_uncached(); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flush I-cache */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccr = ctrl_inl(CCR); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccr |= CCR_CACHE_ICI; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl_outl(ccr, CCR); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 224298476220d1f793ca0ac6c9e5dc817e1ad3e9851Paul Mundt /* 225cbaa118ecfd99fc5ed7adbd9c34a30e1c05e3c93Stuart Menefy * back_to_cached() will take care of the barrier for us, don't add 226298476220d1f793ca0ac6c9e5dc817e1ad3e9851Paul Mundt * another one! 227298476220d1f793ca0ac6c9e5dc817e1ad3e9851Paul Mundt */ 228298476220d1f793ca0ac6c9e5dc817e1ad3e9851Paul Mundt 229cbaa118ecfd99fc5ed7adbd9c34a30e1c05e3c93Stuart Menefy back_to_cached(); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 233a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundtvoid flush_dcache_all(void) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2357ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size); 236fdfc74f9fcebdda14609159d5010b758a9409acfPaul Mundt wmb(); 237a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt} 238a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt 239a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundtvoid flush_cache_all(void) 240a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt{ 241a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt flush_dcache_all(); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_icache_all(); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundtstatic void __flush_cache_mm(struct mm_struct *mm, unsigned long start, 24628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt unsigned long end) 24728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt{ 24828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt unsigned long d = 0, p = start & PAGE_MASK; 2497ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt unsigned long alias_mask = boot_cpu_data.dcache.alias_mask; 2507ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt unsigned long n_aliases = boot_cpu_data.dcache.n_aliases; 25128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt unsigned long select_bit; 25228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt unsigned long all_aliases_mask; 25328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt unsigned long addr_offset; 25428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pgd_t *dir; 25528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pmd_t *pmd; 25628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pud_t *pud; 25728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pte_t *pte; 25828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt int i; 25928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 26028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt dir = pgd_offset(mm, p); 26128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pud = pud_offset(dir, p); 26228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pmd = pmd_offset(pud, p); 26328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt end = PAGE_ALIGN(end); 26428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 26528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt all_aliases_mask = (1 << n_aliases) - 1; 26628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 26728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt do { 26828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { 26928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt p &= PMD_MASK; 27028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt p += PMD_SIZE; 27128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pmd++; 27228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 27328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt continue; 27428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } 27528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 27628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pte = pte_offset_kernel(pmd, p); 27728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 27828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt do { 27928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt unsigned long phys; 28028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pte_t entry = *pte; 28128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 28228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if (!(pte_val(entry) & _PAGE_PRESENT)) { 28328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pte++; 28428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt p += PAGE_SIZE; 28528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt continue; 28628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } 28728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 28828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt phys = pte_val(entry) & PTE_PHYS_MASK; 28928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 29028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if ((p ^ phys) & alias_mask) { 29128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt d |= 1 << ((p & alias_mask) >> PAGE_SHIFT); 29228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT); 29328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 29428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if (d == all_aliases_mask) 29528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt goto loop_exit; 29628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } 29728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 29828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pte++; 29928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt p += PAGE_SIZE; 30028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } while (p < end && ((unsigned long)pte & ~PAGE_MASK)); 30128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt pmd++; 30228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } while (p < end); 30328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 30428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundtloop_exit: 30528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt addr_offset = 0; 30628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt select_bit = 1; 30728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 30828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt for (i = 0; i < n_aliases; i++) { 30928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if (d & select_bit) { 31028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE); 31128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt wmb(); 31228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } 31328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 31428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt select_bit <<= 1; 31528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt addr_offset += PAGE_SIZE; 31628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } 31728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt} 31828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 31928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt/* 32028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * Note : (RPC) since the caches are physically tagged, the only point 32128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * of flush_cache_mm for SH-4 is to get rid of aliases from the 32228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * D-cache. The assumption elsewhere, e.g. flush_cache_range, is that 32328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * lines can stay resident so long as the virtual address they were 32428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * accessed with (hence cache set) is in accord with the physical 32528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * address (i.e. tag). It's no different here. So I reckon we don't 32628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * need to flush the I-cache, since aliases don't matter for that. We 32728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * should try that. 32828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * 32928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * Caller takes mm->mmap_sem. 33028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt */ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid flush_cache_mm(struct mm_struct *mm) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 333e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT) 334e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt return; 335e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt 336b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 33728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * If cache is only 4k-per-way, there are never any 'aliases'. Since 33828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * the cache is physically tagged, the data can just be left in there. 33928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt */ 3407ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt if (boot_cpu_data.dcache.n_aliases == 0) 34128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt return; 34228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 34328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt /* 34428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * Don't bother groveling around the dcache for the VMA ranges 34528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * if there are too many PTEs to make it worthwhile. 346b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 34728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if (mm->nr_ptes >= MAX_DCACHE_PAGES) 34828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt flush_dcache_all(); 34928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt else { 35028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt struct vm_area_struct *vma; 35128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 35228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt /* 35328ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * In this case there are reasonably sized ranges to flush, 35428ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt * iterate through the VMA list and take care of any aliases. 35528ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt */ 35628ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt for (vma = mm->mmap; vma; vma = vma->vm_next) 35728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt __flush_cache_mm(mm, vma->vm_start, vma->vm_end); 35828ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt } 35928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt 36028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt /* Only touch the icache if one of the VMAs has VM_EXEC set. */ 36128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if (mm->exec_vm) 36228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt flush_icache_all(); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write back and invalidate I/D-caches for the page. 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ADDR: Virtual Address (U0 address) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PFN: Physical page number 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37128ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundtvoid flush_cache_page(struct vm_area_struct *vma, unsigned long address, 37228ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt unsigned long pfn) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long phys = pfn << PAGE_SHIFT; 375b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned int alias_mask; 376b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 377e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) 378e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt return; 379e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt 3807ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt alias_mask = boot_cpu_data.dcache.alias_mask; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We only need to flush D-cache when we have alias */ 383b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow if ((address^phys) & alias_mask) { 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Loop 4K of the D-cache */ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_cache_4096( 386b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow CACHE_OC_ADDRESS_ARRAY | (address & alias_mask), 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Loop another 4K of the D-cache */ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_cache_4096( 390b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask), 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3947ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt alias_mask = boot_cpu_data.icache.alias_mask; 395b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow if (vma->vm_flags & VM_EXEC) { 396b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 397b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * Evict entries from the portion of the cache from which code 398b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * may have been executed at this address (virtual). There's 399b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * no need to evict from the portion corresponding to the 400b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * physical address as for the D-cache, because we know the 401b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * kernel has never executed the code through its identity 402b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * translation. 403b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_cache_4096( 405b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow CACHE_IC_ADDRESS_ARRAY | (address & alias_mask), 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys); 407b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write back and invalidate D-caches. 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * START, END: Virtual Address (U0 address) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: We need to flush the _physical_ page entry. 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Flushing the cache lines for U0 only isn't enough. 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to flush for P1 too, which may contain aliases. 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid flush_cache_range(struct vm_area_struct *vma, unsigned long start, 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long end) 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 422e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) 423e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt return; 424e7b8b7f16edc9b363573eadf2ab2683473626071Paul Mundt 425b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 426b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * If cache is only 4k-per-way, there are never any 'aliases'. Since 427b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * the cache is physically tagged, the data can just be left in there. 428b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 4297ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt if (boot_cpu_data.dcache.n_aliases == 0) 430b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow return; 431b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 432a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt /* 433a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt * Don't bother with the lookup and alias check if we have a 434a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt * wide range to cover, just blow away the dcache in its 435a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt * entirety instead. -- PFM. 436a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt */ 43728ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES) 438a252710fc5b63b24934905ca47ecf661702d7f00Paul Mundt flush_dcache_all(); 43928ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt else 44028ccf7f91b1ac42ee1f18480a69d2a7486b625cePaul Mundt __flush_cache_mm(vma->vm_mm, start, end); 441b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 442b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow if (vma->vm_flags & VM_EXEC) { 443b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 444b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * TODO: Is this required??? Need to look at how I-cache 445b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * coherency is assured when new programs are loaded to see if 446b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * this matters. 447b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_icache_all(); 449b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * flush_icache_user_range 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @vma: VMA of the process 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @page: page 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @addr: U0 address 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: length of the range (< page size) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid flush_icache_user_range(struct vm_area_struct *vma, 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct page *page, unsigned long addr, int len) 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_cache_page(vma, addr, page_to_pfn(page)); 463fdfc74f9fcebdda14609159d5010b758a9409acfPaul Mundt mb(); 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 466b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow/** 467b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * __flush_cache_4096 468b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * 469b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * @addr: address in memory mapped cache array 470b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * @phys: P1 address to flush (has to match tags if addr has 'A' bit 471b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * set i.e. associative write) 472b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * @exec_offset: set to 0x20000000 if flush has to be executed from P2 473b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * region else 0x0 474b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * 475b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * The offset into the cache array implied by 'addr' selects the 476b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * 'colour' of the virtual address range that will be flushed. The 477b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * operation (purge/write-back) is selected by the lower 2 bits of 478b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * 'phys'. 479b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 480b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_cache_4096(unsigned long addr, unsigned long phys, 481b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long exec_offset) 482b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow{ 483b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow int way_count; 484b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long base_addr = addr; 485b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow struct cache_info *dcache; 486b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long way_incr; 487b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long a, ea, p; 488b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long temp_pc; 489b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 4907ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt dcache = &boot_cpu_data.dcache; 491b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* Write this way for better assembly. */ 492b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_count = dcache->ways; 493b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_incr = dcache->way_incr; 494b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 495b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 496b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * Apply exec_offset (i.e. branch to P2 if required.). 497b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * 498b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * FIXME: 499b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * 500b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * If I write "=r" for the (temp_pc), it puts this in r6 hence 501b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * trashing exec_offset before it's been added on - why? Hence 502b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * "=&r" as a 'workaround' 503b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 504b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("mov.l 1f, %0\n\t" 505b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "add %1, %0\n\t" 506b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "jmp @%0\n\t" 507b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "nop\n\t" 508b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow ".balign 4\n\t" 509b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "1: .long 2f\n\t" 510b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "2:\n" : "=&r" (temp_pc) : "r" (exec_offset)); 511b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 512b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 513b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * We know there will be >=1 iteration, so write as do-while to avoid 514b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * pointless nead-of-loop check for 0 iterations. 515b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 516b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow do { 517b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow ea = base_addr + PAGE_SIZE; 518b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a = base_addr; 519b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow p = phys; 520b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 521b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow do { 522b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow *(volatile unsigned long *)a = p; 523b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 524b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * Next line: intentionally not p+32, saves an add, p 525b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * will do since only the cache tag bits need to 526b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * match. 527b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 528b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow *(volatile unsigned long *)(a+32) = p; 529b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a += 64; 530b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow p += 64; 531b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } while (a < ea); 532b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 533b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr += way_incr; 534b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } while (--way_count != 0); 535b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow} 536b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 537b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow/* 538b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * Break the 1, 2 and 4 way variants of this out into separate functions to 539b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * avoid nearly all the overhead of having the conditional stuff in the function 540b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * bodies (+ the 1 and 2 way cases avoid saving any registers too). 541b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 542b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_dcache_segment_1way(unsigned long start, 543b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long extent_per_way) 544b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow{ 545b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long orig_sr, sr_with_bl; 546b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long base_addr; 547b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long way_incr, linesz, way_size; 548b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow struct cache_info *dcache; 549b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow register unsigned long a0, a0e; 550b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 551b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("stc sr, %0" : "=r" (orig_sr)); 552b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow sr_with_bl = orig_sr | (1<<28); 553b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr = ((unsigned long)&empty_zero_page[0]); 554b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 555b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* 556b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * The previous code aligned base_addr to 16k, i.e. the way_size of all 557b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * existing SH-4 D-caches. Whilst I don't see a need to have this 558b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * aligned to any better than the cache line size (which it will be 559b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * anyway by construction), let's align it to at least the way_size of 560b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow * any existing or conceivable SH-4 D-cache. -- RPC 561b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow */ 562b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr = ((base_addr >> 16) << 16); 563b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr |= start; 564b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 5657ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt dcache = &boot_cpu_data.dcache; 566b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow linesz = dcache->linesz; 567b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_incr = dcache->way_incr; 568b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_size = dcache->way_size; 569b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 570b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 = base_addr; 571b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0e = base_addr + extent_per_way; 572b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow do { 573b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); 574b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 575b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0" : : "r" (a0)); 576b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 577b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 578b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0" : : "r" (a0)); 579b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 580b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 581b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0" : : "r" (a0)); 582b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 583b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 584b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0" : : "r" (a0)); 585b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("ldc %0, sr" : : "r" (orig_sr)); 586b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 587b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } while (a0 < a0e); 588b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow} 589b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 590b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_dcache_segment_2way(unsigned long start, 591b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long extent_per_way) 592b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow{ 593b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long orig_sr, sr_with_bl; 594b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long base_addr; 595b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long way_incr, linesz, way_size; 596b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow struct cache_info *dcache; 597b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow register unsigned long a0, a1, a0e; 598b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 599b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("stc sr, %0" : "=r" (orig_sr)); 600b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow sr_with_bl = orig_sr | (1<<28); 601b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr = ((unsigned long)&empty_zero_page[0]); 602b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 603b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* See comment under 1-way above */ 604b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr = ((base_addr >> 16) << 16); 605b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr |= start; 606b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 6077ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt dcache = &boot_cpu_data.dcache; 608b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow linesz = dcache->linesz; 609b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_incr = dcache->way_incr; 610b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_size = dcache->way_size; 611b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 612b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 = base_addr; 613b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 = a0 + way_incr; 614b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0e = base_addr + extent_per_way; 615b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow do { 616b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); 617b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 618b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 619b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 620b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1" : : 621b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1)); 622b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 623b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 624b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 625b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 626b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 627b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1" : : 628b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1)); 629b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 630b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 631b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 632b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 633b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 634b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1" : : 635b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1)); 636b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 637b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 638b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 639b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 640b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 641b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1" : : 642b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1)); 643b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("ldc %0, sr" : : "r" (orig_sr)); 644b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 645b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 646b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } while (a0 < a0e); 647b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow} 648b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 649b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnowstatic void __flush_dcache_segment_4way(unsigned long start, 650b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long extent_per_way) 651b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow{ 652b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long orig_sr, sr_with_bl; 653b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long base_addr; 654b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow unsigned long way_incr, linesz, way_size; 655b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow struct cache_info *dcache; 656b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow register unsigned long a0, a1, a2, a3, a0e; 657b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 658b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("stc sr, %0" : "=r" (orig_sr)); 659b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow sr_with_bl = orig_sr | (1<<28); 660b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr = ((unsigned long)&empty_zero_page[0]); 661b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 662b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow /* See comment under 1-way above */ 663b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr = ((base_addr >> 16) << 16); 664b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow base_addr |= start; 665b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 6667ec9d6f8c0e6932d380da1964021fbebf2311f04Paul Mundt dcache = &boot_cpu_data.dcache; 667b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow linesz = dcache->linesz; 668b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_incr = dcache->way_incr; 669b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow way_size = dcache->way_size; 670b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow 671b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 = base_addr; 672b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 = a0 + way_incr; 673b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a2 = a1 + way_incr; 674b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a3 = a2 + way_incr; 675b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0e = base_addr + extent_per_way; 676b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow do { 677b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); 678b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 679b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 680b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%2\n\t" 681b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%3\n\t" 682b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 683b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1\n\t" 684b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%2\n\t" 685b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%3\n\t" : : 686b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 687b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 688b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 689b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a2 += linesz; 690b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a3 += linesz; 691b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 692b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 693b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%2\n\t" 694b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%3\n\t" 695b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 696b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1\n\t" 697b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%2\n\t" 698b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%3\n\t" : : 699b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 700b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 701b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 702b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a2 += linesz; 703b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a3 += linesz; 704b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 705b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 706b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%2\n\t" 707b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%3\n\t" 708b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 709b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1\n\t" 710b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%2\n\t" 711b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%3\n\t" : : 712b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 713b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 714b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 715b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a2 += linesz; 716b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a3 += linesz; 717b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("movca.l r0, @%0\n\t" 718b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%1\n\t" 719b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%2\n\t" 720b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "movca.l r0, @%3\n\t" 721b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%0\n\t" 722b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%1\n\t" 723b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%2\n\t" 724b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "ocbi @%3\n\t" : : 725b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow "r" (a0), "r" (a1), "r" (a2), "r" (a3)); 726b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow asm volatile("ldc %0, sr" : : "r" (orig_sr)); 727b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a0 += linesz; 728b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a1 += linesz; 729b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a2 += linesz; 730b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow a3 += linesz; 731b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow } while (a0 < a0e); 732b638d0b921dc95229af0dfd09cd24850336a2f75Richard Curnow} 733