csum-partial.c 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/export.h>
  3. #include <asm/checksum.h>
  4. #include <asm/fpu.h>
  5. /*
  6. * Computes the checksum of a memory block at src, length len,
  7. * and adds in "sum" (32-bit). If copy is true copies to dst.
  8. *
  9. * Returns a 32-bit number suitable for feeding into itself
  10. * or csum_tcpudp_magic.
  11. *
  12. * This function must be called with even lengths, except
  13. * for the last fragment, which may be odd.
  14. *
  15. * It's best to have src and dst aligned on a 64-bit boundary.
  16. */
  17. static __always_inline __wsum csum_copy(void *dst, const void *src, int len, __wsum sum, bool copy)
  18. {
  19. DECLARE_KERNEL_FPU_ONSTACK8(vxstate);
  20. if (!cpu_has_vx()) {
  21. if (copy)
  22. memcpy(dst, src, len);
  23. return cksm(dst, len, sum);
  24. }
  25. kernel_fpu_begin(&vxstate, KERNEL_VXR_V16V23);
  26. fpu_vlvgf(16, (__force u32)sum, 1);
  27. fpu_vzero(17);
  28. fpu_vzero(18);
  29. fpu_vzero(19);
  30. while (len >= 64) {
  31. fpu_vlm(20, 23, src);
  32. if (copy) {
  33. fpu_vstm(20, 23, dst);
  34. dst += 64;
  35. }
  36. fpu_vcksm(16, 20, 16);
  37. fpu_vcksm(17, 21, 17);
  38. fpu_vcksm(18, 22, 18);
  39. fpu_vcksm(19, 23, 19);
  40. src += 64;
  41. len -= 64;
  42. }
  43. while (len >= 32) {
  44. fpu_vlm(20, 21, src);
  45. if (copy) {
  46. fpu_vstm(20, 21, dst);
  47. dst += 32;
  48. }
  49. fpu_vcksm(16, 20, 16);
  50. fpu_vcksm(17, 21, 17);
  51. src += 32;
  52. len -= 32;
  53. }
  54. while (len >= 16) {
  55. fpu_vl(20, src);
  56. if (copy) {
  57. fpu_vst(20, dst);
  58. dst += 16;
  59. }
  60. fpu_vcksm(16, 20, 16);
  61. src += 16;
  62. len -= 16;
  63. }
  64. if (len) {
  65. fpu_vll(20, len - 1, src);
  66. if (copy)
  67. fpu_vstl(20, len - 1, dst);
  68. fpu_vcksm(16, 20, 16);
  69. }
  70. fpu_vcksm(18, 19, 18);
  71. fpu_vcksm(16, 17, 16);
  72. fpu_vcksm(16, 18, 16);
  73. sum = (__force __wsum)fpu_vlgvf(16, 1);
  74. kernel_fpu_end(&vxstate, KERNEL_VXR_V16V23);
  75. return sum;
  76. }
  77. __wsum csum_partial(const void *buff, int len, __wsum sum)
  78. {
  79. return csum_copy(NULL, buff, len, sum, false);
  80. }
  81. EXPORT_SYMBOL(csum_partial);
  82. __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
  83. {
  84. return csum_copy(dst, src, len, 0, true);
  85. }
  86. EXPORT_SYMBOL(csum_partial_copy_nocheck);