1 ; SPDX-License-Identifier: GPL-2.0-only
2 ;
3 ;  linux/arch/c6x/lib/csum_64plus.s
4 ;
5 ;  Port on Texas Instruments TMS320C6x architecture
6 ;
7 ;  Copyright (C) 2006, 2009, 2010, 2011 Texas Instruments Incorporated
8 ;  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
9 ;
10 #include <linux/linkage.h>
11 
12 ;
13 ;unsigned int csum_partial_copy_nocheck(const char *src, char * dst,
14 ;					int len, int sum)
15 ;
16 ; A4:	src
17 ; B4:	dst
18 ; A6:	len
19 ; B6:	sum
20 ; return csum in A4
21 ;
22 
23 	.text
24 ENTRY(csum_partial_copy_nocheck)
25 	MVC	.S2	ILC,B30
26 
27 	ZERO	.D1	A9		; csum (a side)
28 ||	ZERO	.D2	B9		; csum (b side)
29 ||	SHRU	.S2X	A6,2,B5		; len / 4
30 
31 	;; Check alignment and size
32 	AND	.S1	3,A4,A1
33 ||	AND	.S2	3,B4,B0
34 	OR	.L2X	B0,A1,B0	; non aligned condition
35 ||	MVC	.S2	B5,ILC
36 ||	MVK	.D2	1,B2
37 ||	MV	.D1X	B5,A1		; words condition
38   [!A1]	B	.S1	L8
39    [B0] BNOP	.S1	L6,5
40 
41 	SPLOOP		1
42 
43 	;; Main loop for aligned words
44 	LDW	.D1T1	*A4++,A7
45 	NOP	4
46 	MV	.S2X	A7,B7
47 ||	EXTU	.S1	A7,0,16,A16
48 	STW	.D2T2	B7,*B4++
49 ||	MPYU	.M2	B7,B2,B8
50 ||	ADD	.L1	A16,A9,A9
51 	NOP
52 	SPKERNEL	8,0
53 ||	ADD	.L2	B8,B9,B9
54 
55 	ZERO	.D1	A1
56 ||	ADD	.L1X	A9,B9,A9	;  add csum from a and b sides
57 
58 L6:
59   [!A1]	BNOP	.S1	L8,5
60 
61 	;; Main loop for non-aligned words
62 	SPLOOP		2
63  ||	MVK	.L1	1,A2
64 
65 	LDNW	.D1T1	*A4++,A7
66 	NOP		3
67 
68 	NOP
69 	MV	.S2X	A7,B7
70  ||	EXTU	.S1	A7,0,16,A16
71  ||	MPYU	.M1	A7,A2,A8
72 
73 	ADD	.L1	A16,A9,A9
74 	SPKERNEL	6,0
75  ||	STNW	.D2T2	B7,*B4++
76  ||	ADD	.L1	A8,A9,A9
77 
78 L8:	AND	.S2X	2,A6,B5
79 	CMPGT	.L2	B5,0,B0
80   [!B0]	BNOP	.S1	L82,4
81 
82 	;; Manage half-word
83 	ZERO	.L1	A7
84 ||	ZERO	.D1	A8
85 
86 #ifdef CONFIG_CPU_BIG_ENDIAN
87 
88 	LDBU	.D1T1	*A4++,A7
89 	LDBU	.D1T1	*A4++,A8
90 	NOP		3
91 	SHL	.S1	A7,8,A0
92 	ADD	.S1	A8,A9,A9
93 	STB	.D2T1	A7,*B4++
94 ||	ADD	.S1	A0,A9,A9
95 	STB	.D2T1	A8,*B4++
96 
97 #else
98 
99 	LDBU	.D1T1	*A4++,A7
100 	LDBU	.D1T1	*A4++,A8
101 	NOP		3
102 	ADD	.S1	A7,A9,A9
103 	SHL	.S1	A8,8,A0
104 
105 	STB	.D2T1	A7,*B4++
106 ||	ADD	.S1	A0,A9,A9
107 	STB	.D2T1	A8,*B4++
108 
109 #endif
110 
111 	;; Manage eventually the last byte
112 L82:	AND	.S2X	1,A6,B0
113   [!B0]	BNOP	.S1	L9,5
114 
115 ||	ZERO	.L1	A7
116 
117 L83:	LDBU	.D1T1	*A4++,A7
118 	NOP		4
119 
120 	MV	.L2X	A7,B7
121 
122 #ifdef CONFIG_CPU_BIG_ENDIAN
123 
124 	STB	.D2T2	B7,*B4++
125 ||	SHL	.S1	A7,8,A7
126 	ADD	.S1	A7,A9,A9
127 
128 #else
129 
130 	STB	.D2T2	B7,*B4++
131 ||	ADD	.S1	A7,A9,A9
132 
133 #endif
134 
135 	;; Fold the csum
136 L9:	SHRU	.S2X	A9,16,B0
137   [!B0]	BNOP	.S1	L10,5
138 
139 L91:	SHRU	.S2X	A9,16,B4
140 ||	EXTU	.S1	A9,16,16,A3
141 	ADD	.D1X	A3,B4,A9
142 
143 	SHRU	.S1	A9,16,A0
144    [A0]	BNOP	.S1	L91,5
145 
146 L10:	MV	.D1	A9,A4
147 
148 	BNOP	.S2	B3,4
149 	MVC	.S2	B30,ILC
150 ENDPROC(csum_partial_copy_nocheck)
151 
152 ;
153 ;unsigned short
154 ;ip_fast_csum(unsigned char *iph, unsigned int ihl)
155 ;{
156 ;	unsigned int checksum = 0;
157 ;	unsigned short *tosum = (unsigned short *) iph;
158 ;	int len;
159 ;
160 ;	len = ihl*4;
161 ;
162 ;	if (len <= 0)
163 ;		return 0;
164 ;
165 ;	while(len) {
166 ;		len -= 2;
167 ;		checksum += *tosum++;
168 ;	}
169 ;	if (len & 1)
170 ;		checksum += *(unsigned char*) tosum;
171 ;
172 ;	while(checksum >> 16)
173 ;		checksum = (checksum & 0xffff) + (checksum >> 16);
174 ;
175 ;	return ~checksum;
176 ;}
177 ;
178 ; A4:	iph
179 ; B4:	ihl
180 ; return checksum in A4
181 ;
182 	.text
183 
184 ENTRY(ip_fast_csum)
185 	ZERO	.D1	A5
186  ||	MVC	.S2	ILC,B30
187 	SHL	.S2	B4,2,B0
188 	CMPGT	.L2	B0,0,B1
189   [!B1] BNOP	.S1	L15,4
190   [!B1]	ZERO	.D1	A3
191 
192   [!B0]	B	.S1	L12
193 	SHRU	.S2	B0,1,B0
194 	MVC	.S2	B0,ILC
195 	NOP	3
196 
197 	SPLOOP	1
198 	LDHU	.D1T1	*A4++,A3
199 	NOP	3
200 	NOP
201 	SPKERNEL	5,0
202  ||	ADD	.L1	A3,A5,A5
203 
204 L12:	SHRU	.S1	A5,16,A0
205   [!A0]	BNOP	.S1	L14,5
206 
207 L13:	SHRU	.S2X	A5,16,B4
208 	EXTU	.S1	A5,16,16,A3
209 	ADD	.D1X	A3,B4,A5
210 	SHRU	.S1	A5,16,A0
211   [A0]	BNOP	.S1	L13,5
212 
213 L14:	NOT	.D1	A5,A3
214 	EXTU	.S1	A3,16,16,A3
215 
216 L15:	BNOP	.S2	B3,3
217 	MVC	.S2	B30,ILC
218 	MV	.D1	A3,A4
219 ENDPROC(ip_fast_csum)
220 
221 ;
222 ;unsigned short
223 ;do_csum(unsigned char *buff, unsigned int len)
224 ;{
225 ;	int odd, count;
226 ;	unsigned int result = 0;
227 ;
228 ;	if (len <= 0)
229 ;		goto out;
230 ;	odd = 1 & (unsigned long) buff;
231 ;	if (odd) {
232 ;#ifdef __LITTLE_ENDIAN
233 ;		result += (*buff << 8);
234 ;#else
235 ;		result = *buff;
236 ;#endif
237 ;		len--;
238 ;		buff++;
239 ;	}
240 ;	count = len >> 1;		/* nr of 16-bit words.. */
241 ;	if (count) {
242 ;		if (2 & (unsigned long) buff) {
243 ;			result += *(unsigned short *) buff;
244 ;			count--;
245 ;			len -= 2;
246 ;			buff += 2;
247 ;		}
248 ;		count >>= 1;		/* nr of 32-bit words.. */
249 ;		if (count) {
250 ;			unsigned int carry = 0;
251 ;			do {
252 ;				unsigned int w = *(unsigned int *) buff;
253 ;				count--;
254 ;				buff += 4;
255 ;				result += carry;
256 ;				result += w;
257 ;				carry = (w > result);
258 ;			} while (count);
259 ;			result += carry;
260 ;			result = (result & 0xffff) + (result >> 16);
261 ;		}
262 ;		if (len & 2) {
263 ;			result += *(unsigned short *) buff;
264 ;			buff += 2;
265 ;		}
266 ;	}
267 ;	if (len & 1)
268 ;#ifdef __LITTLE_ENDIAN
269 ;		result += *buff;
270 ;#else
271 ;		result += (*buff << 8);
272 ;#endif
273 ;	result = (result & 0xffff) + (result >> 16);
274 ;	/* add up carry.. */
275 ;	result = (result & 0xffff) + (result >> 16);
276 ;	if (odd)
277 ;		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
278 ;out:
279 ;	return result;
280 ;}
281 ;
282 ; A4:	buff
283 ; B4:	len
284 ; return checksum in A4
285 ;
286 
287 ENTRY(do_csum)
288 	   CMPGT   .L2	   B4,0,B0
289    [!B0]   BNOP    .S1	   L26,3
290 	   EXTU    .S1	   A4,31,31,A0
291 
292 	   MV	   .L1	   A0,A3
293 ||	   MV	   .S1X    B3,A5
294 ||	   MV	   .L2	   B4,B3
295 ||	   ZERO    .D1	   A1
296 
297 #ifdef CONFIG_CPU_BIG_ENDIAN
298    [A0]    SUB	   .L2	   B3,1,B3
299 || [A0]    LDBU    .D1T1   *A4++,A1
300 #else
301    [!A0]   BNOP    .S1	   L21,5
302 || [A0]    LDBU    .D1T1   *A4++,A0
303 	   SUB	   .L2	   B3,1,B3
304 ||	   SHL	   .S1	   A0,8,A1
305 L21:
306 #endif
307 	   SHR	   .S2	   B3,1,B0
308    [!B0]   BNOP    .S1	   L24,3
309 	   MVK	   .L1	   2,A0
310 	   AND	   .L1	   A4,A0,A0
311 
312    [!A0]   BNOP    .S1	   L22,5
313 || [A0]    LDHU    .D1T1   *A4++,A0
314 	   SUB	   .L2	   B0,1,B0
315 ||	   SUB	   .S2	   B3,2,B3
316 ||	   ADD	   .L1	   A0,A1,A1
317 L22:
318 	   SHR	   .S2	   B0,1,B0
319 ||	   ZERO    .L1	   A0
320 
321    [!B0]   BNOP    .S1	   L23,5
322 || [B0]    MVC	   .S2	   B0,ILC
323 
324 	   SPLOOP  3
325 	   SPMASK  L1
326 ||	   MV	   .L1	   A1,A2
327 ||	   LDW	   .D1T1   *A4++,A1
328 
329 	   NOP	   4
330 	   ADD	   .L1	   A0,A1,A0
331 	   ADD	   .L1	   A2,A0,A2
332 
333 	   SPKERNEL 1,2
334 ||	   CMPGTU  .L1	   A1,A2,A0
335 
336 	   ADD	   .L1	   A0,A2,A6
337 	   EXTU    .S1	   A6,16,16,A7
338 	   SHRU    .S2X    A6,16,B0
339 	   NOP		   1
340 	   ADD	   .L1X    A7,B0,A1
341 L23:
342 	   MVK	   .L2	   2,B0
343 	   AND	   .L2	   B3,B0,B0
344    [B0]    LDHU    .D1T1   *A4++,A0
345 	   NOP	   4
346    [B0]    ADD	   .L1	   A0,A1,A1
347 L24:
348 	   EXTU    .S2	   B3,31,31,B0
349 #ifdef CONFIG_CPU_BIG_ENDIAN
350    [!B0]   BNOP    .S1	   L25,4
351 || [B0]    LDBU    .D1T1   *A4,A0
352 	   SHL	   .S1	   A0,8,A0
353 	   ADD	   .L1	   A0,A1,A1
354 L25:
355 #else
356    [B0]    LDBU    .D1T1   *A4,A0
357 	   NOP	   4
358    [B0]    ADD	   .L1	   A0,A1,A1
359 #endif
360 	   EXTU    .S1	   A1,16,16,A0
361 	   SHRU    .S2X    A1,16,B0
362 	   NOP	   1
363 	   ADD	   .L1X    A0,B0,A0
364 	   SHRU    .S1	   A0,16,A1
365 	   ADD	   .L1	   A0,A1,A0
366 	   EXTU    .S1	   A0,16,16,A1
367 	   EXTU    .S1	   A1,16,24,A2
368 
369 	   EXTU    .S1	   A1,24,16,A0
370 ||	   MV	   .L2X    A3,B0
371 
372    [B0]    OR	   .L1	   A0,A2,A1
373 L26:
374 	   NOP	   1
375 	   BNOP    .S2X    A5,4
376 	   MV	   .L1	   A1,A4
377 ENDPROC(do_csum)
378 
379 ;__wsum csum_partial(const void *buff, int len, __wsum wsum)
380 ;{
381 ;	unsigned int sum = (__force unsigned int)wsum;
382 ;	unsigned int result = do_csum(buff, len);
383 ;
384 ;	/* add in old sum, and carry.. */
385 ;	result += sum;
386 ;	if (sum > result)
387 ;		result += 1;
388 ;	return (__force __wsum)result;
389 ;}
390 ;
391 ENTRY(csum_partial)
392 	   MV	   .L1X    B3,A9
393 ||	   CALLP   .S2	   do_csum,B3
394 ||	   MV	   .S1	   A6,A8
395 	   BNOP    .S2X    A9,2
396 	   ADD	   .L1	   A8,A4,A1
397 	   CMPGTU  .L1	   A8,A1,A0
398 	   ADD	   .L1	   A1,A0,A4
399 ENDPROC(csum_partial)
400 
401 ;unsigned short
402 ;ip_compute_csum(unsigned char *buff, unsigned int len)
403 ;
404 ; A4:	buff
405 ; B4:	len
406 ; return checksum in A4
407 
408 ENTRY(ip_compute_csum)
409 	   MV	   .L1X    B3,A9
410 ||	   CALLP   .S2	   do_csum,B3
411 	   BNOP    .S2X    A9,3
412 	   NOT	   .S1	   A4,A4
413 	   CLR     .S1	   A4,16,31,A4
414 ENDPROC(ip_compute_csum)
415