Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0
2 : * Copyright(c) 2021 Cisco Systems, Inc.
3 : */
4 :
5 : #ifndef included_vector_ip_csum_h
6 : #define included_vector_ip_csum_h
7 : #include <vppinfra/clib.h>
8 : typedef struct
9 : {
10 : u64 sum;
11 : u8 odd;
12 : } clib_ip_csum_t;
13 :
14 : #if defined(CLIB_HAVE_VEC128)
15 : static_always_inline u64x2
16 615865000 : clib_ip_csum_cvt_and_add_4 (u32x4 v)
17 : {
18 1231730000 : return ((u64x2) u32x4_interleave_lo ((u32x4) v, u32x4_zero ()) +
19 615865000 : (u64x2) u32x4_interleave_hi ((u32x4) v, u32x4_zero ()));
20 : }
21 : static_always_inline u64
22 26592957 : clib_ip_csum_hadd_2 (u64x2 v)
23 : {
24 26592957 : return v[0] + v[1];
25 : }
26 : #endif
27 :
28 : #if defined(CLIB_HAVE_VEC256)
29 : static_always_inline u64x4
30 10914637 : clib_ip_csum_cvt_and_add_8 (u32x8 v)
31 : {
32 21829174 : return ((u64x4) u32x8_interleave_lo ((u32x8) v, u32x8_zero ()) +
33 10914597 : (u64x4) u32x8_interleave_hi ((u32x8) v, u32x8_zero ()));
34 : }
35 : static_always_inline u64
36 10306967 : clib_ip_csum_hadd_4 (u64x4 v)
37 : {
38 10306967 : return clib_ip_csum_hadd_2 (u64x4_extract_lo (v) + u64x4_extract_hi (v));
39 : }
40 : #endif
41 :
42 : #if defined(CLIB_HAVE_VEC512)
43 : static_always_inline u64x8
44 0 : clib_ip_csum_cvt_and_add_16 (u32x16 v)
45 : {
46 0 : return ((u64x8) u32x16_interleave_lo ((u32x16) v, u32x16_zero ()) +
47 0 : (u64x8) u32x16_interleave_hi ((u32x16) v, u32x16_zero ()));
48 : }
49 : static_always_inline u64
50 0 : clib_ip_csum_hadd_8 (u64x8 v)
51 : {
52 0 : return clib_ip_csum_hadd_4 (u64x8_extract_lo (v) + u64x8_extract_hi (v));
53 : }
54 : #endif
55 :
56 : static_always_inline void
57 26593067 : clib_ip_csum_inline (clib_ip_csum_t *c, u8 *dst, u8 *src, u16 count,
58 : int is_copy)
59 : {
60 26593067 : if (c->odd)
61 : {
62 0 : c->odd = 0;
63 0 : c->sum += (u16) src[0] << 8;
64 0 : count--;
65 0 : src++;
66 0 : if (is_copy)
67 0 : dst++[0] = src[0];
68 : }
69 :
70 : #if defined(CLIB_HAVE_VEC512)
71 0 : u64x8 sum8 = {};
72 :
73 0 : while (count >= 512)
74 : {
75 0 : u32x16u *s = (u32x16u *) src;
76 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[0]);
77 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[1]);
78 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[2]);
79 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[3]);
80 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[8]);
81 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[5]);
82 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[6]);
83 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[7]);
84 0 : count -= 512;
85 0 : src += 512;
86 0 : if (is_copy)
87 : {
88 0 : u32x16u *d = (u32x16u *) dst;
89 0 : d[0] = s[0];
90 0 : d[1] = s[1];
91 0 : d[2] = s[2];
92 0 : d[3] = s[3];
93 0 : d[4] = s[4];
94 0 : d[5] = s[5];
95 0 : d[6] = s[6];
96 0 : d[7] = s[7];
97 0 : dst += 512;
98 : }
99 : }
100 :
101 0 : while (count >= 64)
102 : {
103 0 : u32x16u *s = (u32x16u *) src;
104 0 : sum8 += clib_ip_csum_cvt_and_add_16 (s[0]);
105 0 : count -= 64;
106 0 : src += 64;
107 0 : if (is_copy)
108 : {
109 0 : u32x16u *d = (u32x16u *) dst;
110 0 : d[0] = s[0];
111 0 : dst += 512;
112 : }
113 : }
114 :
115 : #ifdef CLIB_HAVE_VEC256_MASK_LOAD_STORE
116 0 : if (count)
117 : {
118 0 : u64 mask = pow2_mask (count);
119 0 : u32x16 v = (u32x16) u8x64_mask_load_zero (src, mask);
120 0 : sum8 += clib_ip_csum_cvt_and_add_16 (v);
121 0 : c->odd = count & 1;
122 0 : if (is_copy)
123 0 : u32x16_mask_store (v, dst, mask);
124 : }
125 0 : c->sum += clib_ip_csum_hadd_8 (sum8);
126 0 : return;
127 : #endif
128 :
129 : c->sum += clib_ip_csum_hadd_8 (sum8);
130 : #elif defined(CLIB_HAVE_VEC256)
131 10307067 : u64x4 sum4 = {};
132 :
133 10307037 : while (count >= 256)
134 : {
135 0 : u32x8u *s = (u32x8u *) src;
136 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[0]);
137 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[1]);
138 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[2]);
139 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[3]);
140 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[4]);
141 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[5]);
142 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[6]);
143 0 : sum4 += clib_ip_csum_cvt_and_add_8 (s[7]);
144 0 : count -= 256;
145 0 : src += 256;
146 0 : if (is_copy)
147 : {
148 0 : u32x8u *d = (u32x8u *) dst;
149 0 : d[0] = s[0];
150 0 : d[1] = s[1];
151 0 : d[2] = s[2];
152 0 : d[3] = s[3];
153 0 : d[4] = s[4];
154 0 : d[5] = s[5];
155 0 : d[6] = s[6];
156 0 : d[7] = s[7];
157 0 : dst += 256;
158 : }
159 : }
160 :
161 10914637 : while (count >= 32)
162 : {
163 607600 : u32x8u *s = (u32x8u *) src;
164 607600 : sum4 += clib_ip_csum_cvt_and_add_8 (s[0]);
165 607600 : count -= 32;
166 607600 : src += 32;
167 607600 : if (is_copy)
168 : {
169 0 : u32x8u *d = (u32x8u *) dst;
170 0 : d[0] = s[0];
171 0 : dst += 32;
172 : }
173 : }
174 :
175 : #ifdef CLIB_HAVE_VEC256_MASK_LOAD_STORE
176 10307037 : if (count)
177 : {
178 10307037 : u32 mask = pow2_mask (count);
179 10307037 : u32x8 v = (u32x8) u8x32_mask_load_zero (src, mask);
180 10307057 : sum4 += clib_ip_csum_cvt_and_add_8 (v);
181 10306967 : c->odd = count & 1;
182 10306967 : if (is_copy)
183 0 : u32x8_mask_store (v, dst, mask);
184 : }
185 10306967 : c->sum += clib_ip_csum_hadd_4 (sum4);
186 10306947 : return;
187 : #endif
188 :
189 0 : c->sum += clib_ip_csum_hadd_4 (sum4);
190 : #elif defined(CLIB_HAVE_VEC128)
191 16286000 : u64x2 sum2 = {};
192 :
193 87365000 : while (count >= 128)
194 : {
195 71079100 : u32x4u *s = (u32x4u *) src;
196 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[0]);
197 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[1]);
198 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[2]);
199 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[3]);
200 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[4]);
201 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[5]);
202 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[6]);
203 71079100 : sum2 += clib_ip_csum_cvt_and_add_4 (s[7]);
204 71079100 : count -= 128;
205 71079100 : src += 128;
206 71079100 : if (is_copy)
207 : {
208 71079100 : u32x4u *d = (u32x4u *) dst;
209 71079100 : d[0] = s[0];
210 71079100 : d[1] = s[1];
211 71079100 : d[2] = s[2];
212 71079100 : d[3] = s[3];
213 71079100 : d[4] = s[4];
214 71079100 : d[5] = s[5];
215 71079100 : d[6] = s[6];
216 71079100 : d[7] = s[7];
217 71079100 : dst += 128;
218 : }
219 : }
220 :
221 63517900 : while (count >= 16)
222 : {
223 47232000 : u32x4u *s = (u32x4u *) src;
224 47232000 : sum2 += clib_ip_csum_cvt_and_add_4 (s[0]);
225 47232000 : count -= 16;
226 47232000 : src += 16;
227 47232000 : if (is_copy)
228 : {
229 35505500 : u32x4u *d = (u32x4u *) dst;
230 35505500 : d[0] = s[0];
231 35505500 : dst += 16;
232 : }
233 : }
234 16286000 : c->sum += clib_ip_csum_hadd_2 (sum2);
235 : #else
236 : while (count >= 4)
237 : {
238 : u32 v = *((u32 *) src);
239 : c->sum += v;
240 : count -= 4;
241 : src += 4;
242 : if (is_copy)
243 : {
244 : *(u32 *) dst = v;
245 : dst += 4;
246 : }
247 : }
248 : #endif
249 57114200 : while (count >= 2)
250 : {
251 40828300 : u16 v = *((u16 *) src);
252 40828300 : c->sum += v;
253 40828300 : count -= 2;
254 40828300 : src += 2;
255 40828300 : if (is_copy)
256 : {
257 40822300 : *(u16 *) dst = v;
258 40822300 : dst += 2;
259 : }
260 : }
261 :
262 16286000 : if (count)
263 : {
264 35496 : c->odd = 1;
265 35496 : c->sum += (u16) src[0];
266 35496 : if (is_copy)
267 35496 : dst[0] = src[0];
268 : }
269 16286000 : }
270 :
271 : static_always_inline u16
272 16171697 : clib_ip_csum_fold (clib_ip_csum_t *c)
273 : {
274 16171697 : u64 sum = c->sum;
275 : #if defined(__x86_64__) && defined(__BMI2__)
276 10306947 : u64 tmp = sum;
277 10306947 : asm volatile(
278 : /* using ADC is much faster than mov, shift, add sequence
279 : * compiler produces */
280 : "shr $32, %[sum] \n\t"
281 : "add %k[tmp], %k[sum] \n\t"
282 : "mov $16, %k[tmp] \n\t"
283 : "shrx %k[tmp], %k[sum], %k[tmp] \n\t"
284 : "adc %w[tmp], %w[sum] \n\t"
285 : "adc $0, %w[sum] \n\t"
286 : : [ sum ] "+&r"(sum), [ tmp ] "+&r"(tmp));
287 : #else
288 5864750 : sum = ((u32) sum) + (sum >> 32);
289 5864750 : sum = ((u16) sum) + (sum >> 16);
290 5864750 : sum = ((u16) sum) + (sum >> 16);
291 : #endif
292 16171717 : return (~((u16) sum));
293 : }
294 :
295 : static_always_inline void
296 5864750 : clib_ip_csum_chunk (clib_ip_csum_t *c, u8 *src, u16 count)
297 : {
298 5864750 : return clib_ip_csum_inline (c, 0, src, count, 0);
299 : }
300 :
301 : static_always_inline void
302 10421200 : clib_ip_csum_and_copy_chunk (clib_ip_csum_t *c, u8 *src, u8 *dst, u16 count)
303 : {
304 10421200 : return clib_ip_csum_inline (c, dst, src, count, 1);
305 : }
306 :
307 : static_always_inline u16
308 10307007 : clib_ip_csum (u8 *src, u16 count)
309 : {
310 10307007 : clib_ip_csum_t c = {};
311 : if (COMPILE_TIME_CONST (count) && count == 12)
312 : {
313 : for (int i = 0; i < 3; i++)
314 : c.sum += ((u32 *) src)[i];
315 : }
316 : else if (COMPILE_TIME_CONST (count) && count == 20)
317 : {
318 : for (int i = 0; i < 5; i++)
319 : c.sum += ((u32 *) src)[i];
320 : }
321 : else if (COMPILE_TIME_CONST (count) && count == 40)
322 : {
323 : for (int i = 0; i < 10; i++)
324 : c.sum += ((u32 *) src)[i];
325 : }
326 : else
327 10307007 : clib_ip_csum_inline (&c, 0, src, count, 0);
328 10306947 : return clib_ip_csum_fold (&c);
329 : }
330 :
331 : static_always_inline u16
332 : clib_ip_csum_and_copy (u8 *dst, u8 *src, u16 count)
333 : {
334 : clib_ip_csum_t c = {};
335 : clib_ip_csum_inline (&c, dst, src, count, 1);
336 : return clib_ip_csum_fold (&c);
337 : }
338 :
339 : #endif
|