LCOV - code coverage report
Current view: top level - lib/net - net_crc_sse.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 43 43 100.0 %
Date: 2026-08-01 17:54:00 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 27 32 84.4 %

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

Generated by: LCOV version 1.14