xref: /freebsd-src/contrib/arm-optimized-routines/networking/chksum_common.h (revision 072a4ba82a01476eaee33781ccd241033eefcf0b)
131914882SAlex Richardson /*
231914882SAlex Richardson  * Common code for checksum implementations
331914882SAlex Richardson  *
431914882SAlex Richardson  * Copyright (c) 2020, Arm Limited.
5*072a4ba8SAndrew Turner  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
631914882SAlex Richardson  */
731914882SAlex Richardson 
831914882SAlex Richardson #ifndef CHKSUM_COMMON_H
931914882SAlex Richardson #define CHKSUM_COMMON_H
1031914882SAlex Richardson 
1131914882SAlex Richardson #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
1231914882SAlex Richardson #error Only little endian supported
1331914882SAlex Richardson #endif
1431914882SAlex Richardson 
1531914882SAlex Richardson #include <limits.h>
1631914882SAlex Richardson #include <stdbool.h>
1731914882SAlex Richardson #include <stdint.h>
1831914882SAlex Richardson #include <string.h>
1931914882SAlex Richardson 
2031914882SAlex Richardson /* Assertions must be explicitly enabled */
2131914882SAlex Richardson #if WANT_ASSERT
2231914882SAlex Richardson #undef NDEBUG
2331914882SAlex Richardson #include <assert.h>
2431914882SAlex Richardson #define Assert(exp) assert(exp)
2531914882SAlex Richardson #else
2631914882SAlex Richardson #define Assert(exp) (void) (exp)
2731914882SAlex Richardson #endif
2831914882SAlex Richardson 
2931914882SAlex Richardson #ifdef __GNUC__
3031914882SAlex Richardson #define likely(x)     __builtin_expect(!!(x), 1)
3131914882SAlex Richardson #define unlikely(x)   __builtin_expect(!!(x), 0)
3231914882SAlex Richardson #define may_alias     __attribute__((__may_alias__))
3331914882SAlex Richardson #define always_inline __attribute__((always_inline))
3431914882SAlex Richardson #ifdef __clang__
3531914882SAlex Richardson #define no_unroll_loops
3631914882SAlex Richardson #else
3731914882SAlex Richardson #define no_unroll_loops  __attribute__((optimize("no-unroll-loops")))
3831914882SAlex Richardson #endif
3931914882SAlex Richardson #define bswap16(x)    __builtin_bswap16((x))
4031914882SAlex Richardson #else
4131914882SAlex Richardson #define likely(x)     (x)
4231914882SAlex Richardson #define unlikely(x)   (x)
4331914882SAlex Richardson #define may_alias
4431914882SAlex Richardson #define always_inline
4531914882SAlex Richardson #define no_unroll_loops
4631914882SAlex Richardson #define bswap16(x)    ((uint8_t)((x) >> 8) | ((uint8_t)(x) << 8))
4731914882SAlex Richardson #endif
4831914882SAlex Richardson 
4931914882SAlex Richardson #define ALL_ONES ~UINT64_C(0)
5031914882SAlex Richardson 
5131914882SAlex Richardson static inline
load64(const void * ptr)5231914882SAlex Richardson uint64_t load64(const void *ptr)
5331914882SAlex Richardson {
5431914882SAlex Richardson     /* GCC will optimise this to a normal load instruction */
5531914882SAlex Richardson     uint64_t v;
5631914882SAlex Richardson     memcpy(&v, ptr, sizeof v);
5731914882SAlex Richardson     return v;
5831914882SAlex Richardson }
5931914882SAlex Richardson 
6031914882SAlex Richardson static inline
load32(const void * ptr)6131914882SAlex Richardson uint32_t load32(const void *ptr)
6231914882SAlex Richardson {
6331914882SAlex Richardson     /* GCC will optimise this to a normal load instruction */
6431914882SAlex Richardson     uint32_t v;
6531914882SAlex Richardson     memcpy(&v, ptr, sizeof v);
6631914882SAlex Richardson     return v;
6731914882SAlex Richardson }
6831914882SAlex Richardson 
6931914882SAlex Richardson static inline
load16(const void * ptr)7031914882SAlex Richardson uint16_t load16(const void *ptr)
7131914882SAlex Richardson {
7231914882SAlex Richardson     /* GCC will optimise this to a normal load instruction */
7331914882SAlex Richardson     uint16_t v;
7431914882SAlex Richardson     memcpy(&v, ptr, sizeof v);
7531914882SAlex Richardson     return v;
7631914882SAlex Richardson }
7731914882SAlex Richardson 
7831914882SAlex Richardson /* slurp_small() is for small buffers, don't waste cycles on alignment */
7931914882SAlex Richardson no_unroll_loops
8031914882SAlex Richardson always_inline
8131914882SAlex Richardson static inline uint64_t
slurp_small(const void * ptr,uint32_t nbytes)8231914882SAlex Richardson slurp_small(const void *ptr, uint32_t nbytes)
8331914882SAlex Richardson {
8431914882SAlex Richardson     const unsigned char *cptr = ptr;
8531914882SAlex Richardson     uint64_t sum = 0;
8631914882SAlex Richardson     while (nbytes >= 4)
8731914882SAlex Richardson     {
8831914882SAlex Richardson 	sum += load32(cptr);
8931914882SAlex Richardson 	cptr += 4;
9031914882SAlex Richardson 	nbytes -= 4;
9131914882SAlex Richardson     }
9231914882SAlex Richardson     if (nbytes & 2)
9331914882SAlex Richardson     {
9431914882SAlex Richardson 	sum += load16(cptr);
9531914882SAlex Richardson 	cptr += 2;
9631914882SAlex Richardson     }
9731914882SAlex Richardson     if (nbytes & 1)
9831914882SAlex Richardson     {
9931914882SAlex Richardson 	sum += (uint8_t) *cptr;
10031914882SAlex Richardson     }
10131914882SAlex Richardson     return sum;
10231914882SAlex Richardson }
10331914882SAlex Richardson 
10431914882SAlex Richardson static inline const void *
align_ptr(const void * ptr,size_t bytes)10531914882SAlex Richardson align_ptr(const void *ptr, size_t bytes)
10631914882SAlex Richardson {
10731914882SAlex Richardson     return (void *) ((uintptr_t) ptr & -(uintptr_t) bytes);
10831914882SAlex Richardson }
10931914882SAlex Richardson 
11031914882SAlex Richardson always_inline
11131914882SAlex Richardson static inline uint16_t
fold_and_swap(uint64_t sum,bool swap)11231914882SAlex Richardson fold_and_swap(uint64_t sum, bool swap)
11331914882SAlex Richardson {
11431914882SAlex Richardson     /* Fold 64-bit sum to 32 bits */
11531914882SAlex Richardson     sum = (sum & 0xffffffff) + (sum >> 32);
11631914882SAlex Richardson     sum = (sum & 0xffffffff) + (sum >> 32);
11731914882SAlex Richardson     Assert(sum == (uint32_t) sum);
11831914882SAlex Richardson 
11931914882SAlex Richardson     /* Fold 32-bit sum to 16 bits */
12031914882SAlex Richardson     sum = (sum & 0xffff) + (sum >> 16);
12131914882SAlex Richardson     sum = (sum & 0xffff) + (sum >> 16);
12231914882SAlex Richardson     Assert(sum == (uint16_t) sum);
12331914882SAlex Richardson 
12431914882SAlex Richardson     if (unlikely(swap)) /* Odd base pointer is unexpected */
12531914882SAlex Richardson     {
12631914882SAlex Richardson 	sum = bswap16(sum);
12731914882SAlex Richardson     }
12831914882SAlex Richardson 
12931914882SAlex Richardson     return (uint16_t) sum;
13031914882SAlex Richardson }
13131914882SAlex Richardson 
13231914882SAlex Richardson #endif
133