Whamcloud - gitweb
LU-1339 libcfs: add crc32 pclmulqdq implementation
[fs/lustre-release.git] / libcfs / libcfs / user-crc32pclmul.c
1 /* GPL HEADER START
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 only,
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License version 2 for more details (a copy is included
13  * in the LICENSE file that accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License
16  * version 2 along with this program; If not, see http://www.gnu.org/licenses
17  *
18  * Please  visit http://www.xyratex.com/contact if you need additional
19  * information or have any questions.
20  *
21  * GPL HEADER END
22  */
23
24 /*
25  * Copyright 2012 Xyratex Technology Limited
26  *
27  */
28
29 #include <libcfs/libcfs.h>
30 #include <libcfs/posix/posix-crypto.h>
31 #include <libcfs/user-crypto.h>
32
33 #define CHKSUM_BLOCK_SIZE       1
34 #define CHKSUM_DIGEST_SIZE      4
35
36 #define PCLMUL_MIN_LEN          64L     /* minimum size of buffer
37                                          * for crc32_pclmul_le_16 */
38 #define SCALE_F                 16L     /* size of xmm register */
39 #define SCALE_F_MASK            (SCALE_F - 1)
40
41 unsigned int crc32_pclmul_le(unsigned int crc, unsigned char const *p,
42                              size_t len)
43 {
44         unsigned int iquotient;
45         unsigned int iremainder;
46         unsigned int prealign;
47
48         if (len < PCLMUL_MIN_LEN + SCALE_F_MASK)
49                 return crc32_le(crc, p, len);
50
51         if ((long)p & SCALE_F_MASK) {
52                 /* align p to 16 byte */
53                 prealign = SCALE_F - ((long)p & SCALE_F_MASK);
54
55                 crc = crc32_le(crc, p, prealign);
56                 len -= prealign;
57                 p = (unsigned char *)(((unsigned long)p + SCALE_F_MASK) &
58                                      ~SCALE_F_MASK);
59         }
60         iquotient = len & (~SCALE_F_MASK);
61         iremainder = len & SCALE_F_MASK;
62
63         crc = crc32_pclmul_le_16(p, iquotient, crc);
64
65         if (iremainder)
66                 crc = crc32_le(crc, p + iquotient, iremainder);
67
68         return crc;
69 }
70 #ifndef bit_PCLMUL
71 #define bit_PCLMUL              (1 << 1)
72 #endif
73
74 int crc32_pclmul_init(void)
75 {
76         unsigned int eax, ebx, ecx, edx, level;
77
78         eax = ebx = ecx = edx = 0;
79         level = 1;
80         /* get cpuid */
81         __asm__ ("xchg{l}\t{%%}ebx, %1\n\t"                          \
82                  "cpuid\n\t"                                         \
83                  "xchg{l}\t{%%}ebx, %1\n\t"                          \
84                  : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)    \
85                  : "0" (level));
86
87         if (ecx & bit_PCLMUL)
88                 return 1;
89
90         return -1;
91 }