xref: /openbmc/linux/arch/sparc/lib/NGmemcpy.S (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */
2478b8fecSSam Ravnborg/* NGmemcpy.S: Niagara optimized memcpy.
3478b8fecSSam Ravnborg *
4478b8fecSSam Ravnborg * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
5478b8fecSSam Ravnborg */
6478b8fecSSam Ravnborg
7478b8fecSSam Ravnborg#ifdef __KERNEL__
87ae3aaf5SDavid S. Miller#include <linux/linkage.h>
9478b8fecSSam Ravnborg#include <asm/asi.h>
10478b8fecSSam Ravnborg#include <asm/thread_info.h>
11478b8fecSSam Ravnborg#define GLOBAL_SPARE	%g7
12478b8fecSSam Ravnborg#define RESTORE_ASI(TMP)	\
13*a5ad8378SArnd Bergmann	wr	%g0, ASI_AIUS, %asi
14478b8fecSSam Ravnborg#else
15478b8fecSSam Ravnborg#define GLOBAL_SPARE	%g5
16478b8fecSSam Ravnborg#define RESTORE_ASI(TMP)	\
17478b8fecSSam Ravnborg	wr	%g0, ASI_PNF, %asi
18478b8fecSSam Ravnborg#endif
19478b8fecSSam Ravnborg
20478b8fecSSam Ravnborg#ifdef __sparc_v9__
21478b8fecSSam Ravnborg#define SAVE_AMOUNT	128
22478b8fecSSam Ravnborg#else
23478b8fecSSam Ravnborg#define SAVE_AMOUNT	64
24478b8fecSSam Ravnborg#endif
25478b8fecSSam Ravnborg
26478b8fecSSam Ravnborg#ifndef STORE_ASI
27478b8fecSSam Ravnborg#define STORE_ASI	ASI_BLK_INIT_QUAD_LDD_P
28478b8fecSSam Ravnborg#endif
29478b8fecSSam Ravnborg
30478b8fecSSam Ravnborg#ifndef EX_LD
317ae3aaf5SDavid S. Miller#define EX_LD(x,y)	x
32478b8fecSSam Ravnborg#endif
33478b8fecSSam Ravnborg
34478b8fecSSam Ravnborg#ifndef EX_ST
357ae3aaf5SDavid S. Miller#define EX_ST(x,y)	x
36478b8fecSSam Ravnborg#endif
37478b8fecSSam Ravnborg
38478b8fecSSam Ravnborg#ifndef LOAD
39478b8fecSSam Ravnborg#ifndef MEMCPY_DEBUG
40478b8fecSSam Ravnborg#define LOAD(type,addr,dest)	type [addr], dest
41478b8fecSSam Ravnborg#else
42478b8fecSSam Ravnborg#define LOAD(type,addr,dest)	type##a [addr] 0x80, dest
43478b8fecSSam Ravnborg#endif
44478b8fecSSam Ravnborg#endif
45478b8fecSSam Ravnborg
46478b8fecSSam Ravnborg#ifndef LOAD_TWIN
47478b8fecSSam Ravnborg#define LOAD_TWIN(addr_reg,dest0,dest1)	\
48478b8fecSSam Ravnborg	ldda [addr_reg] ASI_BLK_INIT_QUAD_LDD_P, dest0
49478b8fecSSam Ravnborg#endif
50478b8fecSSam Ravnborg
51478b8fecSSam Ravnborg#ifndef STORE
52478b8fecSSam Ravnborg#define STORE(type,src,addr)	type src, [addr]
53478b8fecSSam Ravnborg#endif
54478b8fecSSam Ravnborg
55478b8fecSSam Ravnborg#ifndef STORE_INIT
56478b8fecSSam Ravnborg#ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
57478b8fecSSam Ravnborg#define STORE_INIT(src,addr)	stxa src, [addr] %asi
58478b8fecSSam Ravnborg#else
59478b8fecSSam Ravnborg#define STORE_INIT(src,addr)	stx src, [addr + 0x00]
60478b8fecSSam Ravnborg#endif
61478b8fecSSam Ravnborg#endif
62478b8fecSSam Ravnborg
63478b8fecSSam Ravnborg#ifndef FUNC_NAME
64478b8fecSSam Ravnborg#define FUNC_NAME	NGmemcpy
65478b8fecSSam Ravnborg#endif
66478b8fecSSam Ravnborg
67478b8fecSSam Ravnborg#ifndef PREAMBLE
68478b8fecSSam Ravnborg#define PREAMBLE
69478b8fecSSam Ravnborg#endif
70478b8fecSSam Ravnborg
71478b8fecSSam Ravnborg#ifndef XCC
72478b8fecSSam Ravnborg#define XCC xcc
73478b8fecSSam Ravnborg#endif
74478b8fecSSam Ravnborg
75478b8fecSSam Ravnborg	.register	%g2,#scratch
76478b8fecSSam Ravnborg	.register	%g3,#scratch
77478b8fecSSam Ravnborg
78478b8fecSSam Ravnborg	.text
797ae3aaf5SDavid S. Miller#ifndef EX_RETVAL
807ae3aaf5SDavid S. Miller#define EX_RETVAL(x)	x
817ae3aaf5SDavid S. Miller__restore_asi:
827ae3aaf5SDavid S. Miller	ret
837ae3aaf5SDavid S. Miller	wr	%g0, ASI_AIUS, %asi
847ae3aaf5SDavid S. Miller	 restore
857ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_i4_plus_1)
867ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
877ae3aaf5SDavid S. Miller	 add	%i2, %i5, %i0
887ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_i4_plus_1)
897ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1)
907ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
917ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
927ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1)
937ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_minus_8)
947ae3aaf5SDavid S. Miller	sub	%g1, 8, %g1
957ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
967ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
977ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_minus_8)
987ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_minus_16)
997ae3aaf5SDavid S. Miller	sub	%g1, 16, %g1
1007ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1017ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
1027ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_minus_16)
1037ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_minus_24)
1047ae3aaf5SDavid S. Miller	sub	%g1, 24, %g1
1057ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1067ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
1077ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_minus_24)
1087ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_minus_32)
1097ae3aaf5SDavid S. Miller	sub	%g1, 32, %g1
1107ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1117ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
1127ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_minus_32)
1137ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_minus_40)
1147ae3aaf5SDavid S. Miller	sub	%g1, 40, %g1
1157ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1167ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
1177ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_minus_40)
1187ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_minus_48)
1197ae3aaf5SDavid S. Miller	sub	%g1, 48, %g1
1207ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1217ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
1227ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_minus_48)
1237ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_minus_56)
1247ae3aaf5SDavid S. Miller	sub	%g1, 56, %g1
1257ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1267ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
1277ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_minus_56)
1287ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_i4)
1297ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1307ae3aaf5SDavid S. Miller	 add	%i2, %i4, %i0
1317ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_i4)
1327ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_i4_minus_8)
1337ae3aaf5SDavid S. Miller	sub	%i4, 8, %i4
1347ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1357ae3aaf5SDavid S. Miller	 add	%i2, %i4, %i0
1367ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_i4_minus_8)
1377ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_8)
1387ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1397ae3aaf5SDavid S. Miller	 add	%i2, 8, %i0
1407ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_8)
1417ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_4)
1427ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1437ae3aaf5SDavid S. Miller	 add	%i2, 4, %i0
1447ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_4)
1457ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_1)
1467ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1477ae3aaf5SDavid S. Miller	 add	%i2, 1, %i0
1487ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_1)
1497ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_plus_g1_plus_1)
1507ae3aaf5SDavid S. Miller	add	%g1, 1, %g1
1517ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1527ae3aaf5SDavid S. Miller	 add	%i2, %g1, %i0
1537ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_plus_g1_plus_1)
1547ae3aaf5SDavid S. MillerENTRY(NG_ret_i2)
1557ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1567ae3aaf5SDavid S. Miller	 mov	%i2, %i0
1577ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2)
1587ae3aaf5SDavid S. MillerENTRY(NG_ret_i2_and_7_plus_i4)
1597ae3aaf5SDavid S. Miller	and	%i2, 7, %i2
1607ae3aaf5SDavid S. Miller	ba,pt	%xcc, __restore_asi
1617ae3aaf5SDavid S. Miller	 add	%i2, %i4, %i0
1627ae3aaf5SDavid S. MillerENDPROC(NG_ret_i2_and_7_plus_i4)
1637ae3aaf5SDavid S. Miller#endif
1647ae3aaf5SDavid S. Miller
165478b8fecSSam Ravnborg	.align		64
166478b8fecSSam Ravnborg
167478b8fecSSam Ravnborg	.globl	FUNC_NAME
168478b8fecSSam Ravnborg	.type	FUNC_NAME,#function
169478b8fecSSam RavnborgFUNC_NAME:	/* %i0=dst, %i1=src, %i2=len */
170478b8fecSSam Ravnborg	PREAMBLE
171478b8fecSSam Ravnborg	save		%sp, -SAVE_AMOUNT, %sp
172478b8fecSSam Ravnborg	srlx		%i2, 31, %g2
173478b8fecSSam Ravnborg	cmp		%g2, 0
174478b8fecSSam Ravnborg	tne		%xcc, 5
175478b8fecSSam Ravnborg	mov		%i0, %o0
176478b8fecSSam Ravnborg	cmp		%i2, 0
177478b8fecSSam Ravnborg	be,pn		%XCC, 85f
178478b8fecSSam Ravnborg	 or		%o0, %i1, %i3
179478b8fecSSam Ravnborg	cmp		%i2, 16
180478b8fecSSam Ravnborg	blu,a,pn	%XCC, 80f
181478b8fecSSam Ravnborg	 or		%i3, %i2, %i3
182478b8fecSSam Ravnborg
183478b8fecSSam Ravnborg	/* 2 blocks (128 bytes) is the minimum we can do the block
184478b8fecSSam Ravnborg	 * copy with.  We need to ensure that we'll iterate at least
185478b8fecSSam Ravnborg	 * once in the block copy loop.  At worst we'll need to align
186478b8fecSSam Ravnborg	 * the destination to a 64-byte boundary which can chew up
187478b8fecSSam Ravnborg	 * to (64 - 1) bytes from the length before we perform the
188478b8fecSSam Ravnborg	 * block copy loop.
189478b8fecSSam Ravnborg	 */
190478b8fecSSam Ravnborg	cmp		%i2, (2 * 64)
191478b8fecSSam Ravnborg	blu,pt		%XCC, 70f
192478b8fecSSam Ravnborg	 andcc		%i3, 0x7, %g0
193478b8fecSSam Ravnborg
194478b8fecSSam Ravnborg	/* %o0:	dst
195478b8fecSSam Ravnborg	 * %i1:	src
196478b8fecSSam Ravnborg	 * %i2:	len  (known to be >= 128)
197478b8fecSSam Ravnborg	 *
198478b8fecSSam Ravnborg	 * The block copy loops will use %i4/%i5,%g2/%g3 as
199478b8fecSSam Ravnborg	 * temporaries while copying the data.
200478b8fecSSam Ravnborg	 */
201478b8fecSSam Ravnborg
202478b8fecSSam Ravnborg	LOAD(prefetch, %i1, #one_read)
203478b8fecSSam Ravnborg	wr		%g0, STORE_ASI, %asi
204478b8fecSSam Ravnborg
205478b8fecSSam Ravnborg	/* Align destination on 64-byte boundary.  */
206478b8fecSSam Ravnborg	andcc		%o0, (64 - 1), %i4
207478b8fecSSam Ravnborg	be,pt		%XCC, 2f
208478b8fecSSam Ravnborg	 sub		%i4, 64, %i4
209478b8fecSSam Ravnborg	sub		%g0, %i4, %i4	! bytes to align dst
210478b8fecSSam Ravnborg	sub		%i2, %i4, %i2
211478b8fecSSam Ravnborg1:	subcc		%i4, 1, %i4
2127ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldub, %i1, %g1), NG_ret_i2_plus_i4_plus_1)
2137ae3aaf5SDavid S. Miller	EX_ST(STORE(stb, %g1, %o0), NG_ret_i2_plus_i4_plus_1)
214478b8fecSSam Ravnborg	add		%i1, 1, %i1
215478b8fecSSam Ravnborg	bne,pt		%XCC, 1b
216478b8fecSSam Ravnborg	add		%o0, 1, %o0
217478b8fecSSam Ravnborg
218478b8fecSSam Ravnborg	/* If the source is on a 16-byte boundary we can do
219478b8fecSSam Ravnborg	 * the direct block copy loop.  If it is 8-byte aligned
220478b8fecSSam Ravnborg	 * we can do the 16-byte loads offset by -8 bytes and the
221478b8fecSSam Ravnborg	 * init stores offset by one register.
222478b8fecSSam Ravnborg	 *
223478b8fecSSam Ravnborg	 * If the source is not even 8-byte aligned, we need to do
224478b8fecSSam Ravnborg	 * shifting and masking (basically integer faligndata).
225478b8fecSSam Ravnborg	 *
226478b8fecSSam Ravnborg	 * The careful bit with init stores is that if we store
227478b8fecSSam Ravnborg	 * to any part of the cache line we have to store the whole
228478b8fecSSam Ravnborg	 * cacheline else we can end up with corrupt L2 cache line
229478b8fecSSam Ravnborg	 * contents.  Since the loop works on 64-bytes of 64-byte
230478b8fecSSam Ravnborg	 * aligned store data at a time, this is easy to ensure.
231478b8fecSSam Ravnborg	 */
232478b8fecSSam Ravnborg2:
233478b8fecSSam Ravnborg	andcc		%i1, (16 - 1), %i4
234478b8fecSSam Ravnborg	andn		%i2, (64 - 1), %g1	! block copy loop iterator
235478b8fecSSam Ravnborg	be,pt		%XCC, 50f
236478b8fecSSam Ravnborg	 sub		%i2, %g1, %i2		! final sub-block copy bytes
237478b8fecSSam Ravnborg
238478b8fecSSam Ravnborg	cmp		%i4, 8
239478b8fecSSam Ravnborg	be,pt		%XCC, 10f
240478b8fecSSam Ravnborg	 sub		%i1, %i4, %i1
241478b8fecSSam Ravnborg
242478b8fecSSam Ravnborg	/* Neither 8-byte nor 16-byte aligned, shift and mask.  */
243478b8fecSSam Ravnborg	and		%i4, 0x7, GLOBAL_SPARE
244478b8fecSSam Ravnborg	sll		GLOBAL_SPARE, 3, GLOBAL_SPARE
245478b8fecSSam Ravnborg	mov		64, %i5
2467ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1, %g2, %g3), NG_ret_i2_plus_g1)
247478b8fecSSam Ravnborg	sub		%i5, GLOBAL_SPARE, %i5
248478b8fecSSam Ravnborg	mov		16, %o4
249478b8fecSSam Ravnborg	mov		32, %o5
250478b8fecSSam Ravnborg	mov		48, %o7
251478b8fecSSam Ravnborg	mov		64, %i3
252478b8fecSSam Ravnborg
253478b8fecSSam Ravnborg	bg,pn	   	%XCC, 9f
254478b8fecSSam Ravnborg	 nop
255478b8fecSSam Ravnborg
256478b8fecSSam Ravnborg#define MIX_THREE_WORDS(WORD1, WORD2, WORD3, PRE_SHIFT, POST_SHIFT, TMP) \
257478b8fecSSam Ravnborg	sllx		WORD1, POST_SHIFT, WORD1; \
258478b8fecSSam Ravnborg	srlx		WORD2, PRE_SHIFT, TMP; \
259478b8fecSSam Ravnborg	sllx		WORD2, POST_SHIFT, WORD2; \
260478b8fecSSam Ravnborg	or		WORD1, TMP, WORD1; \
261478b8fecSSam Ravnborg	srlx		WORD3, PRE_SHIFT, TMP; \
262478b8fecSSam Ravnborg	or		WORD2, TMP, WORD2;
263478b8fecSSam Ravnborg
2647ae3aaf5SDavid S. Miller8:	EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3), NG_ret_i2_plus_g1)
265478b8fecSSam Ravnborg	MIX_THREE_WORDS(%g2, %g3, %o2, %i5, GLOBAL_SPARE, %o1)
266478b8fecSSam Ravnborg	LOAD(prefetch, %i1 + %i3, #one_read)
267478b8fecSSam Ravnborg
2687ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g2, %o0 + 0x00), NG_ret_i2_plus_g1)
2697ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g3, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
270478b8fecSSam Ravnborg
2717ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3), NG_ret_i2_plus_g1_minus_16)
272478b8fecSSam Ravnborg	MIX_THREE_WORDS(%o2, %o3, %g2, %i5, GLOBAL_SPARE, %o1)
273478b8fecSSam Ravnborg
2747ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
2757ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
276478b8fecSSam Ravnborg
2777ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
278478b8fecSSam Ravnborg	MIX_THREE_WORDS(%g2, %g3, %o2, %i5, GLOBAL_SPARE, %o1)
279478b8fecSSam Ravnborg
2807ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g2, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
2817ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g3, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
282478b8fecSSam Ravnborg
2837ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3), NG_ret_i2_plus_g1_minus_48)
284478b8fecSSam Ravnborg	add		%i1, 64, %i1
285478b8fecSSam Ravnborg	MIX_THREE_WORDS(%o2, %o3, %g2, %i5, GLOBAL_SPARE, %o1)
286478b8fecSSam Ravnborg
2877ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
2887ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
289478b8fecSSam Ravnborg
290478b8fecSSam Ravnborg	subcc		%g1, 64, %g1
291478b8fecSSam Ravnborg	bne,pt		%XCC, 8b
292478b8fecSSam Ravnborg	 add		%o0, 64, %o0
293478b8fecSSam Ravnborg
294478b8fecSSam Ravnborg	ba,pt		%XCC, 60f
295478b8fecSSam Ravnborg	 add		%i1, %i4, %i1
296478b8fecSSam Ravnborg
2977ae3aaf5SDavid S. Miller9:	EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3), NG_ret_i2_plus_g1)
298478b8fecSSam Ravnborg	MIX_THREE_WORDS(%g3, %o2, %o3, %i5, GLOBAL_SPARE, %o1)
299478b8fecSSam Ravnborg	LOAD(prefetch, %i1 + %i3, #one_read)
300478b8fecSSam Ravnborg
3017ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g3, %o0 + 0x00), NG_ret_i2_plus_g1)
3027ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
303478b8fecSSam Ravnborg
3047ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3), NG_ret_i2_plus_g1_minus_16)
305478b8fecSSam Ravnborg	MIX_THREE_WORDS(%o3, %g2, %g3, %i5, GLOBAL_SPARE, %o1)
306478b8fecSSam Ravnborg
3077ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
3087ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g2, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
309478b8fecSSam Ravnborg
3107ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
311478b8fecSSam Ravnborg	MIX_THREE_WORDS(%g3, %o2, %o3, %i5, GLOBAL_SPARE, %o1)
312478b8fecSSam Ravnborg
3137ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g3, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
3147ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
315478b8fecSSam Ravnborg
3167ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3), NG_ret_i2_plus_g1_minus_48)
317478b8fecSSam Ravnborg	add		%i1, 64, %i1
318478b8fecSSam Ravnborg	MIX_THREE_WORDS(%o3, %g2, %g3, %i5, GLOBAL_SPARE, %o1)
319478b8fecSSam Ravnborg
3207ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
3217ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%g2, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
322478b8fecSSam Ravnborg
323478b8fecSSam Ravnborg	subcc		%g1, 64, %g1
324478b8fecSSam Ravnborg	bne,pt		%XCC, 9b
325478b8fecSSam Ravnborg	 add		%o0, 64, %o0
326478b8fecSSam Ravnborg
327478b8fecSSam Ravnborg	ba,pt		%XCC, 60f
328478b8fecSSam Ravnborg	 add		%i1, %i4, %i1
329478b8fecSSam Ravnborg
330478b8fecSSam Ravnborg10:	/* Destination is 64-byte aligned, source was only 8-byte
331478b8fecSSam Ravnborg	 * aligned but it has been subtracted by 8 and we perform
332478b8fecSSam Ravnborg	 * one twin load ahead, then add 8 back into source when
333478b8fecSSam Ravnborg	 * we finish the loop.
334478b8fecSSam Ravnborg	 */
3357ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1, %o4, %o5), NG_ret_i2_plus_g1)
336478b8fecSSam Ravnborg	mov	16, %o7
337478b8fecSSam Ravnborg	mov	32, %g2
338478b8fecSSam Ravnborg	mov	48, %g3
339478b8fecSSam Ravnborg	mov	64, %o1
3407ae3aaf5SDavid S. Miller1:	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1)
341478b8fecSSam Ravnborg	LOAD(prefetch, %i1 + %o1, #one_read)
3427ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o5, %o0 + 0x00), NG_ret_i2_plus_g1)	! initializes cache line
3437ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
3447ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5), NG_ret_i2_plus_g1_minus_16)
3457ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
3467ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o4, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
3477ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
3487ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o5, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
3497ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
3507ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %o1, %o4, %o5), NG_ret_i2_plus_g1_minus_48)
351478b8fecSSam Ravnborg	add		%i1, 64, %i1
3527ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
3537ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o4, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
354478b8fecSSam Ravnborg	subcc		%g1, 64, %g1
355478b8fecSSam Ravnborg	bne,pt		%XCC, 1b
356478b8fecSSam Ravnborg	 add		%o0, 64, %o0
357478b8fecSSam Ravnborg
358478b8fecSSam Ravnborg	ba,pt		%XCC, 60f
359478b8fecSSam Ravnborg	 add		%i1, 0x8, %i1
360478b8fecSSam Ravnborg
361478b8fecSSam Ravnborg50:	/* Destination is 64-byte aligned, and source is 16-byte
362478b8fecSSam Ravnborg	 * aligned.
363478b8fecSSam Ravnborg	 */
364478b8fecSSam Ravnborg	mov	16, %o7
365478b8fecSSam Ravnborg	mov	32, %g2
366478b8fecSSam Ravnborg	mov	48, %g3
367478b8fecSSam Ravnborg	mov	64, %o1
3687ae3aaf5SDavid S. Miller1:	EX_LD(LOAD_TWIN(%i1 + %g0, %o4, %o5), NG_ret_i2_plus_g1)
3697ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1)
370478b8fecSSam Ravnborg	LOAD(prefetch, %i1 + %o1, #one_read)
3717ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o4, %o0 + 0x00), NG_ret_i2_plus_g1)	! initializes cache line
3727ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o5, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
3737ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5), NG_ret_i2_plus_g1_minus_16)
3747ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
3757ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
3767ae3aaf5SDavid S. Miller	EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
377478b8fecSSam Ravnborg	add	%i1, 64, %i1
3787ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o4, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
3797ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o5, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
3807ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o2, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
3817ae3aaf5SDavid S. Miller	EX_ST(STORE_INIT(%o3, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
382478b8fecSSam Ravnborg	subcc	%g1, 64, %g1
383478b8fecSSam Ravnborg	bne,pt	%XCC, 1b
384478b8fecSSam Ravnborg	 add	%o0, 64, %o0
385478b8fecSSam Ravnborg	/* fall through */
386478b8fecSSam Ravnborg
387478b8fecSSam Ravnborg60:
388478b8fecSSam Ravnborg	membar		#Sync
389478b8fecSSam Ravnborg
390478b8fecSSam Ravnborg	/* %i2 contains any final bytes still needed to be copied
391478b8fecSSam Ravnborg	 * over. If anything is left, we copy it one byte at a time.
392478b8fecSSam Ravnborg	 */
393478b8fecSSam Ravnborg	RESTORE_ASI(%i3)
394478b8fecSSam Ravnborg	brz,pt		%i2, 85f
395478b8fecSSam Ravnborg	 sub		%o0, %i1, %i3
396478b8fecSSam Ravnborg	ba,a,pt		%XCC, 90f
3970ae2d26fSBabu Moger	 nop
398478b8fecSSam Ravnborg
399478b8fecSSam Ravnborg	.align		64
400478b8fecSSam Ravnborg70: /* 16 < len <= 64 */
401478b8fecSSam Ravnborg	bne,pn		%XCC, 75f
402478b8fecSSam Ravnborg	 sub		%o0, %i1, %i3
403478b8fecSSam Ravnborg
404478b8fecSSam Ravnborg72:
405478b8fecSSam Ravnborg	andn		%i2, 0xf, %i4
406478b8fecSSam Ravnborg	and		%i2, 0xf, %i2
407478b8fecSSam Ravnborg1:	subcc		%i4, 0x10, %i4
4087ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_i4)
409478b8fecSSam Ravnborg	add		%i1, 0x08, %i1
4107ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldx, %i1, %g1), NG_ret_i2_plus_i4)
411478b8fecSSam Ravnborg	sub		%i1, 0x08, %i1
4127ae3aaf5SDavid S. Miller	EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_i4)
413478b8fecSSam Ravnborg	add		%i1, 0x8, %i1
4147ae3aaf5SDavid S. Miller	EX_ST(STORE(stx, %g1, %i1 + %i3), NG_ret_i2_plus_i4_minus_8)
415478b8fecSSam Ravnborg	bgu,pt		%XCC, 1b
416478b8fecSSam Ravnborg	 add		%i1, 0x8, %i1
417478b8fecSSam Ravnborg73:	andcc		%i2, 0x8, %g0
418478b8fecSSam Ravnborg	be,pt		%XCC, 1f
419478b8fecSSam Ravnborg	 nop
420478b8fecSSam Ravnborg	sub		%i2, 0x8, %i2
4217ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_8)
4227ae3aaf5SDavid S. Miller	EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_8)
423478b8fecSSam Ravnborg	add		%i1, 0x8, %i1
424478b8fecSSam Ravnborg1:	andcc		%i2, 0x4, %g0
425478b8fecSSam Ravnborg	be,pt		%XCC, 1f
426478b8fecSSam Ravnborg	 nop
427478b8fecSSam Ravnborg	sub		%i2, 0x4, %i2
4287ae3aaf5SDavid S. Miller	EX_LD(LOAD(lduw, %i1, %i5), NG_ret_i2_plus_4)
4297ae3aaf5SDavid S. Miller	EX_ST(STORE(stw, %i5, %i1 + %i3), NG_ret_i2_plus_4)
430478b8fecSSam Ravnborg	add		%i1, 0x4, %i1
431478b8fecSSam Ravnborg1:	cmp		%i2, 0
432478b8fecSSam Ravnborg	be,pt		%XCC, 85f
433478b8fecSSam Ravnborg	 nop
434478b8fecSSam Ravnborg	ba,pt		%xcc, 90f
435478b8fecSSam Ravnborg	 nop
436478b8fecSSam Ravnborg
437478b8fecSSam Ravnborg75:
438478b8fecSSam Ravnborg	andcc		%o0, 0x7, %g1
439478b8fecSSam Ravnborg	sub		%g1, 0x8, %g1
440478b8fecSSam Ravnborg	be,pn		%icc, 2f
441478b8fecSSam Ravnborg	 sub		%g0, %g1, %g1
442478b8fecSSam Ravnborg	sub		%i2, %g1, %i2
443478b8fecSSam Ravnborg
444478b8fecSSam Ravnborg1:	subcc		%g1, 1, %g1
4457ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldub, %i1, %i5), NG_ret_i2_plus_g1_plus_1)
4467ae3aaf5SDavid S. Miller	EX_ST(STORE(stb, %i5, %i1 + %i3), NG_ret_i2_plus_g1_plus_1)
447478b8fecSSam Ravnborg	bgu,pt		%icc, 1b
448478b8fecSSam Ravnborg	 add		%i1, 1, %i1
449478b8fecSSam Ravnborg
450478b8fecSSam Ravnborg2:	add		%i1, %i3, %o0
451478b8fecSSam Ravnborg	andcc		%i1, 0x7, %g1
452478b8fecSSam Ravnborg	bne,pt		%icc, 8f
453478b8fecSSam Ravnborg	 sll		%g1, 3, %g1
454478b8fecSSam Ravnborg
455478b8fecSSam Ravnborg	cmp		%i2, 16
456478b8fecSSam Ravnborg	bgeu,pt		%icc, 72b
457478b8fecSSam Ravnborg	 nop
458478b8fecSSam Ravnborg	ba,a,pt		%xcc, 73b
459478b8fecSSam Ravnborg
460478b8fecSSam Ravnborg8:	mov		64, %i3
461478b8fecSSam Ravnborg	andn		%i1, 0x7, %i1
4627ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldx, %i1, %g2), NG_ret_i2)
463478b8fecSSam Ravnborg	sub		%i3, %g1, %i3
464478b8fecSSam Ravnborg	andn		%i2, 0x7, %i4
465478b8fecSSam Ravnborg	sllx		%g2, %g1, %g2
466478b8fecSSam Ravnborg1:	add		%i1, 0x8, %i1
4677ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldx, %i1, %g3), NG_ret_i2_and_7_plus_i4)
468478b8fecSSam Ravnborg	subcc		%i4, 0x8, %i4
469478b8fecSSam Ravnborg	srlx		%g3, %i3, %i5
470478b8fecSSam Ravnborg	or		%i5, %g2, %i5
4717ae3aaf5SDavid S. Miller	EX_ST(STORE(stx, %i5, %o0), NG_ret_i2_and_7_plus_i4)
472478b8fecSSam Ravnborg	add		%o0, 0x8, %o0
473478b8fecSSam Ravnborg	bgu,pt		%icc, 1b
474478b8fecSSam Ravnborg	 sllx		%g3, %g1, %g2
475478b8fecSSam Ravnborg
476478b8fecSSam Ravnborg	srl		%g1, 3, %g1
477478b8fecSSam Ravnborg	andcc		%i2, 0x7, %i2
478478b8fecSSam Ravnborg	be,pn		%icc, 85f
479478b8fecSSam Ravnborg	 add		%i1, %g1, %i1
480478b8fecSSam Ravnborg	ba,pt		%xcc, 90f
481478b8fecSSam Ravnborg	 sub		%o0, %i1, %i3
482478b8fecSSam Ravnborg
483478b8fecSSam Ravnborg	.align		64
484478b8fecSSam Ravnborg80: /* 0 < len <= 16 */
485478b8fecSSam Ravnborg	andcc		%i3, 0x3, %g0
486478b8fecSSam Ravnborg	bne,pn		%XCC, 90f
487478b8fecSSam Ravnborg	 sub		%o0, %i1, %i3
488478b8fecSSam Ravnborg
489478b8fecSSam Ravnborg1:
490478b8fecSSam Ravnborg	subcc		%i2, 4, %i2
4917ae3aaf5SDavid S. Miller	EX_LD(LOAD(lduw, %i1, %g1), NG_ret_i2_plus_4)
4927ae3aaf5SDavid S. Miller	EX_ST(STORE(stw, %g1, %i1 + %i3), NG_ret_i2_plus_4)
493478b8fecSSam Ravnborg	bgu,pt		%XCC, 1b
494478b8fecSSam Ravnborg	 add		%i1, 4, %i1
495478b8fecSSam Ravnborg
496478b8fecSSam Ravnborg85:	ret
497478b8fecSSam Ravnborg	 restore	EX_RETVAL(%i0), %g0, %o0
498478b8fecSSam Ravnborg
499478b8fecSSam Ravnborg	.align		32
500478b8fecSSam Ravnborg90:
501478b8fecSSam Ravnborg	subcc		%i2, 1, %i2
5027ae3aaf5SDavid S. Miller	EX_LD(LOAD(ldub, %i1, %g1), NG_ret_i2_plus_1)
5037ae3aaf5SDavid S. Miller	EX_ST(STORE(stb, %g1, %i1 + %i3), NG_ret_i2_plus_1)
504478b8fecSSam Ravnborg	bgu,pt		%XCC, 90b
505478b8fecSSam Ravnborg	 add		%i1, 1, %i1
506478b8fecSSam Ravnborg	ret
507478b8fecSSam Ravnborg	 restore	EX_RETVAL(%i0), %g0, %o0
508478b8fecSSam Ravnborg
509478b8fecSSam Ravnborg	.size		FUNC_NAME, .-FUNC_NAME
510