checksum.h 5.7 KB

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