LCOV - code coverage report
Current view: top level - lib/net - net_crc_sse.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 34 37 91.9 %
Date: 2026-07-01 18:02:41 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 19 32 59.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 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                 :            : }

Generated by: LCOV version 1.14