checksum.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #ifndef _PARISC_CHECKSUM_H
  2. #define _PARISC_CHECKSUM_H
  3. #include <linux/in6.h>
  4. /*
  5. * computes the checksum of a memory block at buff, length len,
  6. * and adds in "sum" (32-bit)
  7. *
  8. * returns a 32-bit number suitable for feeding into itself
  9. * or csum_tcpudp_magic
  10. *
  11. * this function must be called with even lengths, except
  12. * for the last fragment, which may be odd
  13. *
  14. * it's best to have buff aligned on a 32-bit boundary
  15. */
  16. extern __wsum csum_partial(const void *, int, __wsum);
  17. /*
  18. * The same as csum_partial, but copies from src while it checksums.
  19. *
  20. * Here even more important to align src and dst on a 32-bit (or even
  21. * better 64-bit) boundary
  22. */
  23. extern __wsum csum_partial_copy_nocheck(const void *, void *, int, __wsum);
  24. /*
  25. * this is a new version of the above that records errors it finds in *errp,
  26. * but continues and zeros the rest of the buffer.
  27. */
  28. extern __wsum csum_partial_copy_from_user(const void __user *src,
  29. void *dst, int len, __wsum sum, int *errp);
  30. /*
  31. * Optimized for IP headers, which always checksum on 4 octet boundaries.
  32. *
  33. * Written by Randolph Chung <tausq@debian.org>, and then mucked with by
  34. * LaMont Jones <lamont@debian.org>
  35. */
  36. static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
  37. {
  38. unsigned int sum;
  39. __asm__ __volatile__ (
  40. " ldws,ma 4(%1), %0\n"
  41. " addib,<= -4, %2, 2f\n"
  42. "\n"
  43. " ldws 4(%1), %%r20\n"
  44. " ldws 8(%1), %%r21\n"
  45. " add %0, %%r20, %0\n"
  46. " ldws,ma 12(%1), %%r19\n"
  47. " addc %0, %%r21, %0\n"
  48. " addc %0, %%r19, %0\n"
  49. "1: ldws,ma 4(%1), %%r19\n"
  50. " addib,< 0, %2, 1b\n"
  51. " addc %0, %%r19, %0\n"
  52. "\n"
  53. " extru %0, 31, 16, %%r20\n"
  54. " extru %0, 15, 16, %%r21\n"
  55. " addc %%r20, %%r21, %0\n"
  56. " extru %0, 15, 16, %%r21\n"
  57. " add %0, %%r21, %0\n"
  58. " subi -1, %0, %0\n"
  59. "2:\n"
  60. : "=r" (sum), "=r" (iph), "=r" (ihl)
  61. : "1" (iph), "2" (ihl)
  62. : "r19", "r20", "r21", "memory");
  63. return (__force __sum16)sum;
  64. }
  65. /*
  66. * Fold a partial checksum
  67. */
  68. static inline __sum16 csum_fold(__wsum csum)
  69. {
  70. u32 sum = (__force u32)csum;
  71. /* add the swapped two 16-bit halves of sum,
  72. a possible carry from adding the two 16-bit halves,
  73. will carry from the lower half into the upper half,
  74. giving us the correct sum in the upper half. */
  75. sum += (sum << 16) + (sum >> 16);
  76. return (__force __sum16)(~sum >> 16);
  77. }
  78. static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
  79. unsigned short len,
  80. unsigned short proto,
  81. __wsum sum)
  82. {
  83. __asm__(
  84. " add %1, %0, %0\n"
  85. " addc %2, %0, %0\n"
  86. " addc %3, %0, %0\n"
  87. " addc %%r0, %0, %0\n"
  88. : "=r" (sum)
  89. : "r" (daddr), "r"(saddr), "r"(proto+len), "0"(sum));
  90. return sum;
  91. }
  92. /*
  93. * computes the checksum of the TCP/UDP pseudo-header
  94. * returns a 16-bit checksum, already complemented
  95. */
  96. static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
  97. unsigned short len,
  98. unsigned short proto,
  99. __wsum sum)
  100. {
  101. return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
  102. }
  103. /*
  104. * this routine is used for miscellaneous IP-like checksums, mainly
  105. * in icmp.c
  106. */
  107. static inline __sum16 ip_compute_csum(const void *buf, int len)
  108. {
  109. return csum_fold (csum_partial(buf, len, 0));
  110. }
  111. #define _HAVE_ARCH_IPV6_CSUM
  112. static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  113. const struct in6_addr *daddr,
  114. __u32 len, unsigned short proto,
  115. __wsum sum)
  116. {
  117. __asm__ __volatile__ (
  118. #if BITS_PER_LONG > 32
  119. /*
  120. ** We can execute two loads and two adds per cycle on PA 8000.
  121. ** But add insn's get serialized waiting for the carry bit.
  122. ** Try to keep 4 registers with "live" values ahead of the ALU.
  123. */
  124. " ldd,ma 8(%1), %%r19\n" /* get 1st saddr word */
  125. " ldd,ma 8(%2), %%r20\n" /* get 1st daddr word */
  126. " add %8, %3, %3\n"/* add 16-bit proto + len */
  127. " add %%r19, %0, %0\n"
  128. " ldd,ma 8(%1), %%r21\n" /* 2cd saddr */
  129. " ldd,ma 8(%2), %%r22\n" /* 2cd daddr */
  130. " add,dc %%r20, %0, %0\n"
  131. " add,dc %%r21, %0, %0\n"
  132. " add,dc %%r22, %0, %0\n"
  133. " add,dc %3, %0, %0\n" /* fold in proto+len | carry bit */
  134. " extrd,u %0, 31, 32, %%r19\n" /* copy upper half down */
  135. " depdi 0, 31, 32, %0\n" /* clear upper half */
  136. " add %%r19, %0, %0\n" /* fold into 32-bits */
  137. " addc 0, %0, %0\n" /* add carry */
  138. #else
  139. /*
  140. ** For PA 1.x, the insn order doesn't matter as much.
  141. ** Insn stream is serialized on the carry bit here too.
  142. ** result from the previous operation (eg r0 + x)
  143. */
  144. " ldw,ma 4(%1), %%r19\n" /* get 1st saddr word */
  145. " ldw,ma 4(%2), %%r20\n" /* get 1st daddr word */
  146. " add %8, %3, %3\n" /* add 16-bit proto + len */
  147. " add %%r19, %0, %0\n"
  148. " ldw,ma 4(%1), %%r21\n" /* 2cd saddr */
  149. " addc %%r20, %0, %0\n"
  150. " ldw,ma 4(%2), %%r22\n" /* 2cd daddr */
  151. " addc %%r21, %0, %0\n"
  152. " ldw,ma 4(%1), %%r19\n" /* 3rd saddr */
  153. " addc %%r22, %0, %0\n"
  154. " ldw,ma 4(%2), %%r20\n" /* 3rd daddr */
  155. " addc %%r19, %0, %0\n"
  156. " ldw,ma 4(%1), %%r21\n" /* 4th saddr */
  157. " addc %%r20, %0, %0\n"
  158. " ldw,ma 4(%2), %%r22\n" /* 4th daddr */
  159. " addc %%r21, %0, %0\n"
  160. " addc %%r22, %0, %0\n"
  161. " addc %3, %0, %0\n" /* fold in proto+len, catch carry */
  162. #endif
  163. : "=r" (sum), "=r" (saddr), "=r" (daddr), "=r" (len)
  164. : "0" (sum), "1" (saddr), "2" (daddr), "3" (len), "r" (proto)
  165. : "r19", "r20", "r21", "r22", "memory");
  166. return csum_fold(sum);
  167. }
  168. /*
  169. * Copy and checksum to user
  170. */
  171. #define HAVE_CSUM_COPY_USER
  172. static __inline__ __wsum csum_and_copy_to_user(const void *src,
  173. void __user *dst,
  174. int len, __wsum sum,
  175. int *err_ptr)
  176. {
  177. /* code stolen from include/asm-mips64 */
  178. sum = csum_partial(src, len, sum);
  179. if (copy_to_user(dst, src, len)) {
  180. *err_ptr = -EFAULT;
  181. return (__force __wsum)-1;
  182. }
  183. return sum;
  184. }
  185. #endif