| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- // SPDX-License-Identifier: GPL-2.0
- #include <linux/export.h>
- #include <asm/checksum.h>
- #include <asm/fpu.h>
- /*
- * Computes the checksum of a memory block at src, length len,
- * and adds in "sum" (32-bit). If copy is true copies to dst.
- *
- * 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 src and dst aligned on a 64-bit boundary.
- */
- static __always_inline __wsum csum_copy(void *dst, const void *src, int len, __wsum sum, bool copy)
- {
- DECLARE_KERNEL_FPU_ONSTACK8(vxstate);
- if (!cpu_has_vx()) {
- if (copy)
- memcpy(dst, src, len);
- return cksm(dst, len, sum);
- }
- kernel_fpu_begin(&vxstate, KERNEL_VXR_V16V23);
- fpu_vlvgf(16, (__force u32)sum, 1);
- fpu_vzero(17);
- fpu_vzero(18);
- fpu_vzero(19);
- while (len >= 64) {
- fpu_vlm(20, 23, src);
- if (copy) {
- fpu_vstm(20, 23, dst);
- dst += 64;
- }
- fpu_vcksm(16, 20, 16);
- fpu_vcksm(17, 21, 17);
- fpu_vcksm(18, 22, 18);
- fpu_vcksm(19, 23, 19);
- src += 64;
- len -= 64;
- }
- while (len >= 32) {
- fpu_vlm(20, 21, src);
- if (copy) {
- fpu_vstm(20, 21, dst);
- dst += 32;
- }
- fpu_vcksm(16, 20, 16);
- fpu_vcksm(17, 21, 17);
- src += 32;
- len -= 32;
- }
- while (len >= 16) {
- fpu_vl(20, src);
- if (copy) {
- fpu_vst(20, dst);
- dst += 16;
- }
- fpu_vcksm(16, 20, 16);
- src += 16;
- len -= 16;
- }
- if (len) {
- fpu_vll(20, len - 1, src);
- if (copy)
- fpu_vstl(20, len - 1, dst);
- fpu_vcksm(16, 20, 16);
- }
- fpu_vcksm(18, 19, 18);
- fpu_vcksm(16, 17, 16);
- fpu_vcksm(16, 18, 16);
- sum = (__force __wsum)fpu_vlgvf(16, 1);
- kernel_fpu_end(&vxstate, KERNEL_VXR_V16V23);
- return sum;
- }
- __wsum csum_partial(const void *buff, int len, __wsum sum)
- {
- return csum_copy(NULL, buff, len, sum, false);
- }
- EXPORT_SYMBOL(csum_partial);
- __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
- {
- return csum_copy(dst, src, len, 0, true);
- }
- EXPORT_SYMBOL(csum_partial_copy_nocheck);
|