177fd47e5SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-only 277fd47e5SChristoph Hellwig /* 377fd47e5SChristoph Hellwig * Optimized XOR parity functions for AVX 477fd47e5SChristoph Hellwig * 577fd47e5SChristoph Hellwig * Copyright (C) 2012 Intel Corporation 677fd47e5SChristoph Hellwig * Author: Jim Kukunas <james.t.kukunas@linux.intel.com> 777fd47e5SChristoph Hellwig * 877fd47e5SChristoph Hellwig * Based on Ingo Molnar and Zach Brown's respective MMX and SSE routines 977fd47e5SChristoph Hellwig */ 1077fd47e5SChristoph Hellwig #include <linux/compiler.h> 1177fd47e5SChristoph Hellwig #include <asm/fpu/api.h> 12e20043b4SChristoph Hellwig #include "xor_impl.h" 13e20043b4SChristoph Hellwig #include "xor_arch.h" 1477fd47e5SChristoph Hellwig 1577fd47e5SChristoph Hellwig #define BLOCK4(i) \ 1677fd47e5SChristoph Hellwig BLOCK(32 * i, 0) \ 1777fd47e5SChristoph Hellwig BLOCK(32 * (i + 1), 1) \ 1877fd47e5SChristoph Hellwig BLOCK(32 * (i + 2), 2) \ 1977fd47e5SChristoph Hellwig BLOCK(32 * (i + 3), 3) 2077fd47e5SChristoph Hellwig 2177fd47e5SChristoph Hellwig #define BLOCK16() \ 2277fd47e5SChristoph Hellwig BLOCK4(0) \ 2377fd47e5SChristoph Hellwig BLOCK4(4) \ 2477fd47e5SChristoph Hellwig BLOCK4(8) \ 2577fd47e5SChristoph Hellwig BLOCK4(12) 2677fd47e5SChristoph Hellwig 2777fd47e5SChristoph Hellwig static void xor_avx_2(unsigned long bytes, unsigned long * __restrict p0, 2877fd47e5SChristoph Hellwig const unsigned long * __restrict p1) 2977fd47e5SChristoph Hellwig { 3077fd47e5SChristoph Hellwig unsigned long lines = bytes >> 9; 3177fd47e5SChristoph Hellwig 3277fd47e5SChristoph Hellwig while (lines--) { 3377fd47e5SChristoph Hellwig #undef BLOCK 3477fd47e5SChristoph Hellwig #define BLOCK(i, reg) \ 3577fd47e5SChristoph Hellwig do { \ 3677fd47e5SChristoph Hellwig asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p1[i / sizeof(*p1)])); \ 3777fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 3877fd47e5SChristoph Hellwig "m" (p0[i / sizeof(*p0)])); \ 3977fd47e5SChristoph Hellwig asm volatile("vmovdqa %%ymm" #reg ", %0" : \ 4077fd47e5SChristoph Hellwig "=m" (p0[i / sizeof(*p0)])); \ 4177fd47e5SChristoph Hellwig } while (0); 4277fd47e5SChristoph Hellwig 4377fd47e5SChristoph Hellwig BLOCK16() 4477fd47e5SChristoph Hellwig 4577fd47e5SChristoph Hellwig p0 = (unsigned long *)((uintptr_t)p0 + 512); 4677fd47e5SChristoph Hellwig p1 = (unsigned long *)((uintptr_t)p1 + 512); 4777fd47e5SChristoph Hellwig } 4877fd47e5SChristoph Hellwig } 4977fd47e5SChristoph Hellwig 5077fd47e5SChristoph Hellwig static void xor_avx_3(unsigned long bytes, unsigned long * __restrict p0, 5177fd47e5SChristoph Hellwig const unsigned long * __restrict p1, 5277fd47e5SChristoph Hellwig const unsigned long * __restrict p2) 5377fd47e5SChristoph Hellwig { 5477fd47e5SChristoph Hellwig unsigned long lines = bytes >> 9; 5577fd47e5SChristoph Hellwig 5677fd47e5SChristoph Hellwig while (lines--) { 5777fd47e5SChristoph Hellwig #undef BLOCK 5877fd47e5SChristoph Hellwig #define BLOCK(i, reg) \ 5977fd47e5SChristoph Hellwig do { \ 6077fd47e5SChristoph Hellwig asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p2[i / sizeof(*p2)])); \ 6177fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 6277fd47e5SChristoph Hellwig "m" (p1[i / sizeof(*p1)])); \ 6377fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 6477fd47e5SChristoph Hellwig "m" (p0[i / sizeof(*p0)])); \ 6577fd47e5SChristoph Hellwig asm volatile("vmovdqa %%ymm" #reg ", %0" : \ 6677fd47e5SChristoph Hellwig "=m" (p0[i / sizeof(*p0)])); \ 6777fd47e5SChristoph Hellwig } while (0); 6877fd47e5SChristoph Hellwig 6977fd47e5SChristoph Hellwig BLOCK16() 7077fd47e5SChristoph Hellwig 7177fd47e5SChristoph Hellwig p0 = (unsigned long *)((uintptr_t)p0 + 512); 7277fd47e5SChristoph Hellwig p1 = (unsigned long *)((uintptr_t)p1 + 512); 7377fd47e5SChristoph Hellwig p2 = (unsigned long *)((uintptr_t)p2 + 512); 7477fd47e5SChristoph Hellwig } 7577fd47e5SChristoph Hellwig } 7677fd47e5SChristoph Hellwig 7777fd47e5SChristoph Hellwig static void xor_avx_4(unsigned long bytes, unsigned long * __restrict p0, 7877fd47e5SChristoph Hellwig const unsigned long * __restrict p1, 7977fd47e5SChristoph Hellwig const unsigned long * __restrict p2, 8077fd47e5SChristoph Hellwig const unsigned long * __restrict p3) 8177fd47e5SChristoph Hellwig { 8277fd47e5SChristoph Hellwig unsigned long lines = bytes >> 9; 8377fd47e5SChristoph Hellwig 8477fd47e5SChristoph Hellwig while (lines--) { 8577fd47e5SChristoph Hellwig #undef BLOCK 8677fd47e5SChristoph Hellwig #define BLOCK(i, reg) \ 8777fd47e5SChristoph Hellwig do { \ 8877fd47e5SChristoph Hellwig asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p3[i / sizeof(*p3)])); \ 8977fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 9077fd47e5SChristoph Hellwig "m" (p2[i / sizeof(*p2)])); \ 9177fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 9277fd47e5SChristoph Hellwig "m" (p1[i / sizeof(*p1)])); \ 9377fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 9477fd47e5SChristoph Hellwig "m" (p0[i / sizeof(*p0)])); \ 9577fd47e5SChristoph Hellwig asm volatile("vmovdqa %%ymm" #reg ", %0" : \ 9677fd47e5SChristoph Hellwig "=m" (p0[i / sizeof(*p0)])); \ 9777fd47e5SChristoph Hellwig } while (0); 9877fd47e5SChristoph Hellwig 9977fd47e5SChristoph Hellwig BLOCK16(); 10077fd47e5SChristoph Hellwig 10177fd47e5SChristoph Hellwig p0 = (unsigned long *)((uintptr_t)p0 + 512); 10277fd47e5SChristoph Hellwig p1 = (unsigned long *)((uintptr_t)p1 + 512); 10377fd47e5SChristoph Hellwig p2 = (unsigned long *)((uintptr_t)p2 + 512); 10477fd47e5SChristoph Hellwig p3 = (unsigned long *)((uintptr_t)p3 + 512); 10577fd47e5SChristoph Hellwig } 10677fd47e5SChristoph Hellwig } 10777fd47e5SChristoph Hellwig 10877fd47e5SChristoph Hellwig static void xor_avx_5(unsigned long bytes, unsigned long * __restrict p0, 10977fd47e5SChristoph Hellwig const unsigned long * __restrict p1, 11077fd47e5SChristoph Hellwig const unsigned long * __restrict p2, 11177fd47e5SChristoph Hellwig const unsigned long * __restrict p3, 11277fd47e5SChristoph Hellwig const unsigned long * __restrict p4) 11377fd47e5SChristoph Hellwig { 11477fd47e5SChristoph Hellwig unsigned long lines = bytes >> 9; 11577fd47e5SChristoph Hellwig 11677fd47e5SChristoph Hellwig while (lines--) { 11777fd47e5SChristoph Hellwig #undef BLOCK 11877fd47e5SChristoph Hellwig #define BLOCK(i, reg) \ 11977fd47e5SChristoph Hellwig do { \ 12077fd47e5SChristoph Hellwig asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p4[i / sizeof(*p4)])); \ 12177fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 12277fd47e5SChristoph Hellwig "m" (p3[i / sizeof(*p3)])); \ 12377fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 12477fd47e5SChristoph Hellwig "m" (p2[i / sizeof(*p2)])); \ 12577fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 12677fd47e5SChristoph Hellwig "m" (p1[i / sizeof(*p1)])); \ 12777fd47e5SChristoph Hellwig asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \ 12877fd47e5SChristoph Hellwig "m" (p0[i / sizeof(*p0)])); \ 12977fd47e5SChristoph Hellwig asm volatile("vmovdqa %%ymm" #reg ", %0" : \ 13077fd47e5SChristoph Hellwig "=m" (p0[i / sizeof(*p0)])); \ 13177fd47e5SChristoph Hellwig } while (0); 13277fd47e5SChristoph Hellwig 13377fd47e5SChristoph Hellwig BLOCK16() 13477fd47e5SChristoph Hellwig 13577fd47e5SChristoph Hellwig p0 = (unsigned long *)((uintptr_t)p0 + 512); 13677fd47e5SChristoph Hellwig p1 = (unsigned long *)((uintptr_t)p1 + 512); 13777fd47e5SChristoph Hellwig p2 = (unsigned long *)((uintptr_t)p2 + 512); 13877fd47e5SChristoph Hellwig p3 = (unsigned long *)((uintptr_t)p3 + 512); 13977fd47e5SChristoph Hellwig p4 = (unsigned long *)((uintptr_t)p4 + 512); 14077fd47e5SChristoph Hellwig } 141*80dcf0a7SChristoph Hellwig } 14277fd47e5SChristoph Hellwig 143*80dcf0a7SChristoph Hellwig DO_XOR_BLOCKS(avx_inner, xor_avx_2, xor_avx_3, xor_avx_4, xor_avx_5); 144*80dcf0a7SChristoph Hellwig 145*80dcf0a7SChristoph Hellwig static void xor_gen_avx(void *dest, void **srcs, unsigned int src_cnt, 146*80dcf0a7SChristoph Hellwig unsigned int bytes) 147*80dcf0a7SChristoph Hellwig { 148*80dcf0a7SChristoph Hellwig kernel_fpu_begin(); 149*80dcf0a7SChristoph Hellwig xor_gen_avx_inner(dest, srcs, src_cnt, bytes); 15077fd47e5SChristoph Hellwig kernel_fpu_end(); 15177fd47e5SChristoph Hellwig } 15277fd47e5SChristoph Hellwig 15377fd47e5SChristoph Hellwig struct xor_block_template xor_block_avx = { 15477fd47e5SChristoph Hellwig .name = "avx", 155*80dcf0a7SChristoph Hellwig .xor_gen = xor_gen_avx, 15677fd47e5SChristoph Hellwig }; 157