xref: /linux/lib/raid/xor/x86/xor-avx.c (revision 440d6635b20037bc9ad46b20817d7b61cef0fc1b)
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