2 * Compute 16-bit sum in ones' complement arithmetic (with end-around carry).
3 * This sum is often used as a simple checksum in networking.
5 * Copyright (c) 2020, Arm Limited.
6 * SPDX-License-Identifier: MIT
9 #include "networking.h"
10 #include "chksum_common.h"
13 static inline uint32_t
14 slurp_head32(const void **pptr, uint32_t *nbytes)
18 uint32_t off = (uintptr_t) *pptr % 4;
21 /* Get rid of bytes 0..off-1 */
22 const unsigned char *ptr32 = align_ptr(*pptr, 4);
23 uint32_t mask = ~0U << (CHAR_BIT * off);
24 sum = load32(ptr32) & mask;
31 /* Additional loop unrolling would help when not auto-vectorizing */
33 __chksum(const void *ptr, unsigned int nbytes)
40 /* 4-byte align pointer */
41 swap = (uintptr_t) ptr & 1;
42 sum = slurp_head32(&ptr, &nbytes);
44 /* Else benefit of aligning not worth the overhead */
46 /* Sum all 16-byte chunks */
47 const char *cptr = ptr;
48 for (uint32_t nquads = nbytes / 16; nquads != 0; nquads--)
50 uint64_t h0 = load32(cptr + 0);
51 uint64_t h1 = load32(cptr + 4);
52 uint64_t h2 = load32(cptr + 8);
53 uint64_t h3 = load32(cptr + 12);
54 sum += h0 + h1 + h2 + h3;
60 /* Handle any trailing 4-byte chunks */
77 sum += *(uint8_t *)cptr;
80 return fold_and_swap(sum, swap);