// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2013 Andrea Mazzoleni #include "internal.h" #include "gf.h" #include "cpu.h" #ifdef CONFIG_X86 /* ================================================================ * Optimizations notes * ================================================================ * * For x86 optimizations you can see: * * Software optimization resources * http://www.agner.org/optimize/ * * x86, x64 Instruction Latency, Memory Latency and CPUID dumps * http://users.atw.hu/instlatx64/ * * Optimization notes: * - Cache Line Sizing: Intentionally don't process more than 64 bytes * because 64 is the typical cache block. Processing 128 bytes or more * doesn't increase performance, and in some cases it even decreases it. * - Register Pressure: Processing exactly 64 bytes perfectly balances * the SIMD register file. It allows 128-bit architectures (SSE/NEON) * to hold 4 data vectors while keeping all necessary GF constants and * masks in the remaining registers, avoiding slow stack spills. * - Write-Combining Buffers: The final write of the P,Q,R,S,T parities * always uses non-temporal stores (movntdq), even for writes smaller * than the cache line, as the CPU has enough write-combining buffers * to aggregate the sequential streams and avoid the RFO (Read-For-Ownership) * memory penalty. * - Parity Accumulator Locality: The outer loop iterates by block size, * and the inner loop iterates by disk. This guarantees that the running * parity accumulators never leave the CPU's SIMD registers during the * computation. * - D0 Cauchy Bypass: The final disk processed (D0) always has a * coefficient of 1 for all parities. It is handled separately to bypass * the expensive Cauchy matrix lookup and `pshufb` multiplications. * - Pipeline Dependency Breaking: Galois Field doubling (Horner's method * multiplication by 2) is strategically placed relative to the XOR * operations to break serial dependency chains. This allows the CPU's * out-of-order execution engine to hide the latency of the GF math * behind memory loads. */ /* * ================================================================ * RAID Parity Generation: Q-Parity Horner's Method Implementations * ================================================================ * * This file implements different strategies for computing the Q parity. * Q parity requires scaling each data disk by a descending power of the * primitive generator g (g=2 for RAID_MODE_CAUCHY_RAID, g=3 for * RAID_MODE_CAUCHY_AES) in the Galois Field: * * Q = (D_l * g^l) + (D_{l-1} * g^{l-1}) + ... + (D_1 * g^1) + (D_0 * 1) * * To efficiently calculate this sequentially using SIMD instructions, we * use Horner's method. Depending on hardware architecture and whether we * need to optimize out the final Cauchy matrix multiplication for D0, the * scaling operation can be positioned in distinct ways: * * ------------------------------------------------------------------------- * CASE 1: Multiplication BEFORE XOR, handling all disks inside the loop * ------------------------------------------------------------------------- * Used in GEN2 where all disks can be processed uniformly. * The accumulator is scaled by the active generator BEFORE adding the current disk. * Because the loop runs all the way down to D0 (d >= 0), the final disk is XORed * into the accumulator and the loop terminates. This naturally leaves D0 with * a coefficient of 1, as it escapes the scaling step. * * Simplified Code: * Q = D_l; * for (d = l - 1; d >= 0; --d) { * Q = Q * g; // Scale accumulator by active generator * Q = Q ^ D_d; // Add current disk * } * * ------------------------------------------------------------------------- * CASE 2: Multiplication BEFORE XOR, handling D0 separately * ------------------------------------------------------------------------- * Used in GEN3/GEN4 when the loop contains expensive operations (like * SSSE3 pshufb for Cauchy matrices) that we want to skip for the very * last disk (which only requires coefficient 1). The Q-parity logic is * identical to CASE 1, but the final iteration for D0 is unrolled. * * Simplified Code: * Q = D_l; * for (d = l - 1; d > 0; --d) { * Q = Q * g; // Scale accumulator by active generator * Q = Q ^ D_d; // Add current disk * } * * // Final disk (D0) processed outside the loop to skip Cauchy math * Q = Q * g; * Q = Q ^ D_0; */ /* * Generate one parity block (RAID5 with XOR) using SSE2 implementation. * * Uses 64-byte chunks across four 16-byte XMM vectors. */ static __always_inline void raid_gen1_sse2_gen(int nd, size_t size, void **vv, int streaming) { uint8_t **v = (uint8_t **)vv; uint8_t *p; int d, l; size_t i; l = nd - 1; p = v[nd]; raid_sse_begin(); for (i = 0; i < size; i += 64) { asm volatile ("movdqa %0,%%xmm0" : : "m" (v[0][i])); asm volatile ("movdqa %0,%%xmm1" : : "m" (v[0][i + 16])); asm volatile ("movdqa %0,%%xmm2" : : "m" (v[0][i + 32])); asm volatile ("movdqa %0,%%xmm3" : : "m" (v[0][i + 48])); for (d = 1; d <= l; ++d) { asm volatile ("pxor %0,%%xmm0" : : "m" (v[d][i])); asm volatile ("pxor %0,%%xmm1" : : "m" (v[d][i + 16])); asm volatile ("pxor %0,%%xmm2" : : "m" (v[d][i + 32])); asm volatile ("pxor %0,%%xmm3" : : "m" (v[d][i + 48])); } if (streaming) { asm volatile ("movntdq %%xmm0,%0" : "=m" (p[i])); asm volatile ("movntdq %%xmm1,%0" : "=m" (p[i + 16])); asm volatile ("movntdq %%xmm2,%0" : "=m" (p[i + 32])); asm volatile ("movntdq %%xmm3,%0" : "=m" (p[i + 48])); } else { asm volatile ("movdqa %%xmm0,%0" : "=m" (p[i])); asm volatile ("movdqa %%xmm1,%0" : "=m" (p[i + 16])); asm volatile ("movdqa %%xmm2,%0" : "=m" (p[i + 32])); asm volatile ("movdqa %%xmm3,%0" : "=m" (p[i + 48])); } } raid_sse_end(streaming); } /* * Generate two parity blocks (RAID6 with Cauchy matrix) using SSE2 implementation. */ static __always_inline void raid_gen2_sse2_gen(int nd, size_t size, void **vv, int generator, int streaming) { uint8_t **v = (uint8_t **)vv; uint8_t *p; uint8_t *q; int d, l; size_t i; l = nd - 1; p = v[nd]; q = v[nd + 1]; raid_sse_begin(); asm volatile ("movdqa %0,%%xmm7" : : "m" (gfconst16.poly)); for (i = 0; i < size; i += 32) { asm volatile ("movdqa %0,%%xmm0" : : "m" (v[l][i])); asm volatile ("movdqa %0,%%xmm1" : : "m" (v[l][i + 16])); asm volatile ("movdqa %xmm0,%xmm2"); asm volatile ("movdqa %xmm1,%xmm3"); for (d = l - 1; d >= 0; --d) { /* scale Q by the active generator before adding the current disk */ if (generator == 3) { asm volatile ("movdqa %xmm2,%xmm4"); asm volatile ("movdqa %xmm3,%xmm5"); asm volatile ("pxor %xmm6,%xmm6"); asm volatile ("pcmpgtb %xmm4,%xmm6"); asm volatile ("paddb %xmm2,%xmm2"); asm volatile ("paddb %xmm3,%xmm3"); asm volatile ("pxor %xmm4,%xmm2"); asm volatile ("pxor %xmm4,%xmm4"); asm volatile ("pcmpgtb %xmm5,%xmm4"); asm volatile ("pand %xmm7,%xmm6"); asm volatile ("pand %xmm7,%xmm4"); asm volatile ("pxor %xmm6,%xmm2"); asm volatile ("pxor %xmm4,%xmm3"); asm volatile ("pxor %xmm5,%xmm3"); } else { asm volatile ("pxor %xmm4,%xmm4"); asm volatile ("pxor %xmm5,%xmm5"); asm volatile ("pcmpgtb %xmm2,%xmm4"); asm volatile ("pcmpgtb %xmm3,%xmm5"); asm volatile ("paddb %xmm2,%xmm2"); asm volatile ("paddb %xmm3,%xmm3"); asm volatile ("pand %xmm7,%xmm4"); asm volatile ("pand %xmm7,%xmm5"); asm volatile ("pxor %xmm4,%xmm2"); asm volatile ("pxor %xmm5,%xmm3"); } asm volatile ("movdqa %0,%%xmm4" : : "m" (v[d][i])); asm volatile ("movdqa %0,%%xmm5" : : "m" (v[d][i + 16])); asm volatile ("pxor %xmm4,%xmm0"); asm volatile ("pxor %xmm5,%xmm1"); asm volatile ("pxor %xmm4,%xmm2"); asm volatile ("pxor %xmm5,%xmm3"); } if (streaming) { asm volatile ("movntdq %%xmm0,%0" : "=m" (p[i])); asm volatile ("movntdq %%xmm1,%0" : "=m" (p[i + 16])); asm volatile ("movntdq %%xmm2,%0" : "=m" (q[i])); asm volatile ("movntdq %%xmm3,%0" : "=m" (q[i + 16])); } else { asm volatile ("movdqa %%xmm0,%0" : "=m" (p[i])); asm volatile ("movdqa %%xmm1,%0" : "=m" (p[i + 16])); asm volatile ("movdqa %%xmm2,%0" : "=m" (q[i])); asm volatile ("movdqa %%xmm3,%0" : "=m" (q[i + 16])); } } raid_sse_end(streaming); } #ifdef CONFIG_X86_64 /* * Generate two parity blocks (RAID6 with Cauchy matrix) using SSE2 extended implementation. * * Uses the extended register set (16 XMM registers), unrolling 64-byte chunks * across four 16-byte lanes and processing two disks per iteration. * * Note that it uses 16 registers, meaning that x64 is required. */ static __always_inline void raid_gen2_sse2ext_gen(int nd, size_t size, void **vv, int generator, int streaming) { uint8_t **v = (uint8_t **)vv; uint8_t *p; uint8_t *q; int d, l; size_t i; l = nd - 1; p = v[nd]; q = v[nd + 1]; raid_sse_begin(); asm volatile ("movdqa %0,%%xmm15" : : "m" (gfconst16.poly)); for (i = 0; i < size; i += 64) { asm volatile ("movdqa %0,%%xmm0" : : "m" (v[l][i])); asm volatile ("movdqa %0,%%xmm1" : : "m" (v[l][i + 16])); asm volatile ("movdqa %0,%%xmm2" : : "m" (v[l][i + 32])); asm volatile ("movdqa %0,%%xmm3" : : "m" (v[l][i + 48])); asm volatile ("movdqa %xmm0,%xmm4"); asm volatile ("movdqa %xmm1,%xmm5"); asm volatile ("movdqa %xmm2,%xmm6"); asm volatile ("movdqa %xmm3,%xmm7"); /* process two disks per iteration */ for (d = l - 1; d >= 1; d -= 2) { /* lane 0 */ asm volatile ("movdqa %0,%%xmm8" : : "m" (v[d][i])); asm volatile ("movdqa %0,%%xmm9" : : "m" (v[d - 1][i])); if (generator == 3) asm volatile ("movdqa %xmm4,%xmm10"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm4,%xmm11"); asm volatile ("paddb %xmm4,%xmm4"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm4"); asm volatile ("pxor %xmm8,%xmm4"); asm volatile ("pxor %xmm9,%xmm8"); asm volatile ("pxor %xmm8,%xmm0"); if (generator == 3) asm volatile ("pxor %xmm10,%xmm8"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm4,%xmm11"); asm volatile ("paddb %xmm4,%xmm4"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm4"); if (generator == 3) asm volatile ("pxor %xmm8,%xmm4"); else asm volatile ("pxor %xmm9,%xmm4"); /* lane 1 */ asm volatile ("movdqa %0,%%xmm8" : : "m" (v[d][i + 16])); asm volatile ("movdqa %0,%%xmm9" : : "m" (v[d - 1][i + 16])); if (generator == 3) asm volatile ("movdqa %xmm5,%xmm10"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm5,%xmm11"); asm volatile ("paddb %xmm5,%xmm5"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm5"); asm volatile ("pxor %xmm8,%xmm5"); asm volatile ("pxor %xmm9,%xmm8"); asm volatile ("pxor %xmm8,%xmm1"); if (generator == 3) asm volatile ("pxor %xmm10,%xmm8"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm5,%xmm11"); asm volatile ("paddb %xmm5,%xmm5"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm5"); if (generator == 3) asm volatile ("pxor %xmm8,%xmm5"); else asm volatile ("pxor %xmm9,%xmm5"); /* lane 2 */ asm volatile ("movdqa %0,%%xmm8" : : "m" (v[d][i + 32])); asm volatile ("movdqa %0,%%xmm9" : : "m" (v[d - 1][i + 32])); if (generator == 3) asm volatile ("movdqa %xmm6,%xmm10"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm6,%xmm11"); asm volatile ("paddb %xmm6,%xmm6"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm6"); asm volatile ("pxor %xmm8,%xmm6"); asm volatile ("pxor %xmm9,%xmm8"); asm volatile ("pxor %xmm8,%xmm2"); if (generator == 3) asm volatile ("pxor %xmm10,%xmm8"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm6,%xmm11"); asm volatile ("paddb %xmm6,%xmm6"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm6"); if (generator == 3) asm volatile ("pxor %xmm8,%xmm6"); else asm volatile ("pxor %xmm9,%xmm6"); /* lane 3 */ asm volatile ("movdqa %0,%%xmm8" : : "m" (v[d][i + 48])); asm volatile ("movdqa %0,%%xmm9" : : "m" (v[d - 1][i + 48])); if (generator == 3) asm volatile ("movdqa %xmm7,%xmm10"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm7,%xmm11"); asm volatile ("paddb %xmm7,%xmm7"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm7"); asm volatile ("pxor %xmm8,%xmm7"); asm volatile ("pxor %xmm9,%xmm8"); asm volatile ("pxor %xmm8,%xmm3"); if (generator == 3) asm volatile ("pxor %xmm10,%xmm8"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm7,%xmm11"); asm volatile ("paddb %xmm7,%xmm7"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm11,%xmm7"); if (generator == 3) asm volatile ("pxor %xmm8,%xmm7"); else asm volatile ("pxor %xmm9,%xmm7"); } /* single remaining disk */ if (d == 0) { if (generator == 3) { asm volatile ("movdqa %xmm4,%xmm8"); asm volatile ("movdqa %xmm5,%xmm9"); asm volatile ("movdqa %xmm6,%xmm10"); asm volatile ("movdqa %xmm7,%xmm11"); asm volatile ("pxor %xmm12,%xmm12"); asm volatile ("pxor %xmm13,%xmm13"); asm volatile ("pxor %xmm14,%xmm14"); asm volatile ("pcmpgtb %xmm8,%xmm12"); asm volatile ("pcmpgtb %xmm9,%xmm13"); asm volatile ("pcmpgtb %xmm10,%xmm14"); asm volatile ("paddb %xmm4,%xmm4"); asm volatile ("paddb %xmm5,%xmm5"); asm volatile ("paddb %xmm6,%xmm6"); asm volatile ("paddb %xmm7,%xmm7"); asm volatile ("pxor %xmm8,%xmm4"); asm volatile ("pxor %xmm8,%xmm8"); asm volatile ("pcmpgtb %xmm11,%xmm8"); asm volatile ("pand %xmm15,%xmm12"); asm volatile ("pand %xmm15,%xmm13"); asm volatile ("pand %xmm15,%xmm14"); asm volatile ("pand %xmm15,%xmm8"); asm volatile ("pxor %xmm12,%xmm4"); asm volatile ("pxor %xmm13,%xmm5"); asm volatile ("pxor %xmm14,%xmm6"); asm volatile ("pxor %xmm8,%xmm7"); asm volatile ("pxor %xmm9,%xmm5"); asm volatile ("pxor %xmm10,%xmm6"); asm volatile ("pxor %xmm11,%xmm7"); } else { asm volatile ("pxor %xmm8,%xmm8"); asm volatile ("pxor %xmm9,%xmm9"); asm volatile ("pxor %xmm10,%xmm10"); asm volatile ("pxor %xmm11,%xmm11"); asm volatile ("pcmpgtb %xmm4,%xmm8"); asm volatile ("pcmpgtb %xmm5,%xmm9"); asm volatile ("pcmpgtb %xmm6,%xmm10"); asm volatile ("pcmpgtb %xmm7,%xmm11"); asm volatile ("paddb %xmm4,%xmm4"); asm volatile ("paddb %xmm5,%xmm5"); asm volatile ("paddb %xmm6,%xmm6"); asm volatile ("paddb %xmm7,%xmm7"); asm volatile ("pand %xmm15,%xmm8"); asm volatile ("pand %xmm15,%xmm9"); asm volatile ("pand %xmm15,%xmm10"); asm volatile ("pand %xmm15,%xmm11"); asm volatile ("pxor %xmm8,%xmm4"); asm volatile ("pxor %xmm9,%xmm5"); asm volatile ("pxor %xmm10,%xmm6"); asm volatile ("pxor %xmm11,%xmm7"); } asm volatile ("movdqa %0,%%xmm8" : : "m" (v[0][i])); asm volatile ("movdqa %0,%%xmm9" : : "m" (v[0][i + 16])); asm volatile ("movdqa %0,%%xmm10" : : "m" (v[0][i + 32])); asm volatile ("movdqa %0,%%xmm11" : : "m" (v[0][i + 48])); asm volatile ("pxor %xmm8,%xmm0"); asm volatile ("pxor %xmm9,%xmm1"); asm volatile ("pxor %xmm10,%xmm2"); asm volatile ("pxor %xmm11,%xmm3"); asm volatile ("pxor %xmm8,%xmm4"); asm volatile ("pxor %xmm9,%xmm5"); asm volatile ("pxor %xmm10,%xmm6"); asm volatile ("pxor %xmm11,%xmm7"); } if (streaming) { asm volatile ("movntdq %%xmm0,%0" : "=m" (p[i])); asm volatile ("movntdq %%xmm1,%0" : "=m" (p[i + 16])); asm volatile ("movntdq %%xmm2,%0" : "=m" (p[i + 32])); asm volatile ("movntdq %%xmm3,%0" : "=m" (p[i + 48])); asm volatile ("movntdq %%xmm4,%0" : "=m" (q[i])); asm volatile ("movntdq %%xmm5,%0" : "=m" (q[i + 16])); asm volatile ("movntdq %%xmm6,%0" : "=m" (q[i + 32])); asm volatile ("movntdq %%xmm7,%0" : "=m" (q[i + 48])); } else { asm volatile ("movdqa %%xmm0,%0" : "=m" (p[i])); asm volatile ("movdqa %%xmm1,%0" : "=m" (p[i + 16])); asm volatile ("movdqa %%xmm2,%0" : "=m" (p[i + 32])); asm volatile ("movdqa %%xmm3,%0" : "=m" (p[i + 48])); asm volatile ("movdqa %%xmm4,%0" : "=m" (q[i])); asm volatile ("movdqa %%xmm5,%0" : "=m" (q[i + 16])); asm volatile ("movdqa %%xmm6,%0" : "=m" (q[i + 32])); asm volatile ("movdqa %%xmm7,%0" : "=m" (q[i + 48])); } } raid_sse_end(streaming); } #endif /* * Generate three parity blocks with powers of 2^-1 using SSE2 implementation. */ static __always_inline void raid_genz_sse2_gen(int nd, size_t size, void **vv, int streaming) { uint8_t **v = (uint8_t **)vv; uint8_t *p; uint8_t *q; uint8_t *r; int d, l; size_t i; l = nd - 1; p = v[nd]; q = v[nd + 1]; r = v[nd + 2]; raid_sse_begin(); asm volatile ("movdqa %0,%%xmm7" : : "m" (gfconst16.poly)); asm volatile ("movdqa %0,%%xmm3" : : "m" (gfconst16.half)); asm volatile ("movdqa %0,%%xmm6" : : "m" (gfconst16.low7)); for (i = 0; i < size; i += 16) { asm volatile ("movdqa %0,%%xmm0" : : "m" (v[l][i])); asm volatile ("movdqa %xmm0,%xmm1"); asm volatile ("movdqa %xmm0,%xmm2"); for (d = l - 1; d >= 0; --d) { asm volatile ("pxor %xmm4,%xmm4"); asm volatile ("pcmpgtb %xmm1,%xmm4"); asm volatile ("paddb %xmm1,%xmm1"); asm volatile ("pand %xmm7,%xmm4"); asm volatile ("pxor %xmm4,%xmm1"); asm volatile ("movdqa %xmm2,%xmm4"); asm volatile ("pxor %xmm5,%xmm5"); asm volatile ("psllw $7,%xmm4"); asm volatile ("psrlw $1,%xmm2"); asm volatile ("pcmpgtb %xmm4,%xmm5"); asm volatile ("pand %xmm6,%xmm2"); asm volatile ("pand %xmm3,%xmm5"); asm volatile ("pxor %xmm5,%xmm2"); asm volatile ("movdqa %0,%%xmm4" : : "m" (v[d][i])); asm volatile ("pxor %xmm4,%xmm0"); asm volatile ("pxor %xmm4,%xmm1"); asm volatile ("pxor %xmm4,%xmm2"); } if (streaming) { asm volatile ("movntdq %%xmm0,%0" : "=m" (p[i])); asm volatile ("movntdq %%xmm1,%0" : "=m" (q[i])); asm volatile ("movntdq %%xmm2,%0" : "=m" (r[i])); } else { asm volatile ("movdqa %%xmm0,%0" : "=m" (p[i])); asm volatile ("movdqa %%xmm1,%0" : "=m" (q[i])); asm volatile ("movdqa %%xmm2,%0" : "=m" (r[i])); } } raid_sse_end(streaming); } #ifdef CONFIG_X86_64 /* * Generate three parity blocks with powers of 2^-1 using SSE2 extended implementation. * * Note that it uses 16 registers, meaning that x64 is required. */ static __always_inline void raid_genz_sse2ext_gen(int nd, size_t size, void **vv, int streaming) { uint8_t **v = (uint8_t **)vv; uint8_t *p; uint8_t *q; uint8_t *r; int d, l; size_t i; l = nd - 1; p = v[nd]; q = v[nd + 1]; r = v[nd + 2]; raid_sse_begin(); asm volatile ("movdqa %0,%%xmm7" : : "m" (gfconst16.poly)); asm volatile ("movdqa %0,%%xmm3" : : "m" (gfconst16.half)); asm volatile ("movdqa %0,%%xmm11" : : "m" (gfconst16.low7)); for (i = 0; i < size; i += 32) { asm volatile ("movdqa %0,%%xmm0" : : "m" (v[l][i])); asm volatile ("movdqa %0,%%xmm8" : : "m" (v[l][i + 16])); asm volatile ("movdqa %xmm0,%xmm1"); asm volatile ("movdqa %xmm8,%xmm9"); asm volatile ("movdqa %xmm0,%xmm2"); asm volatile ("movdqa %xmm8,%xmm10"); for (d = l - 1; d >= 0; --d) { asm volatile ("movdqa %xmm2,%xmm6"); asm volatile ("movdqa %xmm10,%xmm14"); asm volatile ("pxor %xmm4,%xmm4"); asm volatile ("pxor %xmm12,%xmm12"); asm volatile ("pxor %xmm5,%xmm5"); asm volatile ("pxor %xmm13,%xmm13"); asm volatile ("psllw $7,%xmm6"); asm volatile ("psllw $7,%xmm14"); asm volatile ("psrlw $1,%xmm2"); asm volatile ("psrlw $1,%xmm10"); asm volatile ("pcmpgtb %xmm1,%xmm4"); asm volatile ("pcmpgtb %xmm9,%xmm12"); asm volatile ("pcmpgtb %xmm6,%xmm5"); asm volatile ("pcmpgtb %xmm14,%xmm13"); asm volatile ("paddb %xmm1,%xmm1"); asm volatile ("paddb %xmm9,%xmm9"); asm volatile ("pand %xmm11,%xmm2"); asm volatile ("pand %xmm11,%xmm10"); asm volatile ("pand %xmm7,%xmm4"); asm volatile ("pand %xmm7,%xmm12"); asm volatile ("pand %xmm3,%xmm5"); asm volatile ("pand %xmm3,%xmm13"); asm volatile ("pxor %xmm4,%xmm1"); asm volatile ("pxor %xmm12,%xmm9"); asm volatile ("pxor %xmm5,%xmm2"); asm volatile ("pxor %xmm13,%xmm10"); asm volatile ("movdqa %0,%%xmm4" : : "m" (v[d][i])); asm volatile ("movdqa %0,%%xmm12" : : "m" (v[d][i + 16])); asm volatile ("pxor %xmm4,%xmm0"); asm volatile ("pxor %xmm4,%xmm1"); asm volatile ("pxor %xmm4,%xmm2"); asm volatile ("pxor %xmm12,%xmm8"); asm volatile ("pxor %xmm12,%xmm9"); asm volatile ("pxor %xmm12,%xmm10"); } if (streaming) { asm volatile ("movntdq %%xmm0,%0" : "=m" (p[i])); asm volatile ("movntdq %%xmm8,%0" : "=m" (p[i + 16])); asm volatile ("movntdq %%xmm1,%0" : "=m" (q[i])); asm volatile ("movntdq %%xmm9,%0" : "=m" (q[i + 16])); asm volatile ("movntdq %%xmm2,%0" : "=m" (r[i])); asm volatile ("movntdq %%xmm10,%0" : "=m" (r[i + 16])); } else { asm volatile ("movdqa %%xmm0,%0" : "=m" (p[i])); asm volatile ("movdqa %%xmm8,%0" : "=m" (p[i + 16])); asm volatile ("movdqa %%xmm1,%0" : "=m" (q[i])); asm volatile ("movdqa %%xmm9,%0" : "=m" (q[i + 16])); asm volatile ("movdqa %%xmm2,%0" : "=m" (r[i])); asm volatile ("movdqa %%xmm10,%0" : "=m" (r[i + 16])); } } raid_sse_end(streaming); } #endif void raid_gen1_sse2(int nd, size_t size, void **vv, int streaming) { if (streaming) raid_gen1_sse2_gen(nd, size, vv, 1); else raid_gen1_sse2_gen(nd, size, vv, 0); } void raid_gen2_sse2_raid(int nd, size_t size, void **vv, int streaming) { if (streaming) raid_gen2_sse2_gen(nd, size, vv, 2, 1); else raid_gen2_sse2_gen(nd, size, vv, 2, 0); } void raid_gen2_sse2_aes(int nd, size_t size, void **vv, int streaming) { if (streaming) raid_gen2_sse2_gen(nd, size, vv, 3, 1); else raid_gen2_sse2_gen(nd, size, vv, 3, 0); } void raid_genz_sse2_raid(int nd, size_t size, void **vv, int streaming) { if (streaming) raid_genz_sse2_gen(nd, size, vv, 1); else raid_genz_sse2_gen(nd, size, vv, 0); } #ifdef CONFIG_X86_64 void raid_gen2_sse2ext_raid(int nd, size_t size, void **vv, int streaming) { if (streaming) raid_gen2_sse2ext_gen(nd, size, vv, 2, 1); else raid_gen2_sse2ext_gen(nd, size, vv, 2, 0); } void raid_gen2_sse2ext_aes(int nd, size_t size, void **vv, int streaming) { if (streaming) raid_gen2_sse2ext_gen(nd, size, vv, 3, 1); else raid_gen2_sse2ext_gen(nd, size, vv, 3, 0); } void raid_genz_sse2ext_raid(int nd, size_t size, void **vv, int streaming) { if (streaming) raid_genz_sse2ext_gen(nd, size, vv, 1); else raid_genz_sse2ext_gen(nd, size, vv, 0); } #endif void raid_register_sse2(void) { if (raid_cpu_has_sse2()) { raid_gen_register(RAID_ALGO_CAUCHY_PAR1, "sse2", raid_gen1_sse2, RAID_POLY_ANY); raid_gen_register(RAID_ALGO_CAUCHY_PAR2, "sse2", raid_gen2_sse2_raid, RAID_POLY_RAID); raid_gen_register(RAID_ALGO_CAUCHY_PAR2, "sse2", raid_gen2_sse2_aes, RAID_POLY_AES); #ifdef CONFIG_X86_64 if (!raid_cpu_has_slow_extendedreg()) { raid_gen_register(RAID_ALGO_CAUCHY_PAR2, "sse2e", raid_gen2_sse2ext_raid, RAID_POLY_RAID); raid_gen_register(RAID_ALGO_CAUCHY_PAR2, "sse2e", raid_gen2_sse2ext_aes, RAID_POLY_AES); } /* note that raid_cpu_has_slow_extendedreg() doesn't affect vandermonde */ raid_gen_register(RAID_ALGO_VANDERMONDE_PAR3, "sse2e", raid_genz_sse2ext_raid, RAID_POLY_RAID); #else raid_gen_register(RAID_ALGO_VANDERMONDE_PAR3, "sse2", raid_genz_sse2_raid, RAID_POLY_RAID); #endif } } #endif