xref: /linux-6.15/arch/mips/lib/csum_partial.S (revision ed99e2bc)
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Quick'n'dirty IP checksum ...
7 *
8 * Copyright (C) 1998, 1999 Ralf Baechle
9 * Copyright (C) 1999 Silicon Graphics, Inc.
10 */
11#include <asm/asm.h>
12#include <asm/regdef.h>
13
14#ifdef CONFIG_64BIT
15/*
16 * As we are sharing code base with the mips32 tree (which use the o32 ABI
17 * register definitions). We need to redefine the register definitions from
18 * the n64 ABI register naming to the o32 ABI register naming.
19 */
20#undef t0
21#undef t1
22#undef t2
23#undef t3
24#define t0	$8
25#define t1	$9
26#define t2	$10
27#define t3	$11
28#define t4	$12
29#define t5	$13
30#define t6	$14
31#define t7	$15
32
33#define USE_DOUBLE
34#endif
35
36#ifdef USE_DOUBLE
37
38#define LOAD   ld
39#define ADD    daddu
40#define NBYTES 8
41
42#else
43
44#define LOAD   lw
45#define ADD    addu
46#define NBYTES 4
47
48#endif /* USE_DOUBLE */
49
50#define UNIT(unit)  ((unit)*NBYTES)
51
52#define ADDC(sum,reg)						\
53	ADD	sum, reg;					\
54	sltu	v1, sum, reg;					\
55	ADD	sum, v1
56
57#define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3)	\
58	LOAD	_t0, (offset + UNIT(0))(src);			\
59	LOAD	_t1, (offset + UNIT(1))(src);			\
60	LOAD	_t2, (offset + UNIT(2))(src); 			\
61	LOAD	_t3, (offset + UNIT(3))(src); 			\
62	ADDC(sum, _t0);						\
63	ADDC(sum, _t1);						\
64	ADDC(sum, _t2);						\
65	ADDC(sum, _t3)
66
67#ifdef USE_DOUBLE
68#define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3)	\
69	CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3)
70#else
71#define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3)	\
72	CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3);	\
73	CSUM_BIGCHUNK1(src, offset + 0x10, sum, _t0, _t1, _t2, _t3)
74#endif
75
76/*
77 * a0: source address
78 * a1: length of the area to checksum
79 * a2: partial checksum
80 */
81
82#define src a0
83#define sum v0
84
85	.text
86	.set	noreorder
87	.align	5
88LEAF(csum_partial)
89	move	sum, zero
90	move	t7, zero
91
92	sltiu	t8, a1, 0x8
93	bnez	t8, small_csumcpy		/* < 8 bytes to copy */
94	 move	t2, a1
95
96	andi	t7, src, 0x1			/* odd buffer? */
97
98hword_align:
99	beqz	t7, word_align
100	 andi	t8, src, 0x2
101
102	lbu	t0, (src)
103	LONG_SUBU	a1, a1, 0x1
104#ifdef __MIPSEL__
105	sll	t0, t0, 8
106#endif
107	ADDC(sum, t0)
108	PTR_ADDU	src, src, 0x1
109	andi	t8, src, 0x2
110
111word_align:
112	beqz	t8, dword_align
113	 sltiu	t8, a1, 56
114
115	lhu	t0, (src)
116	LONG_SUBU	a1, a1, 0x2
117	ADDC(sum, t0)
118	sltiu	t8, a1, 56
119	PTR_ADDU	src, src, 0x2
120
121dword_align:
122	bnez	t8, do_end_words
123	 move	t8, a1
124
125	andi	t8, src, 0x4
126	beqz	t8, qword_align
127	 andi	t8, src, 0x8
128
129	lw	t0, 0x00(src)
130	LONG_SUBU	a1, a1, 0x4
131	ADDC(sum, t0)
132	PTR_ADDU	src, src, 0x4
133	andi	t8, src, 0x8
134
135qword_align:
136	beqz	t8, oword_align
137	 andi	t8, src, 0x10
138
139#ifdef USE_DOUBLE
140	ld	t0, 0x00(src)
141	LONG_SUBU	a1, a1, 0x8
142	ADDC(sum, t0)
143#else
144	lw	t0, 0x00(src)
145	lw	t1, 0x04(src)
146	LONG_SUBU	a1, a1, 0x8
147	ADDC(sum, t0)
148	ADDC(sum, t1)
149#endif
150	PTR_ADDU	src, src, 0x8
151	andi	t8, src, 0x10
152
153oword_align:
154	beqz	t8, begin_movement
155	 LONG_SRL	t8, a1, 0x7
156
157#ifdef USE_DOUBLE
158	ld	t0, 0x00(src)
159	ld	t1, 0x08(src)
160	ADDC(sum, t0)
161	ADDC(sum, t1)
162#else
163	CSUM_BIGCHUNK1(src, 0x00, sum, t0, t1, t3, t4)
164#endif
165	LONG_SUBU	a1, a1, 0x10
166	PTR_ADDU	src, src, 0x10
167	LONG_SRL	t8, a1, 0x7
168
169begin_movement:
170	beqz	t8, 1f
171	 andi	t2, a1, 0x40
172
173move_128bytes:
174	CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
175	CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4)
176	CSUM_BIGCHUNK(src, 0x40, sum, t0, t1, t3, t4)
177	CSUM_BIGCHUNK(src, 0x60, sum, t0, t1, t3, t4)
178	LONG_SUBU	t8, t8, 0x01
179	bnez	t8, move_128bytes
180	 PTR_ADDU	src, src, 0x80
181
1821:
183	beqz	t2, 1f
184	 andi	t2, a1, 0x20
185
186move_64bytes:
187	CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
188	CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4)
189	PTR_ADDU	src, src, 0x40
190
1911:
192	beqz	t2, do_end_words
193	 andi	t8, a1, 0x1c
194
195move_32bytes:
196	CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
197	andi	t8, a1, 0x1c
198	PTR_ADDU	src, src, 0x20
199
200do_end_words:
201	beqz	t8, small_csumcpy
202	 andi	t2, a1, 0x3
203	LONG_SRL	t8, t8, 0x2
204
205end_words:
206	lw	t0, (src)
207	LONG_SUBU	t8, t8, 0x1
208	ADDC(sum, t0)
209	bnez	t8, end_words
210	 PTR_ADDU	src, src, 0x4
211
212/* unknown src alignment and < 8 bytes to go  */
213small_csumcpy:
214	move	a1, t2
215
216	andi	t0, a1, 4
217	beqz	t0, 1f
218	 andi	t0, a1, 2
219
220	/* Still a full word to go  */
221	ulw	t1, (src)
222	PTR_ADDIU	src, 4
223	ADDC(sum, t1)
224
2251:	move	t1, zero
226	beqz	t0, 1f
227	 andi	t0, a1, 1
228
229	/* Still a halfword to go  */
230	ulhu	t1, (src)
231	PTR_ADDIU	src, 2
232
2331:	beqz	t0, 1f
234	 sll	t1, t1, 16
235
236	lbu	t2, (src)
237	 nop
238
239#ifdef __MIPSEB__
240	sll	t2, t2, 8
241#endif
242	or	t1, t2
243
2441:	ADDC(sum, t1)
245
246	/* fold checksum */
247#ifdef USE_DOUBLE
248	dsll32	v1, sum, 0
249	daddu	sum, v1
250	sltu	v1, sum, v1
251	dsra32	sum, sum, 0
252	addu	sum, v1
253#endif
254	sll	v1, sum, 16
255	addu	sum, v1
256	sltu	v1, sum, v1
257	srl	sum, sum, 16
258	addu	sum, v1
259
260	/* odd buffer alignment? */
261	beqz	t7, 1f
262	 nop
263	sll	v1, sum, 8
264	srl	sum, sum, 8
265	or	sum, v1
266	andi	sum, 0xffff
2671:
268	.set	reorder
269	/* Add the passed partial csum.  */
270	ADDC(sum, a2)
271	jr	ra
272	.set	noreorder
273	END(csum_partial)
274