xref: /linux/arch/x86/include/asm/xor_avx.h (revision ea4d26ae24e58fbd2c61de9242adab053cb982d8)
1*ea4d26aeSJim Kukunas #ifndef _ASM_X86_XOR_AVX_H
2*ea4d26aeSJim Kukunas #define _ASM_X86_XOR_AVX_H
3*ea4d26aeSJim Kukunas 
4*ea4d26aeSJim Kukunas /*
5*ea4d26aeSJim Kukunas  * Optimized RAID-5 checksumming functions for AVX
6*ea4d26aeSJim Kukunas  *
7*ea4d26aeSJim Kukunas  * Copyright (C) 2012 Intel Corporation
8*ea4d26aeSJim Kukunas  * Author: Jim Kukunas <james.t.kukunas@linux.intel.com>
9*ea4d26aeSJim Kukunas  *
10*ea4d26aeSJim Kukunas  * Based on Ingo Molnar and Zach Brown's respective MMX and SSE routines
11*ea4d26aeSJim Kukunas  *
12*ea4d26aeSJim Kukunas  * This program is free software; you can redistribute it and/or
13*ea4d26aeSJim Kukunas  * modify it under the terms of the GNU General Public License
14*ea4d26aeSJim Kukunas  * as published by the Free Software Foundation; version 2
15*ea4d26aeSJim Kukunas  * of the License.
16*ea4d26aeSJim Kukunas  */
17*ea4d26aeSJim Kukunas 
18*ea4d26aeSJim Kukunas #ifdef CONFIG_AS_AVX
19*ea4d26aeSJim Kukunas 
20*ea4d26aeSJim Kukunas #include <linux/compiler.h>
21*ea4d26aeSJim Kukunas #include <asm/i387.h>
22*ea4d26aeSJim Kukunas 
23*ea4d26aeSJim Kukunas #define ALIGN32 __aligned(32)
24*ea4d26aeSJim Kukunas 
25*ea4d26aeSJim Kukunas #define YMM_SAVED_REGS 4
26*ea4d26aeSJim Kukunas 
27*ea4d26aeSJim Kukunas #define YMMS_SAVE \
28*ea4d26aeSJim Kukunas do { \
29*ea4d26aeSJim Kukunas 	preempt_disable(); \
30*ea4d26aeSJim Kukunas 	cr0 = read_cr0(); \
31*ea4d26aeSJim Kukunas 	clts(); \
32*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %%ymm0, %0" : "=m" (ymm_save[0]) : : "memory"); \
33*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %%ymm1, %0" : "=m" (ymm_save[32]) : : "memory"); \
34*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %%ymm2, %0" : "=m" (ymm_save[64]) : : "memory"); \
35*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %%ymm3, %0" : "=m" (ymm_save[96]) : : "memory"); \
36*ea4d26aeSJim Kukunas } while (0);
37*ea4d26aeSJim Kukunas 
38*ea4d26aeSJim Kukunas #define YMMS_RESTORE \
39*ea4d26aeSJim Kukunas do { \
40*ea4d26aeSJim Kukunas 	asm volatile("sfence" : : : "memory"); \
41*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %0, %%ymm3" : : "m" (ymm_save[96])); \
42*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %0, %%ymm2" : : "m" (ymm_save[64])); \
43*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %0, %%ymm1" : : "m" (ymm_save[32])); \
44*ea4d26aeSJim Kukunas 	asm volatile("vmovaps %0, %%ymm0" : : "m" (ymm_save[0])); \
45*ea4d26aeSJim Kukunas 	write_cr0(cr0); \
46*ea4d26aeSJim Kukunas 	preempt_enable(); \
47*ea4d26aeSJim Kukunas } while (0);
48*ea4d26aeSJim Kukunas 
49*ea4d26aeSJim Kukunas #define BLOCK4(i) \
50*ea4d26aeSJim Kukunas 		BLOCK(32 * i, 0) \
51*ea4d26aeSJim Kukunas 		BLOCK(32 * (i + 1), 1) \
52*ea4d26aeSJim Kukunas 		BLOCK(32 * (i + 2), 2) \
53*ea4d26aeSJim Kukunas 		BLOCK(32 * (i + 3), 3)
54*ea4d26aeSJim Kukunas 
55*ea4d26aeSJim Kukunas #define BLOCK16() \
56*ea4d26aeSJim Kukunas 		BLOCK4(0) \
57*ea4d26aeSJim Kukunas 		BLOCK4(4) \
58*ea4d26aeSJim Kukunas 		BLOCK4(8) \
59*ea4d26aeSJim Kukunas 		BLOCK4(12)
60*ea4d26aeSJim Kukunas 
61*ea4d26aeSJim Kukunas static void xor_avx_2(unsigned long bytes, unsigned long *p0, unsigned long *p1)
62*ea4d26aeSJim Kukunas {
63*ea4d26aeSJim Kukunas 	unsigned long cr0, lines = bytes >> 9;
64*ea4d26aeSJim Kukunas 	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
65*ea4d26aeSJim Kukunas 
66*ea4d26aeSJim Kukunas 	YMMS_SAVE
67*ea4d26aeSJim Kukunas 
68*ea4d26aeSJim Kukunas 	while (lines--) {
69*ea4d26aeSJim Kukunas #undef BLOCK
70*ea4d26aeSJim Kukunas #define BLOCK(i, reg) \
71*ea4d26aeSJim Kukunas do { \
72*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p1[i / sizeof(*p1)])); \
73*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm"  #reg : : \
74*ea4d26aeSJim Kukunas 		"m" (p0[i / sizeof(*p0)])); \
75*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
76*ea4d26aeSJim Kukunas 		"=m" (p0[i / sizeof(*p0)])); \
77*ea4d26aeSJim Kukunas } while (0);
78*ea4d26aeSJim Kukunas 
79*ea4d26aeSJim Kukunas 		BLOCK16()
80*ea4d26aeSJim Kukunas 
81*ea4d26aeSJim Kukunas 		p0 = (unsigned long *)((uintptr_t)p0 + 512);
82*ea4d26aeSJim Kukunas 		p1 = (unsigned long *)((uintptr_t)p1 + 512);
83*ea4d26aeSJim Kukunas 	}
84*ea4d26aeSJim Kukunas 
85*ea4d26aeSJim Kukunas 	YMMS_RESTORE
86*ea4d26aeSJim Kukunas }
87*ea4d26aeSJim Kukunas 
88*ea4d26aeSJim Kukunas static void xor_avx_3(unsigned long bytes, unsigned long *p0, unsigned long *p1,
89*ea4d26aeSJim Kukunas 	unsigned long *p2)
90*ea4d26aeSJim Kukunas {
91*ea4d26aeSJim Kukunas 	unsigned long cr0, lines = bytes >> 9;
92*ea4d26aeSJim Kukunas 	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
93*ea4d26aeSJim Kukunas 
94*ea4d26aeSJim Kukunas 	YMMS_SAVE
95*ea4d26aeSJim Kukunas 
96*ea4d26aeSJim Kukunas 	while (lines--) {
97*ea4d26aeSJim Kukunas #undef BLOCK
98*ea4d26aeSJim Kukunas #define BLOCK(i, reg) \
99*ea4d26aeSJim Kukunas do { \
100*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p2[i / sizeof(*p2)])); \
101*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
102*ea4d26aeSJim Kukunas 		"m" (p1[i / sizeof(*p1)])); \
103*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
104*ea4d26aeSJim Kukunas 		"m" (p0[i / sizeof(*p0)])); \
105*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
106*ea4d26aeSJim Kukunas 		"=m" (p0[i / sizeof(*p0)])); \
107*ea4d26aeSJim Kukunas } while (0);
108*ea4d26aeSJim Kukunas 
109*ea4d26aeSJim Kukunas 		BLOCK16()
110*ea4d26aeSJim Kukunas 
111*ea4d26aeSJim Kukunas 		p0 = (unsigned long *)((uintptr_t)p0 + 512);
112*ea4d26aeSJim Kukunas 		p1 = (unsigned long *)((uintptr_t)p1 + 512);
113*ea4d26aeSJim Kukunas 		p2 = (unsigned long *)((uintptr_t)p2 + 512);
114*ea4d26aeSJim Kukunas 	}
115*ea4d26aeSJim Kukunas 
116*ea4d26aeSJim Kukunas 	YMMS_RESTORE
117*ea4d26aeSJim Kukunas }
118*ea4d26aeSJim Kukunas 
119*ea4d26aeSJim Kukunas static void xor_avx_4(unsigned long bytes, unsigned long *p0, unsigned long *p1,
120*ea4d26aeSJim Kukunas 	unsigned long *p2, unsigned long *p3)
121*ea4d26aeSJim Kukunas {
122*ea4d26aeSJim Kukunas 	unsigned long cr0, lines = bytes >> 9;
123*ea4d26aeSJim Kukunas 	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
124*ea4d26aeSJim Kukunas 
125*ea4d26aeSJim Kukunas 	YMMS_SAVE
126*ea4d26aeSJim Kukunas 
127*ea4d26aeSJim Kukunas 	while (lines--) {
128*ea4d26aeSJim Kukunas #undef BLOCK
129*ea4d26aeSJim Kukunas #define BLOCK(i, reg) \
130*ea4d26aeSJim Kukunas do { \
131*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p3[i / sizeof(*p3)])); \
132*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
133*ea4d26aeSJim Kukunas 		"m" (p2[i / sizeof(*p2)])); \
134*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
135*ea4d26aeSJim Kukunas 		"m" (p1[i / sizeof(*p1)])); \
136*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
137*ea4d26aeSJim Kukunas 		"m" (p0[i / sizeof(*p0)])); \
138*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
139*ea4d26aeSJim Kukunas 		"=m" (p0[i / sizeof(*p0)])); \
140*ea4d26aeSJim Kukunas } while (0);
141*ea4d26aeSJim Kukunas 
142*ea4d26aeSJim Kukunas 		BLOCK16();
143*ea4d26aeSJim Kukunas 
144*ea4d26aeSJim Kukunas 		p0 = (unsigned long *)((uintptr_t)p0 + 512);
145*ea4d26aeSJim Kukunas 		p1 = (unsigned long *)((uintptr_t)p1 + 512);
146*ea4d26aeSJim Kukunas 		p2 = (unsigned long *)((uintptr_t)p2 + 512);
147*ea4d26aeSJim Kukunas 		p3 = (unsigned long *)((uintptr_t)p3 + 512);
148*ea4d26aeSJim Kukunas 	}
149*ea4d26aeSJim Kukunas 
150*ea4d26aeSJim Kukunas 	YMMS_RESTORE
151*ea4d26aeSJim Kukunas }
152*ea4d26aeSJim Kukunas 
153*ea4d26aeSJim Kukunas static void xor_avx_5(unsigned long bytes, unsigned long *p0, unsigned long *p1,
154*ea4d26aeSJim Kukunas 	unsigned long *p2, unsigned long *p3, unsigned long *p4)
155*ea4d26aeSJim Kukunas {
156*ea4d26aeSJim Kukunas 	unsigned long cr0, lines = bytes >> 9;
157*ea4d26aeSJim Kukunas 	char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
158*ea4d26aeSJim Kukunas 
159*ea4d26aeSJim Kukunas 	YMMS_SAVE
160*ea4d26aeSJim Kukunas 
161*ea4d26aeSJim Kukunas 	while (lines--) {
162*ea4d26aeSJim Kukunas #undef BLOCK
163*ea4d26aeSJim Kukunas #define BLOCK(i, reg) \
164*ea4d26aeSJim Kukunas do { \
165*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p4[i / sizeof(*p4)])); \
166*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
167*ea4d26aeSJim Kukunas 		"m" (p3[i / sizeof(*p3)])); \
168*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
169*ea4d26aeSJim Kukunas 		"m" (p2[i / sizeof(*p2)])); \
170*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
171*ea4d26aeSJim Kukunas 		"m" (p1[i / sizeof(*p1)])); \
172*ea4d26aeSJim Kukunas 	asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
173*ea4d26aeSJim Kukunas 		"m" (p0[i / sizeof(*p0)])); \
174*ea4d26aeSJim Kukunas 	asm volatile("vmovdqa %%ymm" #reg ", %0" : \
175*ea4d26aeSJim Kukunas 		"=m" (p0[i / sizeof(*p0)])); \
176*ea4d26aeSJim Kukunas } while (0);
177*ea4d26aeSJim Kukunas 
178*ea4d26aeSJim Kukunas 		BLOCK16()
179*ea4d26aeSJim Kukunas 
180*ea4d26aeSJim Kukunas 		p0 = (unsigned long *)((uintptr_t)p0 + 512);
181*ea4d26aeSJim Kukunas 		p1 = (unsigned long *)((uintptr_t)p1 + 512);
182*ea4d26aeSJim Kukunas 		p2 = (unsigned long *)((uintptr_t)p2 + 512);
183*ea4d26aeSJim Kukunas 		p3 = (unsigned long *)((uintptr_t)p3 + 512);
184*ea4d26aeSJim Kukunas 		p4 = (unsigned long *)((uintptr_t)p4 + 512);
185*ea4d26aeSJim Kukunas 	}
186*ea4d26aeSJim Kukunas 
187*ea4d26aeSJim Kukunas 	YMMS_RESTORE
188*ea4d26aeSJim Kukunas }
189*ea4d26aeSJim Kukunas 
190*ea4d26aeSJim Kukunas static struct xor_block_template xor_block_avx = {
191*ea4d26aeSJim Kukunas 	.name = "avx",
192*ea4d26aeSJim Kukunas 	.do_2 = xor_avx_2,
193*ea4d26aeSJim Kukunas 	.do_3 = xor_avx_3,
194*ea4d26aeSJim Kukunas 	.do_4 = xor_avx_4,
195*ea4d26aeSJim Kukunas 	.do_5 = xor_avx_5,
196*ea4d26aeSJim Kukunas };
197*ea4d26aeSJim Kukunas 
198*ea4d26aeSJim Kukunas #define AVX_XOR_SPEED \
199*ea4d26aeSJim Kukunas do { \
200*ea4d26aeSJim Kukunas 	if (cpu_has_avx) \
201*ea4d26aeSJim Kukunas 		xor_speed(&xor_block_avx); \
202*ea4d26aeSJim Kukunas } while (0)
203*ea4d26aeSJim Kukunas 
204*ea4d26aeSJim Kukunas #define AVX_SELECT(FASTEST) \
205*ea4d26aeSJim Kukunas 	(cpu_has_avx ? &xor_block_avx : FASTEST)
206*ea4d26aeSJim Kukunas 
207*ea4d26aeSJim Kukunas #else
208*ea4d26aeSJim Kukunas 
209*ea4d26aeSJim Kukunas #define AVX_XOR_SPEED {}
210*ea4d26aeSJim Kukunas 
211*ea4d26aeSJim Kukunas #define AVX_SELECT(FASTEST) (FASTEST)
212*ea4d26aeSJim Kukunas 
213*ea4d26aeSJim Kukunas #endif
214*ea4d26aeSJim Kukunas #endif
215