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