csum-partial_64.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * arch/x86_64/lib/csum-partial.c
  4. *
  5. * This file contains network checksum routines that are better done
  6. * in an architecture-specific manner due to speed.
  7. */
  8. #include <linux/compiler.h>
  9. #include <linux/export.h>
  10. #include <asm/checksum.h>
  11. #include <asm/word-at-a-time.h>
  12. static inline __wsum csum_finalize_sum(u64 temp64)
  13. {
  14. return (__force __wsum)((temp64 + ror64(temp64, 32)) >> 32);
  15. }
  16. static inline unsigned long update_csum_40b(unsigned long sum, const unsigned long m[5])
  17. {
  18. asm("addq %1,%0\n\t"
  19. "adcq %2,%0\n\t"
  20. "adcq %3,%0\n\t"
  21. "adcq %4,%0\n\t"
  22. "adcq %5,%0\n\t"
  23. "adcq $0,%0"
  24. :"+r" (sum)
  25. :"m" (m[0]), "m" (m[1]), "m" (m[2]),
  26. "m" (m[3]), "m" (m[4]));
  27. return sum;
  28. }
  29. /*
  30. * Do a checksum on an arbitrary memory area.
  31. * Returns a 32bit checksum.
  32. *
  33. * This isn't as time critical as it used to be because many NICs
  34. * do hardware checksumming these days.
  35. *
  36. * Still, with CHECKSUM_COMPLETE this is called to compute
  37. * checksums on IPv6 headers (40 bytes) and other small parts.
  38. * it's best to have buff aligned on a 64-bit boundary
  39. */
  40. __wsum csum_partial(const void *buff, int len, __wsum sum)
  41. {
  42. u64 temp64 = (__force u64)sum;
  43. /* Do two 40-byte chunks in parallel to get better ILP */
  44. if (likely(len >= 80)) {
  45. u64 temp64_2 = 0;
  46. do {
  47. temp64 = update_csum_40b(temp64, buff);
  48. temp64_2 = update_csum_40b(temp64_2, buff + 40);
  49. buff += 80;
  50. len -= 80;
  51. } while (len >= 80);
  52. asm("addq %1,%0\n\t"
  53. "adcq $0,%0"
  54. :"+r" (temp64): "r" (temp64_2));
  55. }
  56. /*
  57. * len == 40 is the hot case due to IPv6 headers, so return
  58. * early for that exact case without checking the tail bytes.
  59. */
  60. if (len >= 40) {
  61. temp64 = update_csum_40b(temp64, buff);
  62. len -= 40;
  63. if (!len)
  64. return csum_finalize_sum(temp64);
  65. buff += 40;
  66. }
  67. if (len & 32) {
  68. asm("addq 0*8(%[src]),%[res]\n\t"
  69. "adcq 1*8(%[src]),%[res]\n\t"
  70. "adcq 2*8(%[src]),%[res]\n\t"
  71. "adcq 3*8(%[src]),%[res]\n\t"
  72. "adcq $0,%[res]"
  73. : [res] "+r"(temp64)
  74. : [src] "r"(buff), "m"(*(const char(*)[32])buff));
  75. buff += 32;
  76. }
  77. if (len & 16) {
  78. asm("addq 0*8(%[src]),%[res]\n\t"
  79. "adcq 1*8(%[src]),%[res]\n\t"
  80. "adcq $0,%[res]"
  81. : [res] "+r"(temp64)
  82. : [src] "r"(buff), "m"(*(const char(*)[16])buff));
  83. buff += 16;
  84. }
  85. if (len & 8) {
  86. asm("addq 0*8(%[src]),%[res]\n\t"
  87. "adcq $0,%[res]"
  88. : [res] "+r"(temp64)
  89. : [src] "r"(buff), "m"(*(const char(*)[8])buff));
  90. buff += 8;
  91. }
  92. if (len & 7) {
  93. unsigned int shift = (-len << 3) & 63;
  94. unsigned long trail;
  95. trail = (load_unaligned_zeropad(buff) << shift) >> shift;
  96. asm("addq %[trail],%[res]\n\t"
  97. "adcq $0,%[res]"
  98. : [res] "+r"(temp64)
  99. : [trail] "r"(trail));
  100. }
  101. return csum_finalize_sum(temp64);
  102. }
  103. EXPORT_SYMBOL(csum_partial);
  104. /*
  105. * this routine is used for miscellaneous IP-like checksums, mainly
  106. * in icmp.c
  107. */
  108. __sum16 ip_compute_csum(const void *buff, int len)
  109. {
  110. return csum_fold(csum_partial(buff, len, 0));
  111. }
  112. EXPORT_SYMBOL(ip_compute_csum);