xref: /aosp_15_r20/external/arm-optimized-routines/networking/chksum_common.h (revision 412f47f9e737e10ed5cc46ec6a8d7fa2264f8a14)
1*412f47f9SXin Li /*
2*412f47f9SXin Li  * Common code for checksum implementations
3*412f47f9SXin Li  *
4*412f47f9SXin Li  * Copyright (c) 2020, Arm Limited.
5*412f47f9SXin Li  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6*412f47f9SXin Li  */
7*412f47f9SXin Li 
8*412f47f9SXin Li #ifndef CHKSUM_COMMON_H
9*412f47f9SXin Li #define CHKSUM_COMMON_H
10*412f47f9SXin Li 
11*412f47f9SXin Li #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
12*412f47f9SXin Li #error Only little endian supported
13*412f47f9SXin Li #endif
14*412f47f9SXin Li 
15*412f47f9SXin Li #include <limits.h>
16*412f47f9SXin Li #include <stdbool.h>
17*412f47f9SXin Li #include <stdint.h>
18*412f47f9SXin Li #include <string.h>
19*412f47f9SXin Li 
20*412f47f9SXin Li /* Assertions must be explicitly enabled */
21*412f47f9SXin Li #if WANT_ASSERT
22*412f47f9SXin Li #undef NDEBUG
23*412f47f9SXin Li #include <assert.h>
24*412f47f9SXin Li #define Assert(exp) assert(exp)
25*412f47f9SXin Li #else
26*412f47f9SXin Li #define Assert(exp) (void) (exp)
27*412f47f9SXin Li #endif
28*412f47f9SXin Li 
29*412f47f9SXin Li #ifdef __GNUC__
30*412f47f9SXin Li #define likely(x)     __builtin_expect(!!(x), 1)
31*412f47f9SXin Li #define unlikely(x)   __builtin_expect(!!(x), 0)
32*412f47f9SXin Li #define may_alias     __attribute__((__may_alias__))
33*412f47f9SXin Li #define always_inline __attribute__((always_inline))
34*412f47f9SXin Li #ifdef __clang__
35*412f47f9SXin Li #define no_unroll_loops
36*412f47f9SXin Li #else
37*412f47f9SXin Li #define no_unroll_loops  __attribute__((optimize("no-unroll-loops")))
38*412f47f9SXin Li #endif
39*412f47f9SXin Li #define bswap16(x)    __builtin_bswap16((x))
40*412f47f9SXin Li #else
41*412f47f9SXin Li #define likely(x)     (x)
42*412f47f9SXin Li #define unlikely(x)   (x)
43*412f47f9SXin Li #define may_alias
44*412f47f9SXin Li #define always_inline
45*412f47f9SXin Li #define no_unroll_loops
46*412f47f9SXin Li #define bswap16(x)    ((uint8_t)((x) >> 8) | ((uint8_t)(x) << 8))
47*412f47f9SXin Li #endif
48*412f47f9SXin Li 
49*412f47f9SXin Li #define ALL_ONES ~UINT64_C(0)
50*412f47f9SXin Li 
51*412f47f9SXin Li static inline
load64(const void * ptr)52*412f47f9SXin Li uint64_t load64(const void *ptr)
53*412f47f9SXin Li {
54*412f47f9SXin Li     /* GCC will optimise this to a normal load instruction */
55*412f47f9SXin Li     uint64_t v;
56*412f47f9SXin Li     memcpy(&v, ptr, sizeof v);
57*412f47f9SXin Li     return v;
58*412f47f9SXin Li }
59*412f47f9SXin Li 
60*412f47f9SXin Li static inline
load32(const void * ptr)61*412f47f9SXin Li uint32_t load32(const void *ptr)
62*412f47f9SXin Li {
63*412f47f9SXin Li     /* GCC will optimise this to a normal load instruction */
64*412f47f9SXin Li     uint32_t v;
65*412f47f9SXin Li     memcpy(&v, ptr, sizeof v);
66*412f47f9SXin Li     return v;
67*412f47f9SXin Li }
68*412f47f9SXin Li 
69*412f47f9SXin Li static inline
load16(const void * ptr)70*412f47f9SXin Li uint16_t load16(const void *ptr)
71*412f47f9SXin Li {
72*412f47f9SXin Li     /* GCC will optimise this to a normal load instruction */
73*412f47f9SXin Li     uint16_t v;
74*412f47f9SXin Li     memcpy(&v, ptr, sizeof v);
75*412f47f9SXin Li     return v;
76*412f47f9SXin Li }
77*412f47f9SXin Li 
78*412f47f9SXin Li /* slurp_small() is for small buffers, don't waste cycles on alignment */
79*412f47f9SXin Li no_unroll_loops
80*412f47f9SXin Li always_inline
81*412f47f9SXin Li static inline uint64_t
slurp_small(const void * ptr,uint32_t nbytes)82*412f47f9SXin Li slurp_small(const void *ptr, uint32_t nbytes)
83*412f47f9SXin Li {
84*412f47f9SXin Li     const unsigned char *cptr = ptr;
85*412f47f9SXin Li     uint64_t sum = 0;
86*412f47f9SXin Li     while (nbytes >= 4)
87*412f47f9SXin Li     {
88*412f47f9SXin Li 	sum += load32(cptr);
89*412f47f9SXin Li 	cptr += 4;
90*412f47f9SXin Li 	nbytes -= 4;
91*412f47f9SXin Li     }
92*412f47f9SXin Li     if (nbytes & 2)
93*412f47f9SXin Li     {
94*412f47f9SXin Li 	sum += load16(cptr);
95*412f47f9SXin Li 	cptr += 2;
96*412f47f9SXin Li     }
97*412f47f9SXin Li     if (nbytes & 1)
98*412f47f9SXin Li     {
99*412f47f9SXin Li 	sum += (uint8_t) *cptr;
100*412f47f9SXin Li     }
101*412f47f9SXin Li     return sum;
102*412f47f9SXin Li }
103*412f47f9SXin Li 
104*412f47f9SXin Li static inline const void *
align_ptr(const void * ptr,size_t bytes)105*412f47f9SXin Li align_ptr(const void *ptr, size_t bytes)
106*412f47f9SXin Li {
107*412f47f9SXin Li     return (void *) ((uintptr_t) ptr & -(uintptr_t) bytes);
108*412f47f9SXin Li }
109*412f47f9SXin Li 
110*412f47f9SXin Li always_inline
111*412f47f9SXin Li static inline uint16_t
fold_and_swap(uint64_t sum,bool swap)112*412f47f9SXin Li fold_and_swap(uint64_t sum, bool swap)
113*412f47f9SXin Li {
114*412f47f9SXin Li     /* Fold 64-bit sum to 32 bits */
115*412f47f9SXin Li     sum = (sum & 0xffffffff) + (sum >> 32);
116*412f47f9SXin Li     sum = (sum & 0xffffffff) + (sum >> 32);
117*412f47f9SXin Li     Assert(sum == (uint32_t) sum);
118*412f47f9SXin Li 
119*412f47f9SXin Li     /* Fold 32-bit sum to 16 bits */
120*412f47f9SXin Li     sum = (sum & 0xffff) + (sum >> 16);
121*412f47f9SXin Li     sum = (sum & 0xffff) + (sum >> 16);
122*412f47f9SXin Li     Assert(sum == (uint16_t) sum);
123*412f47f9SXin Li 
124*412f47f9SXin Li     if (unlikely(swap)) /* Odd base pointer is unexpected */
125*412f47f9SXin Li     {
126*412f47f9SXin Li 	sum = bswap16(sum);
127*412f47f9SXin Li     }
128*412f47f9SXin Li 
129*412f47f9SXin Li     return (uint16_t) sum;
130*412f47f9SXin Li }
131*412f47f9SXin Li 
132*412f47f9SXin Li #endif
133