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