mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-05-24 10:39:52 +00:00
64 lines
1.4 KiB
C
64 lines
1.4 KiB
C
![]() |
// 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 buff, length len,
|
||
|
* and adds in "sum" (32-bit).
|
||
|
*
|
||
|
* 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 buff aligned on a 64-bit boundary.
|
||
|
*/
|
||
|
__wsum csum_partial(const void *buff, int len, __wsum sum)
|
||
|
{
|
||
|
DECLARE_KERNEL_FPU_ONSTACK8(vxstate);
|
||
|
|
||
|
if (!cpu_has_vx())
|
||
|
return cksm(buff, 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, buff);
|
||
|
fpu_vcksm(16, 20, 16);
|
||
|
fpu_vcksm(17, 21, 17);
|
||
|
fpu_vcksm(18, 22, 18);
|
||
|
fpu_vcksm(19, 23, 19);
|
||
|
buff += 64;
|
||
|
len -= 64;
|
||
|
}
|
||
|
while (len >= 32) {
|
||
|
fpu_vlm(20, 21, buff);
|
||
|
fpu_vcksm(16, 20, 16);
|
||
|
fpu_vcksm(17, 21, 17);
|
||
|
buff += 32;
|
||
|
len -= 32;
|
||
|
}
|
||
|
while (len >= 16) {
|
||
|
fpu_vl(20, buff);
|
||
|
fpu_vcksm(16, 20, 16);
|
||
|
buff += 16;
|
||
|
len -= 16;
|
||
|
}
|
||
|
if (len) {
|
||
|
fpu_vll(20, len - 1, buff);
|
||
|
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;
|
||
|
}
|
||
|
EXPORT_SYMBOL(csum_partial);
|