xref: /openbmc/linux/arch/mips/mm/page.c (revision b56d1caf)
1fb2a27e7SThiemo Seufer /*
2fb2a27e7SThiemo Seufer  * This file is subject to the terms and conditions of the GNU General Public
3fb2a27e7SThiemo Seufer  * License.  See the file "COPYING" in the main directory of this archive
4fb2a27e7SThiemo Seufer  * for more details.
5fb2a27e7SThiemo Seufer  *
6fb2a27e7SThiemo Seufer  * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
7fb2a27e7SThiemo Seufer  * Copyright (C) 2007  Maciej W. Rozycki
8fb2a27e7SThiemo Seufer  * Copyright (C) 2008  Thiemo Seufer
9c0226306SSteven J. Hill  * Copyright (C) 2012  MIPS Technologies, Inc.
10fb2a27e7SThiemo Seufer  */
11fb2a27e7SThiemo Seufer #include <linux/kernel.h>
12fb2a27e7SThiemo Seufer #include <linux/sched.h>
13631330f5SRalf Baechle #include <linux/smp.h>
14fb2a27e7SThiemo Seufer #include <linux/mm.h>
15fb2a27e7SThiemo Seufer #include <linux/proc_fs.h>
16fb2a27e7SThiemo Seufer 
17fb2a27e7SThiemo Seufer #include <asm/bugs.h>
18fb2a27e7SThiemo Seufer #include <asm/cacheops.h>
1969f24d17SRalf Baechle #include <asm/cpu-type.h>
20fb2a27e7SThiemo Seufer #include <asm/inst.h>
21fb2a27e7SThiemo Seufer #include <asm/io.h>
22fb2a27e7SThiemo Seufer #include <asm/page.h>
23fb2a27e7SThiemo Seufer #include <asm/prefetch.h>
24fb2a27e7SThiemo Seufer #include <asm/bootinfo.h>
25fb2a27e7SThiemo Seufer #include <asm/mipsregs.h>
26fb2a27e7SThiemo Seufer #include <asm/mmu_context.h>
27fb2a27e7SThiemo Seufer #include <asm/cpu.h>
28fb2a27e7SThiemo Seufer 
29fb2a27e7SThiemo Seufer #ifdef CONFIG_SIBYTE_DMA_PAGEOPS
30fb2a27e7SThiemo Seufer #include <asm/sibyte/sb1250.h>
31fb2a27e7SThiemo Seufer #include <asm/sibyte/sb1250_regs.h>
32fb2a27e7SThiemo Seufer #include <asm/sibyte/sb1250_dma.h>
33fb2a27e7SThiemo Seufer #endif
34fb2a27e7SThiemo Seufer 
353482d713SFlorian Fainelli #include <asm/uasm.h>
36fb2a27e7SThiemo Seufer 
37fb2a27e7SThiemo Seufer /* Registers used in the assembled routines. */
38fb2a27e7SThiemo Seufer #define ZERO 0
39fb2a27e7SThiemo Seufer #define AT 2
40fb2a27e7SThiemo Seufer #define A0 4
41fb2a27e7SThiemo Seufer #define A1 5
42fb2a27e7SThiemo Seufer #define A2 6
43fb2a27e7SThiemo Seufer #define T0 8
44fb2a27e7SThiemo Seufer #define T1 9
45fb2a27e7SThiemo Seufer #define T2 10
46fb2a27e7SThiemo Seufer #define T3 11
47fb2a27e7SThiemo Seufer #define T9 25
48fb2a27e7SThiemo Seufer #define RA 31
49fb2a27e7SThiemo Seufer 
50fb2a27e7SThiemo Seufer /* Handle labels (which must be positive integers). */
51fb2a27e7SThiemo Seufer enum label_id {
52fb2a27e7SThiemo Seufer 	label_clear_nopref = 1,
53fb2a27e7SThiemo Seufer 	label_clear_pref,
54fb2a27e7SThiemo Seufer 	label_copy_nopref,
55fb2a27e7SThiemo Seufer 	label_copy_pref_both,
56fb2a27e7SThiemo Seufer 	label_copy_pref_store,
57fb2a27e7SThiemo Seufer };
58fb2a27e7SThiemo Seufer 
59fb2a27e7SThiemo Seufer UASM_L_LA(_clear_nopref)
60fb2a27e7SThiemo Seufer UASM_L_LA(_clear_pref)
61fb2a27e7SThiemo Seufer UASM_L_LA(_copy_nopref)
62fb2a27e7SThiemo Seufer UASM_L_LA(_copy_pref_both)
63fb2a27e7SThiemo Seufer UASM_L_LA(_copy_pref_store)
64fb2a27e7SThiemo Seufer 
65fb2a27e7SThiemo Seufer /* We need one branch and therefore one relocation per target label. */
66078a55fcSPaul Gortmaker static struct uasm_label labels[5];
67078a55fcSPaul Gortmaker static struct uasm_reloc relocs[5];
68fb2a27e7SThiemo Seufer 
69fb2a27e7SThiemo Seufer #define cpu_is_r4600_v1_x()	((read_c0_prid() & 0xfffffff0) == 0x00002010)
70fb2a27e7SThiemo Seufer #define cpu_is_r4600_v2_x()	((read_c0_prid() & 0xfffffff0) == 0x00002020)
71fb2a27e7SThiemo Seufer 
72d2e6d30aSMarkos Chandras /*
73d2e6d30aSMarkos Chandras  * R6 has a limited offset of the pref instruction.
74d2e6d30aSMarkos Chandras  * Skip it if the offset is more than 9 bits.
75d2e6d30aSMarkos Chandras  */
76d2e6d30aSMarkos Chandras #define _uasm_i_pref(a, b, c, d)		\
77d2e6d30aSMarkos Chandras do {						\
78d2e6d30aSMarkos Chandras 	if (cpu_has_mips_r6) {			\
79d2e6d30aSMarkos Chandras 		if (c <= 0xff && c >= -0x100)	\
80d2e6d30aSMarkos Chandras 			uasm_i_pref(a, b, c, d);\
81d2e6d30aSMarkos Chandras 	} else {				\
82d2e6d30aSMarkos Chandras 		uasm_i_pref(a, b, c, d);	\
83d2e6d30aSMarkos Chandras 	}					\
84d2e6d30aSMarkos Chandras } while(0)
85d2e6d30aSMarkos Chandras 
86078a55fcSPaul Gortmaker static int pref_bias_clear_store;
87078a55fcSPaul Gortmaker static int pref_bias_copy_load;
88078a55fcSPaul Gortmaker static int pref_bias_copy_store;
89fb2a27e7SThiemo Seufer 
90078a55fcSPaul Gortmaker static u32 pref_src_mode;
91078a55fcSPaul Gortmaker static u32 pref_dst_mode;
92fb2a27e7SThiemo Seufer 
93078a55fcSPaul Gortmaker static int clear_word_size;
94078a55fcSPaul Gortmaker static int copy_word_size;
95fb2a27e7SThiemo Seufer 
96078a55fcSPaul Gortmaker static int half_clear_loop_size;
97078a55fcSPaul Gortmaker static int half_copy_loop_size;
98fb2a27e7SThiemo Seufer 
99078a55fcSPaul Gortmaker static int cache_line_size;
100fb2a27e7SThiemo Seufer #define cache_line_mask() (cache_line_size - 1)
101fb2a27e7SThiemo Seufer 
102078a55fcSPaul Gortmaker static inline void
pg_addiu(u32 ** buf,unsigned int reg1,unsigned int reg2,unsigned int off)103fb2a27e7SThiemo Seufer pg_addiu(u32 **buf, unsigned int reg1, unsigned int reg2, unsigned int off)
104fb2a27e7SThiemo Seufer {
105*b56d1cafSThomas Bogendoerfer 	if (cpu_has_64bit_gp_regs &&
106*b56d1cafSThomas Bogendoerfer 	    IS_ENABLED(CONFIG_CPU_DADDI_WORKAROUNDS) &&
107*b56d1cafSThomas Bogendoerfer 	    r4k_daddiu_bug()) {
108fb2a27e7SThiemo Seufer 		if (off > 0x7fff) {
109fb2a27e7SThiemo Seufer 			uasm_i_lui(buf, T9, uasm_rel_hi(off));
110fb2a27e7SThiemo Seufer 			uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off));
111fb2a27e7SThiemo Seufer 		} else
112fb2a27e7SThiemo Seufer 			uasm_i_addiu(buf, T9, ZERO, off);
113fb2a27e7SThiemo Seufer 		uasm_i_daddu(buf, reg1, reg2, T9);
114fb2a27e7SThiemo Seufer 	} else {
115fb2a27e7SThiemo Seufer 		if (off > 0x7fff) {
116fb2a27e7SThiemo Seufer 			uasm_i_lui(buf, T9, uasm_rel_hi(off));
117fb2a27e7SThiemo Seufer 			uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off));
118fb2a27e7SThiemo Seufer 			UASM_i_ADDU(buf, reg1, reg2, T9);
119fb2a27e7SThiemo Seufer 		} else
120fb2a27e7SThiemo Seufer 			UASM_i_ADDIU(buf, reg1, reg2, off);
121fb2a27e7SThiemo Seufer 	}
122fb2a27e7SThiemo Seufer }
123fb2a27e7SThiemo Seufer 
set_prefetch_parameters(void)124078a55fcSPaul Gortmaker static void set_prefetch_parameters(void)
125fb2a27e7SThiemo Seufer {
126fb2a27e7SThiemo Seufer 	if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg)
127fb2a27e7SThiemo Seufer 		clear_word_size = 8;
128fb2a27e7SThiemo Seufer 	else
129fb2a27e7SThiemo Seufer 		clear_word_size = 4;
130fb2a27e7SThiemo Seufer 
131fb2a27e7SThiemo Seufer 	if (cpu_has_64bit_gp_regs)
132fb2a27e7SThiemo Seufer 		copy_word_size = 8;
133fb2a27e7SThiemo Seufer 	else
134fb2a27e7SThiemo Seufer 		copy_word_size = 4;
135fb2a27e7SThiemo Seufer 
136fb2a27e7SThiemo Seufer 	/*
137fb2a27e7SThiemo Seufer 	 * The pref's used here are using "streaming" hints, which cause the
138fb2a27e7SThiemo Seufer 	 * copied data to be kicked out of the cache sooner.  A page copy often
139fb2a27e7SThiemo Seufer 	 * ends up copying a lot more data than is commonly used, so this seems
140fb2a27e7SThiemo Seufer 	 * to make sense in terms of reducing cache pollution, but I've no real
141fb2a27e7SThiemo Seufer 	 * performance data to back this up.
142fb2a27e7SThiemo Seufer 	 */
143fb2a27e7SThiemo Seufer 	if (cpu_has_prefetch) {
144fb2a27e7SThiemo Seufer 		/*
145fb2a27e7SThiemo Seufer 		 * XXX: Most prefetch bias values in here are based on
146fb2a27e7SThiemo Seufer 		 * guesswork.
147fb2a27e7SThiemo Seufer 		 */
148fb2a27e7SThiemo Seufer 		cache_line_size = cpu_dcache_line_size();
149fb2a27e7SThiemo Seufer 		switch (current_cpu_type()) {
150a644b277SShinya Kuribayashi 		case CPU_R5500:
151fb2a27e7SThiemo Seufer 		case CPU_TX49XX:
152a644b277SShinya Kuribayashi 			/* These processors only support the Pref_Load. */
153fb2a27e7SThiemo Seufer 			pref_bias_copy_load = 256;
154fb2a27e7SThiemo Seufer 			break;
155fb2a27e7SThiemo Seufer 
156fb2a27e7SThiemo Seufer 		case CPU_R10000:
157fb2a27e7SThiemo Seufer 		case CPU_R12000:
158fb2a27e7SThiemo Seufer 		case CPU_R14000:
15930577391SJoshua Kinard 		case CPU_R16000:
160fb2a27e7SThiemo Seufer 			/*
161fb2a27e7SThiemo Seufer 			 * Those values have been experimentally tuned for an
162fb2a27e7SThiemo Seufer 			 * Origin 200.
163fb2a27e7SThiemo Seufer 			 */
164fb2a27e7SThiemo Seufer 			pref_bias_clear_store = 512;
165fb2a27e7SThiemo Seufer 			pref_bias_copy_load = 256;
166fb2a27e7SThiemo Seufer 			pref_bias_copy_store = 256;
167fb2a27e7SThiemo Seufer 			pref_src_mode = Pref_LoadStreamed;
168fb2a27e7SThiemo Seufer 			pref_dst_mode = Pref_StoreStreamed;
169fb2a27e7SThiemo Seufer 			break;
170fb2a27e7SThiemo Seufer 
171fb2a27e7SThiemo Seufer 		case CPU_SB1:
172fb2a27e7SThiemo Seufer 		case CPU_SB1A:
173fb2a27e7SThiemo Seufer 			pref_bias_clear_store = 128;
174fb2a27e7SThiemo Seufer 			pref_bias_copy_load = 128;
175fb2a27e7SThiemo Seufer 			pref_bias_copy_store = 128;
176fb2a27e7SThiemo Seufer 			/*
177fb2a27e7SThiemo Seufer 			 * SB1 pass1 Pref_LoadStreamed/Pref_StoreStreamed
178fb2a27e7SThiemo Seufer 			 * hints are broken.
179fb2a27e7SThiemo Seufer 			 */
180fb2a27e7SThiemo Seufer 			if (current_cpu_type() == CPU_SB1 &&
181fb2a27e7SThiemo Seufer 			    (current_cpu_data.processor_id & 0xff) < 0x02) {
182fb2a27e7SThiemo Seufer 				pref_src_mode = Pref_Load;
183fb2a27e7SThiemo Seufer 				pref_dst_mode = Pref_Store;
184fb2a27e7SThiemo Seufer 			} else {
185fb2a27e7SThiemo Seufer 				pref_src_mode = Pref_LoadStreamed;
186fb2a27e7SThiemo Seufer 				pref_dst_mode = Pref_StoreStreamed;
187fb2a27e7SThiemo Seufer 			}
188fb2a27e7SThiemo Seufer 			break;
189fb2a27e7SThiemo Seufer 
190268a2d60SJiaxun Yang 		case CPU_LOONGSON64:
1911e820da3SHuacai Chen 			/* Loongson-3 only support the Pref_Load/Pref_Store. */
1921e820da3SHuacai Chen 			pref_bias_clear_store = 128;
1931e820da3SHuacai Chen 			pref_bias_copy_load = 128;
1941e820da3SHuacai Chen 			pref_bias_copy_store = 128;
1951e820da3SHuacai Chen 			pref_src_mode = Pref_Load;
1961e820da3SHuacai Chen 			pref_dst_mode = Pref_Store;
1971e820da3SHuacai Chen 			break;
1981e820da3SHuacai Chen 
199fb2a27e7SThiemo Seufer 		default:
200fb2a27e7SThiemo Seufer 			pref_bias_clear_store = 128;
201fb2a27e7SThiemo Seufer 			pref_bias_copy_load = 256;
202fb2a27e7SThiemo Seufer 			pref_bias_copy_store = 128;
203fb2a27e7SThiemo Seufer 			pref_src_mode = Pref_LoadStreamed;
204d2e6d30aSMarkos Chandras 			if (cpu_has_mips_r6)
205d2e6d30aSMarkos Chandras 				/*
206d2e6d30aSMarkos Chandras 				 * Bit 30 (Pref_PrepareForStore) has been
207d2e6d30aSMarkos Chandras 				 * removed from MIPS R6. Use bit 5
208d2e6d30aSMarkos Chandras 				 * (Pref_StoreStreamed).
209d2e6d30aSMarkos Chandras 				 */
210d2e6d30aSMarkos Chandras 				pref_dst_mode = Pref_StoreStreamed;
211d2e6d30aSMarkos Chandras 			else
212fb2a27e7SThiemo Seufer 				pref_dst_mode = Pref_PrepareForStore;
213fb2a27e7SThiemo Seufer 			break;
214fb2a27e7SThiemo Seufer 		}
215fb2a27e7SThiemo Seufer 	} else {
216fb2a27e7SThiemo Seufer 		if (cpu_has_cache_cdex_s)
217fb2a27e7SThiemo Seufer 			cache_line_size = cpu_scache_line_size();
218fb2a27e7SThiemo Seufer 		else if (cpu_has_cache_cdex_p)
219fb2a27e7SThiemo Seufer 			cache_line_size = cpu_dcache_line_size();
220fb2a27e7SThiemo Seufer 	}
221fb2a27e7SThiemo Seufer 	/*
222fb2a27e7SThiemo Seufer 	 * Too much unrolling will overflow the available space in
22314defd90SThomas Bogendoerfer 	 * clear_space_array / copy_page_array.
224fb2a27e7SThiemo Seufer 	 */
22514defd90SThomas Bogendoerfer 	half_clear_loop_size = min(16 * clear_word_size,
226fb2a27e7SThiemo Seufer 				   max(cache_line_size >> 1,
227fb2a27e7SThiemo Seufer 				       4 * clear_word_size));
22814defd90SThomas Bogendoerfer 	half_copy_loop_size = min(16 * copy_word_size,
229fb2a27e7SThiemo Seufer 				  max(cache_line_size >> 1,
230fb2a27e7SThiemo Seufer 				      4 * copy_word_size));
231fb2a27e7SThiemo Seufer }
232fb2a27e7SThiemo Seufer 
build_clear_store(u32 ** buf,int off)233078a55fcSPaul Gortmaker static void build_clear_store(u32 **buf, int off)
234fb2a27e7SThiemo Seufer {
235fb2a27e7SThiemo Seufer 	if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) {
236fb2a27e7SThiemo Seufer 		uasm_i_sd(buf, ZERO, off, A0);
237fb2a27e7SThiemo Seufer 	} else {
238fb2a27e7SThiemo Seufer 		uasm_i_sw(buf, ZERO, off, A0);
239fb2a27e7SThiemo Seufer 	}
240fb2a27e7SThiemo Seufer }
241fb2a27e7SThiemo Seufer 
build_clear_pref(u32 ** buf,int off)242078a55fcSPaul Gortmaker static inline void build_clear_pref(u32 **buf, int off)
243fb2a27e7SThiemo Seufer {
244fb2a27e7SThiemo Seufer 	if (off & cache_line_mask())
245fb2a27e7SThiemo Seufer 		return;
246fb2a27e7SThiemo Seufer 
247fb2a27e7SThiemo Seufer 	if (pref_bias_clear_store) {
248d2e6d30aSMarkos Chandras 		_uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off,
249fb2a27e7SThiemo Seufer 			    A0);
25014defd90SThomas Bogendoerfer 	} else if (cache_line_size == (half_clear_loop_size << 1)) {
25114defd90SThomas Bogendoerfer 		if (cpu_has_cache_cdex_s) {
252fb2a27e7SThiemo Seufer 			uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0);
253fb2a27e7SThiemo Seufer 		} else if (cpu_has_cache_cdex_p) {
2545e5b6527SThomas Bogendoerfer 			if (IS_ENABLED(CONFIG_WAR_R4600_V1_HIT_CACHEOP) &&
2555e5b6527SThomas Bogendoerfer 			    cpu_is_r4600_v1_x()) {
256fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
257fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
258fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
259fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
260fb2a27e7SThiemo Seufer 			}
261fb2a27e7SThiemo Seufer 
26244def342SThomas Bogendoerfer 			if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) &&
26344def342SThomas Bogendoerfer 			    cpu_is_r4600_v2_x())
264fb2a27e7SThiemo Seufer 				uasm_i_lw(buf, ZERO, ZERO, AT);
265fb2a27e7SThiemo Seufer 
266fb2a27e7SThiemo Seufer 			uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0);
267fb2a27e7SThiemo Seufer 		}
268fb2a27e7SThiemo Seufer 	}
26914defd90SThomas Bogendoerfer }
270fb2a27e7SThiemo Seufer 
271c0226306SSteven J. Hill extern u32 __clear_page_start;
272c0226306SSteven J. Hill extern u32 __clear_page_end;
273c0226306SSteven J. Hill extern u32 __copy_page_start;
274c0226306SSteven J. Hill extern u32 __copy_page_end;
275c0226306SSteven J. Hill 
build_clear_page(void)276078a55fcSPaul Gortmaker void build_clear_page(void)
277fb2a27e7SThiemo Seufer {
278fb2a27e7SThiemo Seufer 	int off;
279c0226306SSteven J. Hill 	u32 *buf = &__clear_page_start;
280fb2a27e7SThiemo Seufer 	struct uasm_label *l = labels;
281fb2a27e7SThiemo Seufer 	struct uasm_reloc *r = relocs;
282fb2a27e7SThiemo Seufer 	int i;
2838759934eSHuacai Chen 	static atomic_t run_once = ATOMIC_INIT(0);
2848759934eSHuacai Chen 
2858759934eSHuacai Chen 	if (atomic_xchg(&run_once, 1)) {
2868759934eSHuacai Chen 		return;
2878759934eSHuacai Chen 	}
288fb2a27e7SThiemo Seufer 
289fb2a27e7SThiemo Seufer 	memset(labels, 0, sizeof(labels));
290fb2a27e7SThiemo Seufer 	memset(relocs, 0, sizeof(relocs));
291fb2a27e7SThiemo Seufer 
292fb2a27e7SThiemo Seufer 	set_prefetch_parameters();
293fb2a27e7SThiemo Seufer 
294fb2a27e7SThiemo Seufer 	/*
295fb2a27e7SThiemo Seufer 	 * This algorithm makes the following assumptions:
296fb2a27e7SThiemo Seufer 	 *   - The prefetch bias is a multiple of 2 words.
297fb2a27e7SThiemo Seufer 	 *   - The prefetch bias is less than one page.
298fb2a27e7SThiemo Seufer 	 */
299fb2a27e7SThiemo Seufer 	BUG_ON(pref_bias_clear_store % (2 * clear_word_size));
300fb2a27e7SThiemo Seufer 	BUG_ON(PAGE_SIZE < pref_bias_clear_store);
301fb2a27e7SThiemo Seufer 
302fb2a27e7SThiemo Seufer 	off = PAGE_SIZE - pref_bias_clear_store;
303fb2a27e7SThiemo Seufer 	if (off > 0xffff || !pref_bias_clear_store)
304fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A2, A0, off);
305fb2a27e7SThiemo Seufer 	else
306fb2a27e7SThiemo Seufer 		uasm_i_ori(&buf, A2, A0, off);
307fb2a27e7SThiemo Seufer 
30844def342SThomas Bogendoerfer 	if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x())
309f3f0d951SThomas Bogendoerfer 		uasm_i_lui(&buf, AT, uasm_rel_hi(0xa0000000));
310fb2a27e7SThiemo Seufer 
311cd9da13dSYoichi Yuasa 	off = cache_line_size ? min(8, pref_bias_clear_store / cache_line_size)
312cd9da13dSYoichi Yuasa 				* cache_line_size : 0;
313fb2a27e7SThiemo Seufer 	while (off) {
314fb2a27e7SThiemo Seufer 		build_clear_pref(&buf, -off);
315fb2a27e7SThiemo Seufer 		off -= cache_line_size;
316fb2a27e7SThiemo Seufer 	}
317fb2a27e7SThiemo Seufer 	uasm_l_clear_pref(&l, buf);
318fb2a27e7SThiemo Seufer 	do {
319fb2a27e7SThiemo Seufer 		build_clear_pref(&buf, off);
320fb2a27e7SThiemo Seufer 		build_clear_store(&buf, off);
321fb2a27e7SThiemo Seufer 		off += clear_word_size;
322fb2a27e7SThiemo Seufer 	} while (off < half_clear_loop_size);
323fb2a27e7SThiemo Seufer 	pg_addiu(&buf, A0, A0, 2 * off);
324fb2a27e7SThiemo Seufer 	off = -off;
325fb2a27e7SThiemo Seufer 	do {
326fb2a27e7SThiemo Seufer 		build_clear_pref(&buf, off);
327fb2a27e7SThiemo Seufer 		if (off == -clear_word_size)
328fb2a27e7SThiemo Seufer 			uasm_il_bne(&buf, &r, A0, A2, label_clear_pref);
329fb2a27e7SThiemo Seufer 		build_clear_store(&buf, off);
330fb2a27e7SThiemo Seufer 		off += clear_word_size;
331fb2a27e7SThiemo Seufer 	} while (off < 0);
332fb2a27e7SThiemo Seufer 
333fb2a27e7SThiemo Seufer 	if (pref_bias_clear_store) {
334fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A2, A0, pref_bias_clear_store);
335fb2a27e7SThiemo Seufer 		uasm_l_clear_nopref(&l, buf);
336fb2a27e7SThiemo Seufer 		off = 0;
337fb2a27e7SThiemo Seufer 		do {
338fb2a27e7SThiemo Seufer 			build_clear_store(&buf, off);
339fb2a27e7SThiemo Seufer 			off += clear_word_size;
340fb2a27e7SThiemo Seufer 		} while (off < half_clear_loop_size);
341fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A0, A0, 2 * off);
342fb2a27e7SThiemo Seufer 		off = -off;
343fb2a27e7SThiemo Seufer 		do {
344fb2a27e7SThiemo Seufer 			if (off == -clear_word_size)
345fb2a27e7SThiemo Seufer 				uasm_il_bne(&buf, &r, A0, A2,
346fb2a27e7SThiemo Seufer 					    label_clear_nopref);
347fb2a27e7SThiemo Seufer 			build_clear_store(&buf, off);
348fb2a27e7SThiemo Seufer 			off += clear_word_size;
349fb2a27e7SThiemo Seufer 		} while (off < 0);
350fb2a27e7SThiemo Seufer 	}
351fb2a27e7SThiemo Seufer 
352fb2a27e7SThiemo Seufer 	uasm_i_jr(&buf, RA);
353fb2a27e7SThiemo Seufer 	uasm_i_nop(&buf);
354fb2a27e7SThiemo Seufer 
355c0226306SSteven J. Hill 	BUG_ON(buf > &__clear_page_end);
356fb2a27e7SThiemo Seufer 
357fb2a27e7SThiemo Seufer 	uasm_resolve_relocs(relocs, labels);
358fb2a27e7SThiemo Seufer 
359fb2a27e7SThiemo Seufer 	pr_debug("Synthesized clear page handler (%u instructions).\n",
360c0226306SSteven J. Hill 		 (u32)(buf - &__clear_page_start));
361fb2a27e7SThiemo Seufer 
362fb2a27e7SThiemo Seufer 	pr_debug("\t.set push\n");
363fb2a27e7SThiemo Seufer 	pr_debug("\t.set noreorder\n");
364c0226306SSteven J. Hill 	for (i = 0; i < (buf - &__clear_page_start); i++)
365c0226306SSteven J. Hill 		pr_debug("\t.word 0x%08x\n", (&__clear_page_start)[i]);
366fb2a27e7SThiemo Seufer 	pr_debug("\t.set pop\n");
367fb2a27e7SThiemo Seufer }
368fb2a27e7SThiemo Seufer 
build_copy_load(u32 ** buf,int reg,int off)369078a55fcSPaul Gortmaker static void build_copy_load(u32 **buf, int reg, int off)
370fb2a27e7SThiemo Seufer {
371fb2a27e7SThiemo Seufer 	if (cpu_has_64bit_gp_regs) {
372fb2a27e7SThiemo Seufer 		uasm_i_ld(buf, reg, off, A1);
373fb2a27e7SThiemo Seufer 	} else {
374fb2a27e7SThiemo Seufer 		uasm_i_lw(buf, reg, off, A1);
375fb2a27e7SThiemo Seufer 	}
376fb2a27e7SThiemo Seufer }
377fb2a27e7SThiemo Seufer 
build_copy_store(u32 ** buf,int reg,int off)378078a55fcSPaul Gortmaker static void build_copy_store(u32 **buf, int reg, int off)
379fb2a27e7SThiemo Seufer {
380fb2a27e7SThiemo Seufer 	if (cpu_has_64bit_gp_regs) {
381fb2a27e7SThiemo Seufer 		uasm_i_sd(buf, reg, off, A0);
382fb2a27e7SThiemo Seufer 	} else {
383fb2a27e7SThiemo Seufer 		uasm_i_sw(buf, reg, off, A0);
384fb2a27e7SThiemo Seufer 	}
385fb2a27e7SThiemo Seufer }
386fb2a27e7SThiemo Seufer 
build_copy_load_pref(u32 ** buf,int off)387fb2a27e7SThiemo Seufer static inline void build_copy_load_pref(u32 **buf, int off)
388fb2a27e7SThiemo Seufer {
389fb2a27e7SThiemo Seufer 	if (off & cache_line_mask())
390fb2a27e7SThiemo Seufer 		return;
391fb2a27e7SThiemo Seufer 
392fb2a27e7SThiemo Seufer 	if (pref_bias_copy_load)
393d2e6d30aSMarkos Chandras 		_uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1);
394fb2a27e7SThiemo Seufer }
395fb2a27e7SThiemo Seufer 
build_copy_store_pref(u32 ** buf,int off)396fb2a27e7SThiemo Seufer static inline void build_copy_store_pref(u32 **buf, int off)
397fb2a27e7SThiemo Seufer {
398fb2a27e7SThiemo Seufer 	if (off & cache_line_mask())
399fb2a27e7SThiemo Seufer 		return;
400fb2a27e7SThiemo Seufer 
401fb2a27e7SThiemo Seufer 	if (pref_bias_copy_store) {
402d2e6d30aSMarkos Chandras 		_uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off,
403fb2a27e7SThiemo Seufer 			    A0);
40414defd90SThomas Bogendoerfer 	} else if (cache_line_size == (half_copy_loop_size << 1)) {
40514defd90SThomas Bogendoerfer 		if (cpu_has_cache_cdex_s) {
406fb2a27e7SThiemo Seufer 			uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0);
407fb2a27e7SThiemo Seufer 		} else if (cpu_has_cache_cdex_p) {
4085e5b6527SThomas Bogendoerfer 			if (IS_ENABLED(CONFIG_WAR_R4600_V1_HIT_CACHEOP) &&
4095e5b6527SThomas Bogendoerfer 			    cpu_is_r4600_v1_x()) {
410fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
411fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
412fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
413fb2a27e7SThiemo Seufer 				uasm_i_nop(buf);
414fb2a27e7SThiemo Seufer 			}
415fb2a27e7SThiemo Seufer 
41644def342SThomas Bogendoerfer 			if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) &&
41744def342SThomas Bogendoerfer 			    cpu_is_r4600_v2_x())
418fb2a27e7SThiemo Seufer 				uasm_i_lw(buf, ZERO, ZERO, AT);
419fb2a27e7SThiemo Seufer 
420fb2a27e7SThiemo Seufer 			uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0);
421fb2a27e7SThiemo Seufer 		}
422fb2a27e7SThiemo Seufer 	}
42314defd90SThomas Bogendoerfer }
424fb2a27e7SThiemo Seufer 
build_copy_page(void)425078a55fcSPaul Gortmaker void build_copy_page(void)
426fb2a27e7SThiemo Seufer {
427fb2a27e7SThiemo Seufer 	int off;
428c0226306SSteven J. Hill 	u32 *buf = &__copy_page_start;
429fb2a27e7SThiemo Seufer 	struct uasm_label *l = labels;
430fb2a27e7SThiemo Seufer 	struct uasm_reloc *r = relocs;
431fb2a27e7SThiemo Seufer 	int i;
4328759934eSHuacai Chen 	static atomic_t run_once = ATOMIC_INIT(0);
4338759934eSHuacai Chen 
4348759934eSHuacai Chen 	if (atomic_xchg(&run_once, 1)) {
4358759934eSHuacai Chen 		return;
4368759934eSHuacai Chen 	}
437fb2a27e7SThiemo Seufer 
438fb2a27e7SThiemo Seufer 	memset(labels, 0, sizeof(labels));
439fb2a27e7SThiemo Seufer 	memset(relocs, 0, sizeof(relocs));
440fb2a27e7SThiemo Seufer 
441fb2a27e7SThiemo Seufer 	set_prefetch_parameters();
442fb2a27e7SThiemo Seufer 
443fb2a27e7SThiemo Seufer 	/*
444fb2a27e7SThiemo Seufer 	 * This algorithm makes the following assumptions:
445fb2a27e7SThiemo Seufer 	 *   - All prefetch biases are multiples of 8 words.
446fb2a27e7SThiemo Seufer 	 *   - The prefetch biases are less than one page.
447fb2a27e7SThiemo Seufer 	 *   - The store prefetch bias isn't greater than the load
448fb2a27e7SThiemo Seufer 	 *     prefetch bias.
449fb2a27e7SThiemo Seufer 	 */
450fb2a27e7SThiemo Seufer 	BUG_ON(pref_bias_copy_load % (8 * copy_word_size));
451fb2a27e7SThiemo Seufer 	BUG_ON(pref_bias_copy_store % (8 * copy_word_size));
452fb2a27e7SThiemo Seufer 	BUG_ON(PAGE_SIZE < pref_bias_copy_load);
453fb2a27e7SThiemo Seufer 	BUG_ON(pref_bias_copy_store > pref_bias_copy_load);
454fb2a27e7SThiemo Seufer 
455fb2a27e7SThiemo Seufer 	off = PAGE_SIZE - pref_bias_copy_load;
456fb2a27e7SThiemo Seufer 	if (off > 0xffff || !pref_bias_copy_load)
457fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A2, A0, off);
458fb2a27e7SThiemo Seufer 	else
459fb2a27e7SThiemo Seufer 		uasm_i_ori(&buf, A2, A0, off);
460fb2a27e7SThiemo Seufer 
46144def342SThomas Bogendoerfer 	if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x())
462f3f0d951SThomas Bogendoerfer 		uasm_i_lui(&buf, AT, uasm_rel_hi(0xa0000000));
463fb2a27e7SThiemo Seufer 
464cd9da13dSYoichi Yuasa 	off = cache_line_size ? min(8, pref_bias_copy_load / cache_line_size) *
465cd9da13dSYoichi Yuasa 				cache_line_size : 0;
466fb2a27e7SThiemo Seufer 	while (off) {
467fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, -off);
468fb2a27e7SThiemo Seufer 		off -= cache_line_size;
469fb2a27e7SThiemo Seufer 	}
4707bd0fea2SAtsushi Nemoto 	off = cache_line_size ? min(8, pref_bias_copy_store / cache_line_size) *
471cd9da13dSYoichi Yuasa 				cache_line_size : 0;
472fb2a27e7SThiemo Seufer 	while (off) {
473fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, -off);
474fb2a27e7SThiemo Seufer 		off -= cache_line_size;
475fb2a27e7SThiemo Seufer 	}
476fb2a27e7SThiemo Seufer 	uasm_l_copy_pref_both(&l, buf);
477fb2a27e7SThiemo Seufer 	do {
478fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off);
479fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T0, off);
480fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off + copy_word_size);
481fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T1, off + copy_word_size);
482fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off + 2 * copy_word_size);
483fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T2, off + 2 * copy_word_size);
484fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off + 3 * copy_word_size);
485fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T3, off + 3 * copy_word_size);
486fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off);
487fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T0, off);
488fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off + copy_word_size);
489fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T1, off + copy_word_size);
490fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off + 2 * copy_word_size);
491fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T2, off + 2 * copy_word_size);
492fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off + 3 * copy_word_size);
493fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T3, off + 3 * copy_word_size);
494fb2a27e7SThiemo Seufer 		off += 4 * copy_word_size;
495fb2a27e7SThiemo Seufer 	} while (off < half_copy_loop_size);
496fb2a27e7SThiemo Seufer 	pg_addiu(&buf, A1, A1, 2 * off);
497fb2a27e7SThiemo Seufer 	pg_addiu(&buf, A0, A0, 2 * off);
498fb2a27e7SThiemo Seufer 	off = -off;
499fb2a27e7SThiemo Seufer 	do {
500fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off);
501fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T0, off);
502fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off + copy_word_size);
503fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T1, off + copy_word_size);
504fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off + 2 * copy_word_size);
505fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T2, off + 2 * copy_word_size);
506fb2a27e7SThiemo Seufer 		build_copy_load_pref(&buf, off + 3 * copy_word_size);
507fb2a27e7SThiemo Seufer 		build_copy_load(&buf, T3, off + 3 * copy_word_size);
508fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off);
509fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T0, off);
510fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off + copy_word_size);
511fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T1, off + copy_word_size);
512fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off + 2 * copy_word_size);
513fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T2, off + 2 * copy_word_size);
514fb2a27e7SThiemo Seufer 		build_copy_store_pref(&buf, off + 3 * copy_word_size);
515fb2a27e7SThiemo Seufer 		if (off == -(4 * copy_word_size))
516fb2a27e7SThiemo Seufer 			uasm_il_bne(&buf, &r, A2, A0, label_copy_pref_both);
517fb2a27e7SThiemo Seufer 		build_copy_store(&buf, T3, off + 3 * copy_word_size);
518fb2a27e7SThiemo Seufer 		off += 4 * copy_word_size;
519fb2a27e7SThiemo Seufer 	} while (off < 0);
520fb2a27e7SThiemo Seufer 
521fb2a27e7SThiemo Seufer 	if (pref_bias_copy_load - pref_bias_copy_store) {
522fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A2, A0,
523fb2a27e7SThiemo Seufer 			 pref_bias_copy_load - pref_bias_copy_store);
524fb2a27e7SThiemo Seufer 		uasm_l_copy_pref_store(&l, buf);
525fb2a27e7SThiemo Seufer 		off = 0;
526fb2a27e7SThiemo Seufer 		do {
527fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T0, off);
528fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T1, off + copy_word_size);
529fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T2, off + 2 * copy_word_size);
530fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T3, off + 3 * copy_word_size);
531fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off);
532fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T0, off);
533fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off + copy_word_size);
534fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T1, off + copy_word_size);
535fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off + 2 * copy_word_size);
536fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T2, off + 2 * copy_word_size);
537fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off + 3 * copy_word_size);
538fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T3, off + 3 * copy_word_size);
539fb2a27e7SThiemo Seufer 			off += 4 * copy_word_size;
540fb2a27e7SThiemo Seufer 		} while (off < half_copy_loop_size);
541fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A1, A1, 2 * off);
542fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A0, A0, 2 * off);
543fb2a27e7SThiemo Seufer 		off = -off;
544fb2a27e7SThiemo Seufer 		do {
545fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T0, off);
546fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T1, off + copy_word_size);
547fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T2, off + 2 * copy_word_size);
548fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T3, off + 3 * copy_word_size);
549fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off);
550fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T0, off);
551fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off + copy_word_size);
552fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T1, off + copy_word_size);
553fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off + 2 * copy_word_size);
554fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T2, off + 2 * copy_word_size);
555fb2a27e7SThiemo Seufer 			build_copy_store_pref(&buf, off + 3 * copy_word_size);
556fb2a27e7SThiemo Seufer 			if (off == -(4 * copy_word_size))
557fb2a27e7SThiemo Seufer 				uasm_il_bne(&buf, &r, A2, A0,
558fb2a27e7SThiemo Seufer 					    label_copy_pref_store);
559fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T3, off + 3 * copy_word_size);
560fb2a27e7SThiemo Seufer 			off += 4 * copy_word_size;
561fb2a27e7SThiemo Seufer 		} while (off < 0);
562fb2a27e7SThiemo Seufer 	}
563fb2a27e7SThiemo Seufer 
564fb2a27e7SThiemo Seufer 	if (pref_bias_copy_store) {
565fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A2, A0, pref_bias_copy_store);
566fb2a27e7SThiemo Seufer 		uasm_l_copy_nopref(&l, buf);
567fb2a27e7SThiemo Seufer 		off = 0;
568fb2a27e7SThiemo Seufer 		do {
569fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T0, off);
570fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T1, off + copy_word_size);
571fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T2, off + 2 * copy_word_size);
572fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T3, off + 3 * copy_word_size);
573fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T0, off);
574fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T1, off + copy_word_size);
575fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T2, off + 2 * copy_word_size);
576fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T3, off + 3 * copy_word_size);
577fb2a27e7SThiemo Seufer 			off += 4 * copy_word_size;
578fb2a27e7SThiemo Seufer 		} while (off < half_copy_loop_size);
579fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A1, A1, 2 * off);
580fb2a27e7SThiemo Seufer 		pg_addiu(&buf, A0, A0, 2 * off);
581fb2a27e7SThiemo Seufer 		off = -off;
582fb2a27e7SThiemo Seufer 		do {
583fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T0, off);
584fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T1, off + copy_word_size);
585fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T2, off + 2 * copy_word_size);
586fb2a27e7SThiemo Seufer 			build_copy_load(&buf, T3, off + 3 * copy_word_size);
587fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T0, off);
588fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T1, off + copy_word_size);
589fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T2, off + 2 * copy_word_size);
590fb2a27e7SThiemo Seufer 			if (off == -(4 * copy_word_size))
591fb2a27e7SThiemo Seufer 				uasm_il_bne(&buf, &r, A2, A0,
592fb2a27e7SThiemo Seufer 					    label_copy_nopref);
593fb2a27e7SThiemo Seufer 			build_copy_store(&buf, T3, off + 3 * copy_word_size);
594fb2a27e7SThiemo Seufer 			off += 4 * copy_word_size;
595fb2a27e7SThiemo Seufer 		} while (off < 0);
596fb2a27e7SThiemo Seufer 	}
597fb2a27e7SThiemo Seufer 
598fb2a27e7SThiemo Seufer 	uasm_i_jr(&buf, RA);
599fb2a27e7SThiemo Seufer 	uasm_i_nop(&buf);
600fb2a27e7SThiemo Seufer 
601c0226306SSteven J. Hill 	BUG_ON(buf > &__copy_page_end);
602fb2a27e7SThiemo Seufer 
603fb2a27e7SThiemo Seufer 	uasm_resolve_relocs(relocs, labels);
604fb2a27e7SThiemo Seufer 
605fb2a27e7SThiemo Seufer 	pr_debug("Synthesized copy page handler (%u instructions).\n",
606c0226306SSteven J. Hill 		 (u32)(buf - &__copy_page_start));
607fb2a27e7SThiemo Seufer 
608fb2a27e7SThiemo Seufer 	pr_debug("\t.set push\n");
609fb2a27e7SThiemo Seufer 	pr_debug("\t.set noreorder\n");
610c0226306SSteven J. Hill 	for (i = 0; i < (buf - &__copy_page_start); i++)
611c0226306SSteven J. Hill 		pr_debug("\t.word 0x%08x\n", (&__copy_page_start)[i]);
612fb2a27e7SThiemo Seufer 	pr_debug("\t.set pop\n");
613fb2a27e7SThiemo Seufer }
614fb2a27e7SThiemo Seufer 
615fb2a27e7SThiemo Seufer #ifdef CONFIG_SIBYTE_DMA_PAGEOPS
616c0226306SSteven J. Hill extern void clear_page_cpu(void *page);
617c0226306SSteven J. Hill extern void copy_page_cpu(void *to, void *from);
618fb2a27e7SThiemo Seufer 
619fb2a27e7SThiemo Seufer /*
620fb2a27e7SThiemo Seufer  * Pad descriptors to cacheline, since each is exclusively owned by a
621fb2a27e7SThiemo Seufer  * particular CPU.
622fb2a27e7SThiemo Seufer  */
623fb2a27e7SThiemo Seufer struct dmadscr {
624fb2a27e7SThiemo Seufer 	u64 dscr_a;
625fb2a27e7SThiemo Seufer 	u64 dscr_b;
626fb2a27e7SThiemo Seufer 	u64 pad_a;
627fb2a27e7SThiemo Seufer 	u64 pad_b;
628fb2a27e7SThiemo Seufer } ____cacheline_aligned_in_smp page_descr[DM_NUM_CHANNELS];
629fb2a27e7SThiemo Seufer 
clear_page(void * page)630fb2a27e7SThiemo Seufer void clear_page(void *page)
631fb2a27e7SThiemo Seufer {
632fb2a27e7SThiemo Seufer 	u64 to_phys = CPHYSADDR((unsigned long)page);
633fb2a27e7SThiemo Seufer 	unsigned int cpu = smp_processor_id();
634fb2a27e7SThiemo Seufer 
635fb2a27e7SThiemo Seufer 	/* if the page is not in KSEG0, use old way */
636fb2a27e7SThiemo Seufer 	if ((long)KSEGX((unsigned long)page) != (long)CKSEG0)
637fb2a27e7SThiemo Seufer 		return clear_page_cpu(page);
638fb2a27e7SThiemo Seufer 
639fb2a27e7SThiemo Seufer 	page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM |
640fb2a27e7SThiemo Seufer 				 M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
641fb2a27e7SThiemo Seufer 	page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
642fb2a27e7SThiemo Seufer 	__raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
643fb2a27e7SThiemo Seufer 
644fb2a27e7SThiemo Seufer 	/*
645fb2a27e7SThiemo Seufer 	 * Don't really want to do it this way, but there's no
646fb2a27e7SThiemo Seufer 	 * reliable way to delay completion detection.
647fb2a27e7SThiemo Seufer 	 */
648fb2a27e7SThiemo Seufer 	while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
649fb2a27e7SThiemo Seufer 		 & M_DM_DSCR_BASE_INTERRUPT))
650fb2a27e7SThiemo Seufer 		;
651fb2a27e7SThiemo Seufer 	__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
652fb2a27e7SThiemo Seufer }
653f44374f1SPaul Burton EXPORT_SYMBOL(clear_page);
654fb2a27e7SThiemo Seufer 
copy_page(void * to,void * from)655fb2a27e7SThiemo Seufer void copy_page(void *to, void *from)
656fb2a27e7SThiemo Seufer {
657fb2a27e7SThiemo Seufer 	u64 from_phys = CPHYSADDR((unsigned long)from);
658fb2a27e7SThiemo Seufer 	u64 to_phys = CPHYSADDR((unsigned long)to);
659fb2a27e7SThiemo Seufer 	unsigned int cpu = smp_processor_id();
660fb2a27e7SThiemo Seufer 
661fb2a27e7SThiemo Seufer 	/* if any page is not in KSEG0, use old way */
662fb2a27e7SThiemo Seufer 	if ((long)KSEGX((unsigned long)to) != (long)CKSEG0
663fb2a27e7SThiemo Seufer 	    || (long)KSEGX((unsigned long)from) != (long)CKSEG0)
664fb2a27e7SThiemo Seufer 		return copy_page_cpu(to, from);
665fb2a27e7SThiemo Seufer 
666fb2a27e7SThiemo Seufer 	page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST |
667fb2a27e7SThiemo Seufer 				 M_DM_DSCRA_INTERRUPT;
668fb2a27e7SThiemo Seufer 	page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
669fb2a27e7SThiemo Seufer 	__raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
670fb2a27e7SThiemo Seufer 
671fb2a27e7SThiemo Seufer 	/*
672fb2a27e7SThiemo Seufer 	 * Don't really want to do it this way, but there's no
673fb2a27e7SThiemo Seufer 	 * reliable way to delay completion detection.
674fb2a27e7SThiemo Seufer 	 */
675fb2a27e7SThiemo Seufer 	while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
676fb2a27e7SThiemo Seufer 		 & M_DM_DSCR_BASE_INTERRUPT))
677fb2a27e7SThiemo Seufer 		;
678fb2a27e7SThiemo Seufer 	__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
679fb2a27e7SThiemo Seufer }
680f44374f1SPaul Burton EXPORT_SYMBOL(copy_page);
681fb2a27e7SThiemo Seufer 
682fb2a27e7SThiemo Seufer #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
683