xref: /linux/arch/sh/lib/checksum.S (revision 6e7fd890f1d6ac83805409e9c346240de2705584)
1/* SPDX-License-Identifier: GPL-2.0+
2 *
3 * $Id: checksum.S,v 1.10 2001/07/06 13:11:32 gniibe Exp $
4 *
5 * INET		An implementation of the TCP/IP protocol suite for the LINUX
6 *		operating system.  INET is implemented using the  BSD Socket
7 *		interface as the means of communication with the user level.
8 *
9 *		IP/TCP/UDP checksumming routines
10 *
11 * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
12 *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
13 *		Tom May, <ftom@netcom.com>
14 *              Pentium Pro/II routines:
15 *              Alexander Kjeldaas <astor@guardian.no>
16 *              Finn Arne Gangstad <finnag@guardian.no>
17 *		Lots of code moved from tcp.c and ip.c; see those files
18 *		for more names.
19 *
20 * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
21 *			     handling.
22 *		Andi Kleen,  add zeroing on error
23 *                   converted to pure assembler
24 *
25 * SuperH version:  Copyright (C) 1999  Niibe Yutaka
26 */
27
28#include <asm/errno.h>
29#include <linux/linkage.h>
30
31/*
32 * computes a partial checksum, e.g. for TCP/UDP fragments
33 */
34
35/*
36 * unsigned int csum_partial(const unsigned char *buf, int len,
37 *                           unsigned int sum);
38 */
39
40.text
41ENTRY(csum_partial)
42	  /*
43	   * Experiments with Ethernet and SLIP connections show that buff
44	   * is aligned on either a 2-byte or 4-byte boundary.  We get at
45	   * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
46	   * Fortunately, it is easy to convert 2-byte alignment to 4-byte
47	   * alignment for the unrolled loop.
48	   */
49	mov	r5, r1
50	mov	r4, r0
51	tst	#2, r0		! Check alignment.
52	bt	2f		! Jump if alignment is ok.
53	!
54	add	#-2, r5		! Alignment uses up two bytes.
55	cmp/pz	r5		!
56	bt/s	1f		! Jump if we had at least two bytes.
57	 clrt
58	bra	6f
59	 add	#2, r5		! r5 was < 2.  Deal with it.
601:
61	mov	r5, r1		! Save new len for later use.
62	mov.w	@r4+, r0
63	extu.w	r0, r0
64	addc	r0, r6
65	bf	2f
66	add	#1, r6
672:
68	mov	#-5, r0
69	shld	r0, r5
70	tst	r5, r5
71	bt/s	4f		! if it's =0, go to 4f
72	 clrt
73	.align	2
743:
75	mov.l	@r4+, r0
76	mov.l	@r4+, r2
77	mov.l	@r4+, r3
78	addc	r0, r6
79	mov.l	@r4+, r0
80	addc	r2, r6
81	mov.l	@r4+, r2
82	addc	r3, r6
83	mov.l	@r4+, r3
84	addc	r0, r6
85	mov.l	@r4+, r0
86	addc	r2, r6
87	mov.l	@r4+, r2
88	addc	r3, r6
89	addc	r0, r6
90	addc	r2, r6
91	movt	r0
92	dt	r5
93	bf/s	3b
94	 cmp/eq	#1, r0
95	! here, we know r5==0
96	addc	r5, r6			! add carry to r6
974:
98	mov	r1, r0
99	and	#0x1c, r0
100	tst	r0, r0
101	bt/s	6f
102	 mov	r0, r5
103	shlr2	r5
104	mov	#0, r2
1055:
106	addc	r2, r6
107	mov.l	@r4+, r2
108	movt	r0
109	dt	r5
110	bf/s	5b
111	 cmp/eq	#1, r0
112	addc	r2, r6
113	addc	r5, r6		! r5==0 here, so it means add carry-bit
1146:
115	mov	r1, r5
116	mov	#3, r0
117	and	r0, r5
118	tst	r5, r5
119	bt	9f		! if it's =0 go to 9f
120	mov	#2, r1
121	cmp/hs  r1, r5
122	bf	7f
123	mov.w	@r4+, r0
124	extu.w	r0, r0
125	cmp/eq	r1, r5
126	bt/s	8f
127	 clrt
128	shll16	r0
129	addc	r0, r6
1307:
131	mov.b	@r4+, r0
132	extu.b	r0, r0
133#ifndef	__LITTLE_ENDIAN__
134	shll8	r0
135#endif
1368:
137	addc	r0, r6
138	mov	#0, r0
139	addc	r0, r6
1409:
141	rts
142	 mov	r6, r0
143
144/*
145unsigned int csum_partial_copy_generic (const char *src, char *dst, int len)
146 */
147
148/*
149 * Copy from ds while checksumming, otherwise like csum_partial with initial
150 * sum being ~0U
151 */
152
153#define EXC(...)			\
154	9999: __VA_ARGS__ ;		\
155	.section __ex_table, "a";	\
156	.long 9999b, 6001f	;	\
157	.previous
158
159!
160! r4:	const char *SRC
161! r5:	char *DST
162! r6:	int LEN
163!
164ENTRY(csum_partial_copy_generic)
165	mov	#-1,r7
166	mov	#3,r0		! Check src and dest are equally aligned
167	mov	r4,r1
168	and	r0,r1
169	and	r5,r0
170	cmp/eq	r1,r0
171	bf	3f		! Different alignments, use slow version
172	tst	#1,r0		! Check dest word aligned
173	bf	3f		! If not, do it the slow way
174
175	mov	#2,r0
176	tst	r0,r5		! Check dest alignment.
177	bt	2f		! Jump if alignment is ok.
178	add	#-2,r6		! Alignment uses up two bytes.
179	cmp/pz	r6		! Jump if we had at least two bytes.
180	bt/s	1f
181	 clrt
182	add	#2,r6		! r6 was < 2.	Deal with it.
183	bra	4f
184	 mov	r6,r2
185
1863:	! Handle different src and dest alignments.
187	! This is not common, so simple byte by byte copy will do.
188	mov	r6,r2
189	shlr	r6
190	tst	r6,r6
191	bt	4f
192	clrt
193	.align	2
1945:
195EXC(	mov.b	@r4+,r1 	)
196EXC(	mov.b	@r4+,r0		)
197	extu.b	r1,r1
198EXC(	mov.b	r1,@r5		)
199EXC(	mov.b	r0,@(1,r5)	)
200	extu.b	r0,r0
201	add	#2,r5
202
203#ifdef	__LITTLE_ENDIAN__
204	shll8	r0
205#else
206	shll8	r1
207#endif
208	or	r1,r0
209
210	addc	r0,r7
211	movt	r0
212	dt	r6
213	bf/s	5b
214	 cmp/eq	#1,r0
215	mov	#0,r0
216	addc	r0, r7
217
218	mov	r2, r0
219	tst	#1, r0
220	bt	7f
221	bra	5f
222	 clrt
223
224	! src and dest equally aligned, but to a two byte boundary.
225	! Handle first two bytes as a special case
226	.align	2
2271:
228EXC(	mov.w	@r4+,r0		)
229EXC(	mov.w	r0,@r5		)
230	add	#2,r5
231	extu.w	r0,r0
232	addc	r0,r7
233	mov	#0,r0
234	addc	r0,r7
2352:
236	mov	r6,r2
237	mov	#-5,r0
238	shld	r0,r6
239	tst	r6,r6
240	bt/s	2f
241	 clrt
242	.align	2
2431:
244EXC(	mov.l	@r4+,r0		)
245EXC(	mov.l	@r4+,r1		)
246	addc	r0,r7
247EXC(	mov.l	r0,@r5		)
248EXC(	mov.l	r1,@(4,r5)	)
249	addc	r1,r7
250
251EXC(	mov.l	@r4+,r0		)
252EXC(	mov.l	@r4+,r1		)
253	addc	r0,r7
254EXC(	mov.l	r0,@(8,r5)	)
255EXC(	mov.l	r1,@(12,r5)	)
256	addc	r1,r7
257
258EXC(	mov.l	@r4+,r0 	)
259EXC(	mov.l	@r4+,r1		)
260	addc	r0,r7
261EXC(	mov.l	r0,@(16,r5)	)
262EXC(	mov.l	r1,@(20,r5)	)
263	addc	r1,r7
264
265EXC(	mov.l	@r4+,r0		)
266EXC(	mov.l	@r4+,r1		)
267	addc	r0,r7
268EXC(	mov.l	r0,@(24,r5)	)
269EXC(	mov.l	r1,@(28,r5)	)
270	addc	r1,r7
271	add	#32,r5
272	movt	r0
273	dt	r6
274	bf/s	1b
275	 cmp/eq	#1,r0
276	mov	#0,r0
277	addc	r0,r7
278
2792:	mov	r2,r6
280	mov	#0x1c,r0
281	and	r0,r6
282	cmp/pl	r6
283	bf/s	4f
284	 clrt
285	shlr2	r6
2863:
287EXC(	mov.l	@r4+,r0	)
288	addc	r0,r7
289EXC(	mov.l	r0,@r5	)
290	add	#4,r5
291	movt	r0
292	dt	r6
293	bf/s	3b
294	 cmp/eq	#1,r0
295	mov	#0,r0
296	addc	r0,r7
2974:	mov	r2,r6
298	mov	#3,r0
299	and	r0,r6
300	cmp/pl	r6
301	bf	7f
302	mov	#2,r1
303	cmp/hs	r1,r6
304	bf	5f
305EXC(	mov.w	@r4+,r0	)
306EXC(	mov.w	r0,@r5	)
307	extu.w	r0,r0
308	add	#2,r5
309	cmp/eq	r1,r6
310	bt/s	6f
311	 clrt
312	shll16	r0
313	addc	r0,r7
3145:
315EXC(	mov.b	@r4+,r0	)
316EXC(	mov.b	r0,@r5	)
317	extu.b	r0,r0
318#ifndef	__LITTLE_ENDIAN__
319	shll8	r0
320#endif
3216:	addc	r0,r7
322	mov	#0,r0
323	addc	r0,r7
3247:
325
326# Exception handler:
327.section .fixup, "ax"
328
3296001:
330	rts
331	 mov	#0,r0
332.previous
333	rts
334	 mov	r7,r0
335