Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2017-2020 Intel Corporation
3 : : */
4 : :
5 : : #include <stdalign.h>
6 : : #include <string.h>
7 : :
8 : : #include <rte_common.h>
9 : : #include <rte_vect.h>
10 : : #include <rte_branch_prediction.h>
11 : :
12 : : #include "net_crc.h"
13 : :
14 : : /** PCLMULQDQ CRC computation context structure */
15 : : struct crc_pclmulqdq_ctx {
16 : : __m128i rk1_rk2;
17 : : __m128i rk5_rk6;
18 : : __m128i rk7_rk8;
19 : : };
20 : :
21 : : static alignas(16) struct crc_pclmulqdq_ctx crc32_eth_pclmulqdq;
22 : : static alignas(16) struct crc_pclmulqdq_ctx crc16_ccitt_pclmulqdq;
23 : : /**
24 : : * @brief Performs one folding round
25 : : *
26 : : * Logically function operates as follows:
27 : : * DATA = READ_NEXT_16BYTES();
28 : : * F1 = LSB8(FOLD)
29 : : * F2 = MSB8(FOLD)
30 : : * T1 = CLMUL(F1, RK1)
31 : : * T2 = CLMUL(F2, RK2)
32 : : * FOLD = XOR(T1, T2, DATA)
33 : : *
34 : : * @param data_block
35 : : * 16 byte data block
36 : : * @param precomp
37 : : * Precomputed rk1 constant
38 : : * @param fold
39 : : * Current16 byte folded data
40 : : *
41 : : * @return
42 : : * New 16 byte folded data
43 : : */
44 : : static __rte_always_inline __m128i
45 : : crcr32_folding_round(__m128i data_block,
46 : : __m128i precomp,
47 : : __m128i fold)
48 : : {
49 : : __m128i tmp0 = _mm_clmulepi64_si128(fold, precomp, 0x01);
50 : : __m128i tmp1 = _mm_clmulepi64_si128(fold, precomp, 0x10);
51 : :
52 : : return _mm_xor_si128(tmp1, _mm_xor_si128(data_block, tmp0));
53 : : }
54 : :
55 : : /**
56 : : * Performs reduction from 128 bits to 64 bits
57 : : *
58 : : * @param data128
59 : : * 128 bits data to be reduced
60 : : * @param precomp
61 : : * precomputed constants rk5, rk6
62 : : *
63 : : * @return
64 : : * 64 bits reduced data
65 : : */
66 : :
67 : : static __rte_always_inline __m128i
68 : : crcr32_reduce_128_to_64(__m128i data128, __m128i precomp)
69 : : {
70 : : __m128i tmp0, tmp1, tmp2;
71 : :
72 : : /* 64b fold */
73 : : tmp0 = _mm_clmulepi64_si128(data128, precomp, 0x00);
74 : : tmp1 = _mm_srli_si128(data128, 8);
75 : : tmp0 = _mm_xor_si128(tmp0, tmp1);
76 : :
77 : : /* 32b fold */
78 : : tmp2 = _mm_slli_si128(tmp0, 4);
79 : : tmp1 = _mm_clmulepi64_si128(tmp2, precomp, 0x10);
80 : :
81 : : return _mm_xor_si128(tmp1, tmp0);
82 : : }
83 : :
84 : : /**
85 : : * Performs Barret's reduction from 64 bits to 32 bits
86 : : *
87 : : * @param data64
88 : : * 64 bits data to be reduced
89 : : * @param precomp
90 : : * rk7 precomputed constant
91 : : *
92 : : * @return
93 : : * reduced 32 bits data
94 : : */
95 : :
96 : : static __rte_always_inline uint32_t
97 : : crcr32_reduce_64_to_32(__m128i data64, __m128i precomp)
98 : : {
99 : : __m128i tmp0, tmp1, tmp2;
100 : :
101 : : tmp0 = _mm_blend_epi16(data64, _mm_setzero_si128(), 0x3);
102 : :
103 : : tmp1 = _mm_clmulepi64_si128(tmp0, precomp, 0x00);
104 : : tmp1 = _mm_xor_si128(tmp1, tmp0);
105 : :
106 : : tmp2 = _mm_clmulepi64_si128(tmp1, precomp, 0x10);
107 : : tmp2 = _mm_xor_si128(tmp2, tmp0);
108 : :
109 : 6 : return _mm_extract_epi32(tmp2, 2);
110 : : }
111 : :
112 : : static const alignas(16) uint8_t crc_xmm_shift_tab[32] = {
113 : : 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
114 : : 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
115 : : 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
116 : : 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
117 : : };
118 : :
119 : : /**
120 : : * Shifts left 128 bit register by specified number of bytes
121 : : *
122 : : * @param reg
123 : : * 128 bit value
124 : : * @param num
125 : : * number of bytes to shift left reg by (0-16)
126 : : *
127 : : * @return
128 : : * reg << (num * 8)
129 : : */
130 : :
131 : : static __rte_always_inline __m128i
132 : : xmm_shift_left(__m128i reg, const unsigned int num)
133 : : {
134 : 4 : const __m128i *p = (const __m128i *)(crc_xmm_shift_tab + 16 - num);
135 : :
136 : : return _mm_shuffle_epi8(reg, _mm_loadu_si128(p));
137 : : }
138 : :
139 : : static __rte_always_inline uint32_t
140 : : crc32_eth_calc_pclmulqdq(
141 : : const uint8_t *data,
142 : : uint32_t data_len,
143 : : uint32_t crc,
144 : : const struct crc_pclmulqdq_ctx *params)
145 : : {
146 : : __m128i temp, fold, k;
147 : : uint32_t n;
148 : :
149 : : /* Get CRC init value */
150 : : temp = _mm_insert_epi32(_mm_setzero_si128(), crc, 0);
151 : :
152 : : /**
153 : : * Folding all data into single 16 byte data block
154 : : * Assumes: fold holds first 16 bytes of data
155 : : */
156 : :
157 [ - + + + ]: 12 : if (unlikely(data_len < 32)) {
158 [ - - - + ]: 4 : if (unlikely(data_len == 16)) {
159 : : /* 16 bytes */
160 : : fold = _mm_loadu_si128((const __m128i *)data);
161 : : fold = _mm_xor_si128(fold, temp);
162 : 0 : goto reduction_128_64;
163 : : }
164 : :
165 [ - - + - ]: 4 : if (unlikely(data_len < 16)) {
166 : : /* 0 to 15 bytes */
167 : : alignas(16) uint8_t buffer[16];
168 : :
169 : : memset(buffer, 0, sizeof(buffer));
170 [ - - + + ]: 4 : memcpy(buffer, data, data_len);
171 : :
172 : : fold = _mm_load_si128((const __m128i *)buffer);
173 : : fold = _mm_xor_si128(fold, temp);
174 [ - - + + ]: 4 : if (unlikely(data_len < 4)) {
175 : 2 : fold = xmm_shift_left(fold, 8 - data_len);
176 : 2 : goto barret_reduction;
177 : : }
178 : 2 : fold = xmm_shift_left(fold, 16 - data_len);
179 : 2 : goto reduction_128_64;
180 : : }
181 : : /* 17 to 31 bytes */
182 : : fold = _mm_loadu_si128((const __m128i *)data);
183 : : fold = _mm_xor_si128(fold, temp);
184 : : n = 16;
185 : 0 : k = params->rk1_rk2;
186 : 0 : goto partial_bytes;
187 : : }
188 : :
189 : : /** At least 32 bytes in the buffer */
190 : : /** Apply CRC initial value */
191 : : fold = _mm_loadu_si128((const __m128i *)data);
192 : : fold = _mm_xor_si128(fold, temp);
193 : :
194 : : /** Main folding loop - the last 16 bytes is processed separately */
195 : 8 : k = params->rk1_rk2;
196 [ + + + + ]: 238 : for (n = 16; (n + 16) <= data_len; n += 16) {
197 : 230 : temp = _mm_loadu_si128((const __m128i *)&data[n]);
198 : : fold = crcr32_folding_round(temp, k, fold);
199 : : }
200 : :
201 : 8 : partial_bytes:
202 [ + + + - ]: 8 : if (likely(n < data_len)) {
203 : :
204 : : __m128i last16, a, b;
205 : :
206 : 4 : last16 = _mm_loadu_si128((const __m128i *)&data[data_len - 16]);
207 : :
208 : : temp = _mm_loadu_si128((const __m128i *)
209 : 4 : &crc_xmm_shift_tab[data_len & 15]);
210 : : a = _mm_shuffle_epi8(fold, temp);
211 : :
212 : : temp = _mm_xor_si128(temp, _mm_set1_epi8(0xff));
213 : : b = _mm_shuffle_epi8(fold, temp);
214 : : b = _mm_blendv_epi8(b, last16, temp);
215 : :
216 : : /* k = rk1 & rk2 */
217 : : temp = _mm_clmulepi64_si128(a, k, 0x01);
218 : : fold = _mm_clmulepi64_si128(a, k, 0x10);
219 : :
220 : : fold = _mm_xor_si128(fold, temp);
221 : : fold = _mm_xor_si128(fold, b);
222 : : }
223 : :
224 : : /** Reduction 128 -> 32 Assumes: fold holds 128bit folded data */
225 : 4 : reduction_128_64:
226 : 10 : k = params->rk5_rk6;
227 : : fold = crcr32_reduce_128_to_64(fold, k);
228 : :
229 : 12 : barret_reduction:
230 : 12 : k = params->rk7_rk8;
231 : : n = crcr32_reduce_64_to_32(fold, k);
232 : :
233 : : return n;
234 : : }
235 : :
236 : : void
237 : 301 : rte_net_crc_sse42_init(void)
238 : : {
239 : : uint64_t k1, k2, k5, k6;
240 : : uint64_t p = 0, q = 0;
241 : :
242 : : /** Initialize CRC16 data */
243 : : k1 = 0x189aeLLU;
244 : : k2 = 0x8e10LLU;
245 : : k5 = 0x189aeLLU;
246 : : k6 = 0x114aaLLU;
247 : : q = 0x11c581910LLU;
248 : : p = 0x10811LLU;
249 : :
250 : : /** Save the params in context structure */
251 : 301 : crc16_ccitt_pclmulqdq.rk1_rk2 = _mm_set_epi64x(k2, k1);
252 : 301 : crc16_ccitt_pclmulqdq.rk5_rk6 = _mm_set_epi64x(k6, k5);
253 : 301 : crc16_ccitt_pclmulqdq.rk7_rk8 = _mm_set_epi64x(p, q);
254 : :
255 : : /** Initialize CRC32 data */
256 : : k1 = 0xccaa009eLLU;
257 : : k2 = 0x1751997d0LLU;
258 : : k5 = 0xccaa009eLLU;
259 : : k6 = 0x163cd6124LLU;
260 : : q = 0x1f7011640LLU;
261 : : p = 0x1db710641LLU;
262 : :
263 : : /** Save the params in context structure */
264 : 301 : crc32_eth_pclmulqdq.rk1_rk2 = _mm_set_epi64x(k2, k1);
265 : 301 : crc32_eth_pclmulqdq.rk5_rk6 = _mm_set_epi64x(k6, k5);
266 : 301 : crc32_eth_pclmulqdq.rk7_rk8 = _mm_set_epi64x(p, q);
267 : 301 : }
268 : :
269 : : uint32_t
270 [ + + ]: 6 : rte_crc16_ccitt_sse42_handler(const uint8_t *data, uint32_t data_len)
271 : : {
272 : : /** return 16-bit CRC value */
273 : 6 : return (uint16_t)~crc32_eth_calc_pclmulqdq(data,
274 : : data_len,
275 : : 0xffff,
276 : : &crc16_ccitt_pclmulqdq);
277 : : }
278 : :
279 : : uint32_t
280 [ - + ]: 6 : rte_crc32_eth_sse42_handler(const uint8_t *data, uint32_t data_len)
281 : : {
282 : 6 : return ~crc32_eth_calc_pclmulqdq(data,
283 : : data_len,
284 : : 0xffffffffUL,
285 : : &crc32_eth_pclmulqdq);
286 : : }
|