Blame view
include/asm-s390/checksum.h
4.11 KB
1da177e4c
|
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 |
#ifndef _S390_CHECKSUM_H #define _S390_CHECKSUM_H /* * include/asm-s390/checksum.h * S390 fast network checksum routines * see also arch/S390/lib/checksum.c * * S390 version * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Ulrich Hild (first version) * Martin Schwidefsky (heavily optimized CKSM version) * D.J. Barrow (third attempt) */ #include <asm/uaccess.h> /* * computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) * * returns a 32-bit number suitable for feeding into itself * or csum_tcpudp_magic * * this function must be called with even lengths, except * for the last fragment, which may be odd * * it's best to have buff aligned on a 32-bit boundary */ |
f994aae1b
|
30 31 |
static inline __wsum csum_partial(const void *buff, int len, __wsum sum) |
1da177e4c
|
32 |
{ |
94c12cc7d
|
33 34 |
register unsigned long reg2 asm("2") = (unsigned long) buff; register unsigned long reg3 asm("3") = (unsigned long) len; |
1da177e4c
|
35 |
|
94c12cc7d
|
36 37 38 39 40 41 |
asm volatile( "0: cksm %0,%1 " /* do checksum on longs */ " jo 0b " : "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory"); |
1da177e4c
|
42 43 44 45 46 47 48 49 50 51 52 53 |
return sum; } /* * the same as csum_partial_copy, but copies from user space. * * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary * * Copy from userspace and compute checksum. If we catch an exception * then zero the rest of the buffer. */ |
f994aae1b
|
54 55 56 |
static inline __wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, |
1da177e4c
|
57 58 59 60 61 62 63 64 65 66 67 68 |
int *err_ptr) { int missing; missing = copy_from_user(dst, src, len); if (missing) { memset(dst + len - missing, 0, missing); *err_ptr = -EFAULT; } return csum_partial(dst, len, sum); } |
f994aae1b
|
69 70 |
static inline __wsum csum_partial_copy_nocheck (const void *src, void *dst, int len, __wsum sum) |
1da177e4c
|
71 72 |
{ memcpy(dst,src,len); |
94c12cc7d
|
73 |
return csum_partial(dst, len, sum); |
1da177e4c
|
74 75 76 77 78 |
} /* * Fold a partial checksum without adding pseudo headers */ |
f994aae1b
|
79 |
static inline __sum16 csum_fold(__wsum sum) |
1da177e4c
|
80 81 82 |
{ #ifndef __s390x__ register_pair rp; |
94c12cc7d
|
83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
asm volatile( " slr %N1,%N1 " /* %0 = H L */ " lr %1,%0 " /* %0 = H L, %1 = H L 0 0 */ " srdl %1,16 " /* %0 = H L, %1 = 0 H L 0 */ " alr %1,%N1 " /* %0 = H L, %1 = L H L 0 */ " alr %0,%1 " /* %0 = H+L+C L+H */ " srl %0,16 " /* %0 = H+L+C */ : "+&d" (sum), "=d" (rp) : : "cc"); |
1da177e4c
|
97 |
#else /* __s390x__ */ |
94c12cc7d
|
98 99 100 101 102 103 104 105 106 107 108 109 110 |
asm volatile( " sr 3,3 " /* %0 = H*65536 + L */ " lr 2,%0 " /* %0 = H L, 2/3 = H L / 0 0 */ " srdl 2,16 " /* %0 = H L, 2/3 = 0 H / L 0 */ " alr 2,3 " /* %0 = H L, 2/3 = L H / L 0 */ " alr %0,2 " /* %0 = H+L+C L+H */ " srl %0,16 " /* %0 = H+L+C */ |
1da177e4c
|
111 112 |
: "+&d" (sum) : : "cc", "2", "3"); #endif /* __s390x__ */ |
f994aae1b
|
113 |
return (__force __sum16) ~sum; |
1da177e4c
|
114 115 116 117 118 119 120 |
} /* * This is a version of ip_compute_csum() optimized for IP headers, * which always checksum on 4 octet boundaries. * */ |
f994aae1b
|
121 |
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) |
1da177e4c
|
122 |
{ |
94c12cc7d
|
123 |
return csum_fold(csum_partial(iph, ihl*4, 0)); |
1da177e4c
|
124 125 126 127 128 129 |
} /* * computes the checksum of the TCP/UDP pseudo-header * returns a 32-bit checksum */ |
f994aae1b
|
130 131 |
static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, |
1da177e4c
|
132 |
unsigned short len, unsigned short proto, |
f994aae1b
|
133 |
__wsum sum) |
1da177e4c
|
134 |
{ |
afbc1e994
|
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
__u32 csum = (__force __u32)sum; csum += (__force __u32)saddr; if (csum < (__force __u32)saddr) csum++; csum += (__force __u32)daddr; if (csum < (__force __u32)daddr) csum++; csum += len + proto; if (csum < len + proto) csum++; return (__force __wsum)csum; |
1da177e4c
|
150 151 152 153 154 155 |
} /* * computes the checksum of the TCP/UDP pseudo-header * returns a 16-bit checksum, already complemented */ |
f994aae1b
|
156 157 |
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, |
1da177e4c
|
158 |
unsigned short len, unsigned short proto, |
f994aae1b
|
159 |
__wsum sum) |
1da177e4c
|
160 161 162 163 164 165 166 167 |
{ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); } /* * this routine is used for miscellaneous IP-like checksums, mainly * in icmp.c */ |
f994aae1b
|
168 |
static inline __sum16 ip_compute_csum(const void *buff, int len) |
1da177e4c
|
169 170 171 172 173 |
{ return csum_fold(csum_partial(buff, len, 0)); } #endif /* _S390_CHECKSUM_H */ |