2 // Accelerated CRC-T10DIF using arm64 NEON and Crypto Extensions instructions
4 // Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org>
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License version 2 as
8 // published by the Free Software Foundation.
12 // Implement fast CRC-T10DIF computation with SSE and PCLMULQDQ instructions
14 // Copyright (c) 2013, Intel Corporation
17 // Erdinc Ozturk <erdinc.ozturk@intel.com>
18 // Vinodh Gopal <vinodh.gopal@intel.com>
19 // James Guilford <james.guilford@intel.com>
20 // Tim Chen <tim.c.chen@linux.intel.com>
22 // This software is available to you under a choice of one of two
23 // licenses. You may choose to be licensed under the terms of the GNU
24 // General Public License (GPL) Version 2, available from the file
25 // COPYING in the main directory of this source tree, or the
26 // OpenIB.org BSD license below:
28 // Redistribution and use in source and binary forms, with or without
29 // modification, are permitted provided that the following conditions are
32 // * Redistributions of source code must retain the above copyright
33 // notice, this list of conditions and the following disclaimer.
35 // * Redistributions in binary form must reproduce the above copyright
36 // notice, this list of conditions and the following disclaimer in the
37 // documentation and/or other materials provided with the
40 // * Neither the name of the Intel Corporation nor the names of its
41 // contributors may be used to endorse or promote products derived from
42 // this software without specific prior written permission.
45 // THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
46 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
49 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
50 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 // UINT16 crc_t10dif_pcl(
59 // UINT16 init_crc, //initial CRC value, 16 bits
60 // const unsigned char *buf, //buffer pointer to calculate CRC on
61 // UINT64 len //buffer length in bytes (64-bit data)
64 // Reference paper titled "Fast CRC Computation for Generic
65 // Polynomials Using PCLMULQDQ Instruction"
66 // URL: http://www.intel.com/content/dam/www/public/us/en/documents
67 // /white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
71 #include <linux/linkage.h>
72 #include <asm/assembler.h>
83 ENTRY(crc_t10dif_pmull)
84 movi vzr.16b, #0 // init zero register
86 // adjust the 16-bit initial_crc value, scale it to 32 bits
87 lsl arg1_low32, arg1_low32, #16
89 // check if smaller than 256
92 // for sizes less than 128, we can't fold 64B at a time...
95 // load the initial crc value
96 // crc value does not need to be byte-reflected, but it needs
97 // to be moved to the high part of the register.
98 // because data will be byte-reflected and will align with
99 // initial crc at correct place.
101 mov v10.s[3], arg1_low32 // initial crc
103 // receive the initial 64B data, xor the initial crc value
105 ldp q2, q3, [arg2, #0x20]
106 ldp q4, q5, [arg2, #0x40]
107 ldp q6, q7, [arg2, #0x60]
108 add arg2, arg2, #0x80
110 CPU_LE( rev64 v0.16b, v0.16b )
111 CPU_LE( rev64 v1.16b, v1.16b )
112 CPU_LE( rev64 v2.16b, v2.16b )
113 CPU_LE( rev64 v3.16b, v3.16b )
114 CPU_LE( rev64 v4.16b, v4.16b )
115 CPU_LE( rev64 v5.16b, v5.16b )
116 CPU_LE( rev64 v6.16b, v6.16b )
117 CPU_LE( rev64 v7.16b, v7.16b )
119 CPU_LE( ext v0.16b, v0.16b, v0.16b, #8 )
120 CPU_LE( ext v1.16b, v1.16b, v1.16b, #8 )
121 CPU_LE( ext v2.16b, v2.16b, v2.16b, #8 )
122 CPU_LE( ext v3.16b, v3.16b, v3.16b, #8 )
123 CPU_LE( ext v4.16b, v4.16b, v4.16b, #8 )
124 CPU_LE( ext v5.16b, v5.16b, v5.16b, #8 )
125 CPU_LE( ext v6.16b, v6.16b, v6.16b, #8 )
126 CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 )
128 // XOR the initial_crc value
129 eor v0.16b, v0.16b, v10.16b
131 ldr q10, rk3 // xmm10 has rk3 and rk4
132 // type of pmull instruction
133 // will determine which constant to use
136 // we subtract 256 instead of 128 to save one instruction from the loop
140 // at this section of the code, there is 64*x+y (0<=y<64) bytes of
141 // buffer. The _fold_64_B_loop will fold 64B at a time
142 // until we have 64+y Bytes of buffer
145 // fold 64B at a time. This section of the code folds 4 vector
146 // registers in parallel
149 .macro fold64, reg1, reg2
150 ldp q11, q12, [arg2], #0x20
152 pmull2 v8.1q, \reg1\().2d, v10.2d
153 pmull \reg1\().1q, \reg1\().1d, v10.1d
155 CPU_LE( rev64 v11.16b, v11.16b )
156 CPU_LE( rev64 v12.16b, v12.16b )
158 pmull2 v9.1q, \reg2\().2d, v10.2d
159 pmull \reg2\().1q, \reg2\().1d, v10.1d
161 CPU_LE( ext v11.16b, v11.16b, v11.16b, #8 )
162 CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 )
164 eor \reg1\().16b, \reg1\().16b, v8.16b
165 eor \reg2\().16b, \reg2\().16b, v9.16b
166 eor \reg1\().16b, \reg1\().16b, v11.16b
167 eor \reg2\().16b, \reg2\().16b, v12.16b
175 subs arg3, arg3, #128
177 // check if there is another 64B in the buffer to be able to fold
180 // at this point, the buffer pointer is pointing at the last y Bytes
181 // of the buffer the 64B of folded data is in 4 of the vector
182 // registers: v0, v1, v2, v3
184 // fold the 8 vector registers to 1 vector register with different
189 .macro fold16, reg, rk
190 pmull v8.1q, \reg\().1d, v10.1d
191 pmull2 \reg\().1q, \reg\().2d, v10.2d
195 eor v7.16b, v7.16b, v8.16b
196 eor v7.16b, v7.16b, \reg\().16b
207 // instead of 64, we add 48 to the loop counter to save 1 instruction
208 // from the loop instead of a cmp instruction, we use the negative
209 // flag with the jl instruction
210 adds arg3, arg3, #(128-16)
211 b.lt _final_reduction_for_128
213 // now we have 16+y bytes left to reduce. 16 Bytes is in register v7
214 // and the rest is in memory. We can fold 16 bytes at a time if y>=16
215 // continue folding 16B at a time
218 pmull v8.1q, v7.1d, v10.1d
219 pmull2 v7.1q, v7.2d, v10.2d
220 eor v7.16b, v7.16b, v8.16b
223 CPU_LE( rev64 v0.16b, v0.16b )
224 CPU_LE( ext v0.16b, v0.16b, v0.16b, #8 )
225 eor v7.16b, v7.16b, v0.16b
228 // instead of a cmp instruction, we utilize the flags with the
229 // jge instruction equivalent of: cmp arg3, 16-16
230 // check if there is any more 16B in the buffer to be able to fold
231 b.ge _16B_reduction_loop
233 // now we have 16+z bytes left to reduce, where 0<= z < 16.
234 // first, we reduce the data in the xmm7 register
236 _final_reduction_for_128:
237 // check if any more data to fold. If not, compute the CRC of
238 // the final 128 bits
242 // here we are getting data that is less than 16 bytes.
243 // since we know that there was data before the pointer, we can
244 // offset the input pointer before the actual point, to receive
245 // exactly 16 bytes. after that the registers need to be adjusted.
249 CPU_LE( rev64 v1.16b, v1.16b )
250 CPU_LE( ext v1.16b, v1.16b, v1.16b, #8 )
252 // get rid of the extra data that was loaded before
253 // load the shift constant
254 adr x4, tbl_shf_table + 16
258 // shift v2 to the left by arg3 bytes
259 tbl v2.16b, {v7.16b}, v0.16b
261 // shift v7 to the right by 16-arg3 bytes
263 eor v0.16b, v0.16b, v9.16b
264 tbl v7.16b, {v7.16b}, v0.16b
267 sshr v0.16b, v0.16b, #7 // convert to 8-bit mask
268 bsl v0.16b, v2.16b, v1.16b
271 pmull v8.1q, v7.1d, v10.1d
272 pmull2 v7.1q, v7.2d, v10.2d
273 eor v7.16b, v7.16b, v8.16b
274 eor v7.16b, v7.16b, v0.16b
277 // compute crc of a 128-bit value
278 ldr q10, rk5 // rk5 and rk6 in xmm10
281 ext v0.16b, vzr.16b, v7.16b, #8
283 pmull v7.1q, v7.1d, v10.1d
284 eor v7.16b, v7.16b, v0.16b
287 ext v0.16b, v7.16b, vzr.16b, #4
288 mov v7.s[3], vzr.s[0]
289 pmull2 v0.1q, v0.2d, v10.2d
290 eor v7.16b, v7.16b, v0.16b
297 pmull v0.1q, v0.1d, v10.1d
298 ext v0.16b, vzr.16b, v0.16b, #12
299 pmull2 v0.1q, v0.2d, v10.2d
300 ext v0.16b, vzr.16b, v0.16b, #12
301 eor v7.16b, v7.16b, v0.16b
305 // scale the result back to 16 bits
313 mov v0.s[3], arg1_low32 // get the initial crc value
315 ldr q7, [arg2], #0x10
316 CPU_LE( rev64 v7.16b, v7.16b )
317 CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 )
318 eor v7.16b, v7.16b, v0.16b // xor the initial crc value
321 b.eq _128_done // exactly 16 left
322 b.lt _less_than_16_left
324 ldr q10, rk1 // rk1 and rk2 in xmm10
326 // update the counter. subtract 32 instead of 16 to save one
327 // instruction from the loop
329 b.ge _16B_reduction_loop
336 adr x0, tbl_shf_table + 16
340 eor v0.16b, v0.16b, v9.16b
341 tbl v7.16b, {v7.16b}, v0.16b
343 ENDPROC(crc_t10dif_pmull)
345 // precomputed constants
346 // these constants are precomputed from the poly:
347 // 0x8bb70000 (0x8bb7 scaled to 32 bits)
350 // rk1 = 2^(32*3) mod Q << 32
351 // rk2 = 2^(32*5) mod Q << 32
352 // rk3 = 2^(32*15) mod Q << 32
353 // rk4 = 2^(32*17) mod Q << 32
354 // rk5 = 2^(32*3) mod Q << 32
355 // rk6 = 2^(32*2) mod Q << 32
356 // rk7 = floor(2^64/Q)
359 rk1: .octa 0x06df0000000000002d56000000000000
360 rk3: .octa 0x7cf50000000000009d9d000000000000
361 rk5: .octa 0x13680000000000002d56000000000000
362 rk7: .octa 0x000000018bb7000000000001f65a57f8
363 rk9: .octa 0xbfd6000000000000ceae000000000000
364 rk11: .octa 0x713c0000000000001e16000000000000
365 rk13: .octa 0x80a6000000000000f7f9000000000000
366 rk15: .octa 0xe658000000000000044c000000000000
367 rk17: .octa 0xa497000000000000ad18000000000000
368 rk19: .octa 0xe7b50000000000006ee3000000000000
371 // use these values for shift constants for the tbl/tbx instruction
372 // different alignments result in values as shown:
373 // DDQ 0x008f8e8d8c8b8a898887868584838281 # shl 15 (16-1) / shr1
374 // DDQ 0x01008f8e8d8c8b8a8988878685848382 # shl 14 (16-3) / shr2
375 // DDQ 0x0201008f8e8d8c8b8a89888786858483 # shl 13 (16-4) / shr3
376 // DDQ 0x030201008f8e8d8c8b8a898887868584 # shl 12 (16-4) / shr4
377 // DDQ 0x04030201008f8e8d8c8b8a8988878685 # shl 11 (16-5) / shr5
378 // DDQ 0x0504030201008f8e8d8c8b8a89888786 # shl 10 (16-6) / shr6
379 // DDQ 0x060504030201008f8e8d8c8b8a898887 # shl 9 (16-7) / shr7
380 // DDQ 0x07060504030201008f8e8d8c8b8a8988 # shl 8 (16-8) / shr8
381 // DDQ 0x0807060504030201008f8e8d8c8b8a89 # shl 7 (16-9) / shr9
382 // DDQ 0x090807060504030201008f8e8d8c8b8a # shl 6 (16-10) / shr10
383 // DDQ 0x0a090807060504030201008f8e8d8c8b # shl 5 (16-11) / shr11
384 // DDQ 0x0b0a090807060504030201008f8e8d8c # shl 4 (16-12) / shr12
385 // DDQ 0x0c0b0a090807060504030201008f8e8d # shl 3 (16-13) / shr13
386 // DDQ 0x0d0c0b0a090807060504030201008f8e # shl 2 (16-14) / shr14
387 // DDQ 0x0e0d0c0b0a090807060504030201008f # shl 1 (16-15) / shr15
389 .byte 0x0, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
390 .byte 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f
391 .byte 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7
392 .byte 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe , 0x0