18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Inline assembly cache operations.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
98c2ecf20Sopenharmony_ci * Copyright (C) 1997 - 2002 Ralf Baechle (ralf@gnu.org)
108c2ecf20Sopenharmony_ci * Copyright (C) 2004 Ralf Baechle (ralf@linux-mips.org)
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#ifndef _ASM_R4KCACHE_H
138c2ecf20Sopenharmony_ci#define _ASM_R4KCACHE_H
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/stringify.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/asm.h>
188c2ecf20Sopenharmony_ci#include <asm/asm-eva.h>
198c2ecf20Sopenharmony_ci#include <asm/cacheops.h>
208c2ecf20Sopenharmony_ci#include <asm/compiler.h>
218c2ecf20Sopenharmony_ci#include <asm/cpu-features.h>
228c2ecf20Sopenharmony_ci#include <asm/cpu-type.h>
238c2ecf20Sopenharmony_ci#include <asm/mipsmtregs.h>
248c2ecf20Sopenharmony_ci#include <asm/mmzone.h>
258c2ecf20Sopenharmony_ci#include <asm/unroll.h>
268c2ecf20Sopenharmony_ci#include <linux/uaccess.h> /* for uaccess_kernel() */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciextern void (*r4k_blast_dcache)(void);
298c2ecf20Sopenharmony_ciextern void (*r4k_blast_icache)(void);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/*
328c2ecf20Sopenharmony_ci * This macro return a properly sign-extended address suitable as base address
338c2ecf20Sopenharmony_ci * for indexed cache operations.  Two issues here:
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci *  - The MIPS32 and MIPS64 specs permit an implementation to directly derive
368c2ecf20Sopenharmony_ci *    the index bits from the virtual address.	This breaks with tradition
378c2ecf20Sopenharmony_ci *    set by the R4000.	 To keep unpleasant surprises from happening we pick
388c2ecf20Sopenharmony_ci *    an address in KSEG0 / CKSEG0.
398c2ecf20Sopenharmony_ci *  - We need a properly sign extended address for 64-bit code.	 To get away
408c2ecf20Sopenharmony_ci *    without ifdefs we let the compiler do it by a type cast.
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_ci#define INDEX_BASE	CKSEG0
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define _cache_op(insn, op, addr)					\
458c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
468c2ecf20Sopenharmony_ci	"	.set	push					\n"	\
478c2ecf20Sopenharmony_ci	"	.set	noreorder				\n"	\
488c2ecf20Sopenharmony_ci	"	.set "MIPS_ISA_ARCH_LEVEL"			\n"	\
498c2ecf20Sopenharmony_ci	"	" insn("%0", "%1") "				\n"	\
508c2ecf20Sopenharmony_ci	"	.set	pop					\n"	\
518c2ecf20Sopenharmony_ci	:								\
528c2ecf20Sopenharmony_ci	: "i" (op), "R" (*(unsigned char *)(addr)))
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define cache_op(op, addr)						\
558c2ecf20Sopenharmony_ci	_cache_op(kernel_cache, op, addr)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline void flush_icache_line_indexed(unsigned long addr)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	cache_op(Index_Invalidate_I, addr);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic inline void flush_dcache_line_indexed(unsigned long addr)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	cache_op(Index_Writeback_Inv_D, addr);
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic inline void flush_scache_line_indexed(unsigned long addr)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	cache_op(Index_Writeback_Inv_SD, addr);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic inline void flush_icache_line(unsigned long addr)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	switch (boot_cpu_type()) {
758c2ecf20Sopenharmony_ci	case CPU_LOONGSON2EF:
768c2ecf20Sopenharmony_ci		cache_op(Hit_Invalidate_I_Loongson2, addr);
778c2ecf20Sopenharmony_ci		break;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	default:
808c2ecf20Sopenharmony_ci		cache_op(Hit_Invalidate_I, addr);
818c2ecf20Sopenharmony_ci		break;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic inline void flush_dcache_line(unsigned long addr)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	cache_op(Hit_Writeback_Inv_D, addr);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic inline void invalidate_dcache_line(unsigned long addr)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	cache_op(Hit_Invalidate_D, addr);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic inline void invalidate_scache_line(unsigned long addr)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	cache_op(Hit_Invalidate_SD, addr);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic inline void flush_scache_line(unsigned long addr)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	cache_op(Hit_Writeback_Inv_SD, addr);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#define protected_cache_op(op,addr)				\
1068c2ecf20Sopenharmony_ci({								\
1078c2ecf20Sopenharmony_ci	int __err = 0;						\
1088c2ecf20Sopenharmony_ci	__asm__ __volatile__(					\
1098c2ecf20Sopenharmony_ci	"	.set	push			\n"		\
1108c2ecf20Sopenharmony_ci	"	.set	noreorder		\n"		\
1118c2ecf20Sopenharmony_ci	"	.set "MIPS_ISA_ARCH_LEVEL"	\n"		\
1128c2ecf20Sopenharmony_ci	"1:	cache	%1, (%2)		\n"		\
1138c2ecf20Sopenharmony_ci	"2:	.insn				\n"		\
1148c2ecf20Sopenharmony_ci	"	.set	pop			\n"		\
1158c2ecf20Sopenharmony_ci	"	.section .fixup,\"ax\"		\n"		\
1168c2ecf20Sopenharmony_ci	"3:	li	%0, %3			\n"		\
1178c2ecf20Sopenharmony_ci	"	j	2b			\n"		\
1188c2ecf20Sopenharmony_ci	"	.previous			\n"		\
1198c2ecf20Sopenharmony_ci	"	.section __ex_table,\"a\"	\n"		\
1208c2ecf20Sopenharmony_ci	"	"STR(PTR)" 1b, 3b		\n"		\
1218c2ecf20Sopenharmony_ci	"	.previous"					\
1228c2ecf20Sopenharmony_ci	: "+r" (__err)						\
1238c2ecf20Sopenharmony_ci	: "i" (op), "r" (addr), "i" (-EFAULT));			\
1248c2ecf20Sopenharmony_ci	__err;							\
1258c2ecf20Sopenharmony_ci})
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#define protected_cachee_op(op,addr)				\
1298c2ecf20Sopenharmony_ci({								\
1308c2ecf20Sopenharmony_ci	int __err = 0;						\
1318c2ecf20Sopenharmony_ci	__asm__ __volatile__(					\
1328c2ecf20Sopenharmony_ci	"	.set	push			\n"		\
1338c2ecf20Sopenharmony_ci	"	.set	noreorder		\n"		\
1348c2ecf20Sopenharmony_ci	"	.set	mips0			\n"		\
1358c2ecf20Sopenharmony_ci	"	.set	eva			\n"		\
1368c2ecf20Sopenharmony_ci	"1:	cachee	%1, (%2)		\n"		\
1378c2ecf20Sopenharmony_ci	"2:	.insn				\n"		\
1388c2ecf20Sopenharmony_ci	"	.set	pop			\n"		\
1398c2ecf20Sopenharmony_ci	"	.section .fixup,\"ax\"		\n"		\
1408c2ecf20Sopenharmony_ci	"3:	li	%0, %3			\n"		\
1418c2ecf20Sopenharmony_ci	"	j	2b			\n"		\
1428c2ecf20Sopenharmony_ci	"	.previous			\n"		\
1438c2ecf20Sopenharmony_ci	"	.section __ex_table,\"a\"	\n"		\
1448c2ecf20Sopenharmony_ci	"	"STR(PTR)" 1b, 3b		\n"		\
1458c2ecf20Sopenharmony_ci	"	.previous"					\
1468c2ecf20Sopenharmony_ci	: "+r" (__err)						\
1478c2ecf20Sopenharmony_ci	: "i" (op), "r" (addr), "i" (-EFAULT));			\
1488c2ecf20Sopenharmony_ci	__err;							\
1498c2ecf20Sopenharmony_ci})
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/*
1528c2ecf20Sopenharmony_ci * The next two are for badland addresses like signal trampolines.
1538c2ecf20Sopenharmony_ci */
1548c2ecf20Sopenharmony_cistatic inline int protected_flush_icache_line(unsigned long addr)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	switch (boot_cpu_type()) {
1578c2ecf20Sopenharmony_ci	case CPU_LOONGSON2EF:
1588c2ecf20Sopenharmony_ci		return protected_cache_op(Hit_Invalidate_I_Loongson2, addr);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	default:
1618c2ecf20Sopenharmony_ci#ifdef CONFIG_EVA
1628c2ecf20Sopenharmony_ci		return protected_cachee_op(Hit_Invalidate_I, addr);
1638c2ecf20Sopenharmony_ci#else
1648c2ecf20Sopenharmony_ci		return protected_cache_op(Hit_Invalidate_I, addr);
1658c2ecf20Sopenharmony_ci#endif
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/*
1708c2ecf20Sopenharmony_ci * R10000 / R12000 hazard - these processors don't support the Hit_Writeback_D
1718c2ecf20Sopenharmony_ci * cacheop so we use Hit_Writeback_Inv_D which is supported by all R4000-style
1728c2ecf20Sopenharmony_ci * caches.  We're talking about one cacheline unnecessarily getting invalidated
1738c2ecf20Sopenharmony_ci * here so the penalty isn't overly hard.
1748c2ecf20Sopenharmony_ci */
1758c2ecf20Sopenharmony_cistatic inline int protected_writeback_dcache_line(unsigned long addr)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci#ifdef CONFIG_EVA
1788c2ecf20Sopenharmony_ci	return protected_cachee_op(Hit_Writeback_Inv_D, addr);
1798c2ecf20Sopenharmony_ci#else
1808c2ecf20Sopenharmony_ci	return protected_cache_op(Hit_Writeback_Inv_D, addr);
1818c2ecf20Sopenharmony_ci#endif
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic inline int protected_writeback_scache_line(unsigned long addr)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci#ifdef CONFIG_EVA
1878c2ecf20Sopenharmony_ci	return protected_cachee_op(Hit_Writeback_Inv_SD, addr);
1888c2ecf20Sopenharmony_ci#else
1898c2ecf20Sopenharmony_ci	return protected_cache_op(Hit_Writeback_Inv_SD, addr);
1908c2ecf20Sopenharmony_ci#endif
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/*
1948c2ecf20Sopenharmony_ci * This one is RM7000-specific
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_cistatic inline void invalidate_tcache_page(unsigned long addr)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	cache_op(Page_Invalidate_T, addr);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci#define cache_unroll(times, insn, op, addr, lsize) do {			\
2028c2ecf20Sopenharmony_ci	int i = 0;							\
2038c2ecf20Sopenharmony_ci	unroll(times, _cache_op, insn, op, (addr) + (i++ * (lsize)));	\
2048c2ecf20Sopenharmony_ci} while (0)
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
2078c2ecf20Sopenharmony_ci#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, extra)	\
2088c2ecf20Sopenharmony_cistatic inline void extra##blast_##pfx##cache##lsize(void)		\
2098c2ecf20Sopenharmony_ci{									\
2108c2ecf20Sopenharmony_ci	unsigned long start = INDEX_BASE;				\
2118c2ecf20Sopenharmony_ci	unsigned long end = start + current_cpu_data.desc.waysize;	\
2128c2ecf20Sopenharmony_ci	unsigned long ws_inc = 1UL << current_cpu_data.desc.waybit;	\
2138c2ecf20Sopenharmony_ci	unsigned long ws_end = current_cpu_data.desc.ways <<		\
2148c2ecf20Sopenharmony_ci			       current_cpu_data.desc.waybit;		\
2158c2ecf20Sopenharmony_ci	unsigned long ws, addr;						\
2168c2ecf20Sopenharmony_ci									\
2178c2ecf20Sopenharmony_ci	for (ws = 0; ws < ws_end; ws += ws_inc)				\
2188c2ecf20Sopenharmony_ci		for (addr = start; addr < end; addr += lsize * 32)	\
2198c2ecf20Sopenharmony_ci			cache_unroll(32, kernel_cache, indexop,		\
2208c2ecf20Sopenharmony_ci				     addr | ws, lsize);			\
2218c2ecf20Sopenharmony_ci}									\
2228c2ecf20Sopenharmony_ci									\
2238c2ecf20Sopenharmony_cistatic inline void extra##blast_##pfx##cache##lsize##_page(unsigned long page) \
2248c2ecf20Sopenharmony_ci{									\
2258c2ecf20Sopenharmony_ci	unsigned long start = page;					\
2268c2ecf20Sopenharmony_ci	unsigned long end = page + PAGE_SIZE;				\
2278c2ecf20Sopenharmony_ci									\
2288c2ecf20Sopenharmony_ci	do {								\
2298c2ecf20Sopenharmony_ci		cache_unroll(32, kernel_cache, hitop, start, lsize);	\
2308c2ecf20Sopenharmony_ci		start += lsize * 32;					\
2318c2ecf20Sopenharmony_ci	} while (start < end);						\
2328c2ecf20Sopenharmony_ci}									\
2338c2ecf20Sopenharmony_ci									\
2348c2ecf20Sopenharmony_cistatic inline void extra##blast_##pfx##cache##lsize##_page_indexed(unsigned long page) \
2358c2ecf20Sopenharmony_ci{									\
2368c2ecf20Sopenharmony_ci	unsigned long indexmask = current_cpu_data.desc.waysize - 1;	\
2378c2ecf20Sopenharmony_ci	unsigned long start = INDEX_BASE + (page & indexmask);		\
2388c2ecf20Sopenharmony_ci	unsigned long end = start + PAGE_SIZE;				\
2398c2ecf20Sopenharmony_ci	unsigned long ws_inc = 1UL << current_cpu_data.desc.waybit;	\
2408c2ecf20Sopenharmony_ci	unsigned long ws_end = current_cpu_data.desc.ways <<		\
2418c2ecf20Sopenharmony_ci			       current_cpu_data.desc.waybit;		\
2428c2ecf20Sopenharmony_ci	unsigned long ws, addr;						\
2438c2ecf20Sopenharmony_ci									\
2448c2ecf20Sopenharmony_ci	for (ws = 0; ws < ws_end; ws += ws_inc)				\
2458c2ecf20Sopenharmony_ci		for (addr = start; addr < end; addr += lsize * 32)	\
2468c2ecf20Sopenharmony_ci			cache_unroll(32, kernel_cache, indexop,		\
2478c2ecf20Sopenharmony_ci				     addr | ws, lsize);			\
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, )
2518c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, )
2528c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
2538c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32, )
2548c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32, )
2558c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I_Loongson2, 32, loongson2_)
2568c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, )
2578c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64, )
2588c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, )
2598c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
2608c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 128, )
2618c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 128, )
2628c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, )
2658c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32, )
2668c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16, )
2678c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32, )
2688c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
2698c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci#define __BUILD_BLAST_USER_CACHE(pfx, desc, indexop, hitop, lsize) \
2728c2ecf20Sopenharmony_cistatic inline void blast_##pfx##cache##lsize##_user_page(unsigned long page) \
2738c2ecf20Sopenharmony_ci{									\
2748c2ecf20Sopenharmony_ci	unsigned long start = page;					\
2758c2ecf20Sopenharmony_ci	unsigned long end = page + PAGE_SIZE;				\
2768c2ecf20Sopenharmony_ci									\
2778c2ecf20Sopenharmony_ci	do {								\
2788c2ecf20Sopenharmony_ci		cache_unroll(32, user_cache, hitop, start, lsize);	\
2798c2ecf20Sopenharmony_ci		start += lsize * 32;					\
2808c2ecf20Sopenharmony_ci	} while (start < end);						\
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
2848c2ecf20Sopenharmony_ci			 16)
2858c2ecf20Sopenharmony_ci__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
2868c2ecf20Sopenharmony_ci__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
2878c2ecf20Sopenharmony_ci			 32)
2888c2ecf20Sopenharmony_ci__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
2898c2ecf20Sopenharmony_ci__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
2908c2ecf20Sopenharmony_ci			 64)
2918c2ecf20Sopenharmony_ci__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/* build blast_xxx_range, protected_blast_xxx_range */
2948c2ecf20Sopenharmony_ci#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, extra)	\
2958c2ecf20Sopenharmony_cistatic inline void prot##extra##blast_##pfx##cache##_range(unsigned long start, \
2968c2ecf20Sopenharmony_ci						    unsigned long end)	\
2978c2ecf20Sopenharmony_ci{									\
2988c2ecf20Sopenharmony_ci	unsigned long lsize = cpu_##desc##_line_size();			\
2998c2ecf20Sopenharmony_ci	unsigned long addr = start & ~(lsize - 1);			\
3008c2ecf20Sopenharmony_ci	unsigned long aend = (end - 1) & ~(lsize - 1);			\
3018c2ecf20Sopenharmony_ci									\
3028c2ecf20Sopenharmony_ci	while (1) {							\
3038c2ecf20Sopenharmony_ci		prot##cache_op(hitop, addr);				\
3048c2ecf20Sopenharmony_ci		if (addr == aend)					\
3058c2ecf20Sopenharmony_ci			break;						\
3068c2ecf20Sopenharmony_ci		addr += lsize;						\
3078c2ecf20Sopenharmony_ci	}								\
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci#ifndef CONFIG_EVA
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, )
3138c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_, )
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci#else
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci#define __BUILD_PROT_BLAST_CACHE_RANGE(pfx, desc, hitop)		\
3188c2ecf20Sopenharmony_cistatic inline void protected_blast_##pfx##cache##_range(unsigned long start,\
3198c2ecf20Sopenharmony_ci							unsigned long end) \
3208c2ecf20Sopenharmony_ci{									\
3218c2ecf20Sopenharmony_ci	unsigned long lsize = cpu_##desc##_line_size();			\
3228c2ecf20Sopenharmony_ci	unsigned long addr = start & ~(lsize - 1);			\
3238c2ecf20Sopenharmony_ci	unsigned long aend = (end - 1) & ~(lsize - 1);			\
3248c2ecf20Sopenharmony_ci									\
3258c2ecf20Sopenharmony_ci	if (!uaccess_kernel()) {					\
3268c2ecf20Sopenharmony_ci		while (1) {						\
3278c2ecf20Sopenharmony_ci			protected_cachee_op(hitop, addr);		\
3288c2ecf20Sopenharmony_ci			if (addr == aend)				\
3298c2ecf20Sopenharmony_ci				break;					\
3308c2ecf20Sopenharmony_ci			addr += lsize;					\
3318c2ecf20Sopenharmony_ci		}							\
3328c2ecf20Sopenharmony_ci	} else {							\
3338c2ecf20Sopenharmony_ci		while (1) {						\
3348c2ecf20Sopenharmony_ci			protected_cache_op(hitop, addr);		\
3358c2ecf20Sopenharmony_ci			if (addr == aend)				\
3368c2ecf20Sopenharmony_ci				break;					\
3378c2ecf20Sopenharmony_ci			addr += lsize;					\
3388c2ecf20Sopenharmony_ci		}                                                       \
3398c2ecf20Sopenharmony_ci									\
3408c2ecf20Sopenharmony_ci	}								\
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci__BUILD_PROT_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D)
3448c2ecf20Sopenharmony_ci__BUILD_PROT_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I)
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci#endif
3478c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_, )
3488c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I_Loongson2, \
3498c2ecf20Sopenharmony_ci	protected_, loongson2_)
3508c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, , )
3518c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, , )
3528c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, , )
3538c2ecf20Sopenharmony_ci/* blast_inv_dcache_range */
3548c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, , )
3558c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, , )
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci/* Currently, this is very specific to Loongson-3 */
3588c2ecf20Sopenharmony_ci#define __BUILD_BLAST_CACHE_NODE(pfx, desc, indexop, hitop, lsize)	\
3598c2ecf20Sopenharmony_cistatic inline void blast_##pfx##cache##lsize##_node(long node)		\
3608c2ecf20Sopenharmony_ci{									\
3618c2ecf20Sopenharmony_ci	unsigned long start = CAC_BASE | nid_to_addrbase(node);		\
3628c2ecf20Sopenharmony_ci	unsigned long end = start + current_cpu_data.desc.waysize;	\
3638c2ecf20Sopenharmony_ci	unsigned long ws_inc = 1UL << current_cpu_data.desc.waybit;	\
3648c2ecf20Sopenharmony_ci	unsigned long ws_end = current_cpu_data.desc.ways <<		\
3658c2ecf20Sopenharmony_ci			       current_cpu_data.desc.waybit;		\
3668c2ecf20Sopenharmony_ci	unsigned long ws, addr;						\
3678c2ecf20Sopenharmony_ci									\
3688c2ecf20Sopenharmony_ci	for (ws = 0; ws < ws_end; ws += ws_inc)				\
3698c2ecf20Sopenharmony_ci		for (addr = start; addr < end; addr += lsize * 32)	\
3708c2ecf20Sopenharmony_ci			cache_unroll(32, kernel_cache, indexop,		\
3718c2ecf20Sopenharmony_ci				     addr | ws, lsize);			\
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
3758c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
3768c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
3778c2ecf20Sopenharmony_ci__BUILD_BLAST_CACHE_NODE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci#endif /* _ASM_R4KCACHE_H */
380