1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
| /* SPDX-License-Identifier: GPL-2.0-only */
| /*
| * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
| *
| * Joern Rennecke <joern.rennecke@embecosm.com>: Jan 2012
| * -Insn Scheduling improvements to csum core routines.
| * = csum_fold( ) largely derived from ARM version.
| * = ip_fast_cum( ) to have module scheduling
| * -gcc 4.4.x broke networking. Alias analysis needed to be primed.
| * worked around by adding memory clobber to ip_fast_csum( )
| *
| * vineetg: May 2010
| * -Rewrote ip_fast_cscum( ) and csum_fold( ) with fast inline asm
| */
|
| #ifndef _ASM_ARC_CHECKSUM_H
| #define _ASM_ARC_CHECKSUM_H
|
| /*
| * Fold a partial checksum
| *
| * The 2 swords comprising the 32bit sum are added, any carry to 16th bit
| * added back and final sword result inverted.
| */
| static inline __sum16 csum_fold(__wsum s)
| {
| unsigned r = s << 16 | s >> 16; /* ror */
| s = ~s;
| s -= r;
| return s >> 16;
| }
|
| /*
| * This is a version of ip_compute_csum() optimized for IP headers,
| * which always checksum on 4 octet boundaries.
| */
| static inline __sum16
| ip_fast_csum(const void *iph, unsigned int ihl)
| {
| const void *ptr = iph;
| unsigned int tmp, tmp2, sum;
|
| __asm__(
| " ld.ab %0, [%3, 4] \n"
| " ld.ab %2, [%3, 4] \n"
| " sub %1, %4, 2 \n"
| " lsr.f lp_count, %1, 1 \n"
| " bcc 0f \n"
| " add.f %0, %0, %2 \n"
| " ld.ab %2, [%3, 4] \n"
| "0: lp 1f \n"
| " ld.ab %1, [%3, 4] \n"
| " adc.f %0, %0, %2 \n"
| " ld.ab %2, [%3, 4] \n"
| " adc.f %0, %0, %1 \n"
| "1: adc.f %0, %0, %2 \n"
| " add.cs %0,%0,1 \n"
| : "=&r"(sum), "=r"(tmp), "=&r"(tmp2), "+&r" (ptr)
| : "r"(ihl)
| : "cc", "lp_count", "memory");
|
| return csum_fold(sum);
| }
|
| /*
| * TCP pseudo Header is 12 bytes:
| * SA [4], DA [4], zeroes [1], Proto[1], TCP Seg(hdr+data) Len [2]
| */
| static inline __wsum
| csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
| __u8 proto, __wsum sum)
| {
| __asm__ __volatile__(
| " add.f %0, %0, %1 \n"
| " adc.f %0, %0, %2 \n"
| " adc.f %0, %0, %3 \n"
| " adc.f %0, %0, %4 \n"
| " adc %0, %0, 0 \n"
| : "+&r"(sum)
| : "r"(saddr), "r"(daddr),
| #ifdef CONFIG_CPU_BIG_ENDIAN
| "r"(len),
| #else
| "r"(len << 8),
| #endif
| "r"(htons(proto))
| : "cc");
|
| return sum;
| }
|
| #define csum_fold csum_fold
| #define ip_fast_csum ip_fast_csum
| #define csum_tcpudp_nofold csum_tcpudp_nofold
|
| #include <asm-generic/checksum.h>
|
| #endif /* _ASM_ARC_CHECKSUM_H */
|
|