1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (C) 2016 Gvozden Nešković. All rights reserved. 24 */ 25 #include <sys/isa_defs.h> 26 27 #if defined(__x86_64) && defined(HAVE_AVX2) 28 29 #include <sys/types.h> 30 #include <sys/simd.h> 31 32 #ifdef __linux__ 33 #define __asm __asm__ __volatile__ 34 #endif 35 36 #define _REG_CNT(_0, _1, _2, _3, _4, _5, _6, _7, N, ...) N 37 #define REG_CNT(r...) _REG_CNT(r, 8, 7, 6, 5, 4, 3, 2, 1) 38 39 #define VR0_(REG, ...) "ymm"#REG 40 #define VR1_(_1, REG, ...) "ymm"#REG 41 #define VR2_(_1, _2, REG, ...) "ymm"#REG 42 #define VR3_(_1, _2, _3, REG, ...) "ymm"#REG 43 #define VR4_(_1, _2, _3, _4, REG, ...) "ymm"#REG 44 #define VR5_(_1, _2, _3, _4, _5, REG, ...) "ymm"#REG 45 #define VR6_(_1, _2, _3, _4, _5, _6, REG, ...) "ymm"#REG 46 #define VR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) "ymm"#REG 47 48 #define VR0(r...) VR0_(r) 49 #define VR1(r...) VR1_(r) 50 #define VR2(r...) VR2_(r, 1) 51 #define VR3(r...) VR3_(r, 1, 2) 52 #define VR4(r...) VR4_(r, 1, 2) 53 #define VR5(r...) VR5_(r, 1, 2, 3) 54 #define VR6(r...) VR6_(r, 1, 2, 3, 4) 55 #define VR7(r...) VR7_(r, 1, 2, 3, 4, 5) 56 57 #define R_01(REG1, REG2, ...) REG1, REG2 58 #define _R_23(_0, _1, REG2, REG3, ...) REG2, REG3 59 #define R_23(REG...) _R_23(REG, 1, 2, 3) 60 61 #define ZFS_ASM_BUG() ASSERT(0) 62 63 extern const uint8_t gf_clmul_mod_lt[4*256][16]; 64 65 #define ELEM_SIZE 32 66 67 typedef struct v { 68 uint8_t b[ELEM_SIZE] __attribute__((aligned(ELEM_SIZE))); 69 } v_t; 70 71 72 #define XOR_ACC(src, r...) \ 73 { \ 74 switch (REG_CNT(r)) { \ 75 case 4: \ 76 __asm( \ 77 "vpxor 0x00(%[SRC]), %%" VR0(r)", %%" VR0(r) "\n" \ 78 "vpxor 0x20(%[SRC]), %%" VR1(r)", %%" VR1(r) "\n" \ 79 "vpxor 0x40(%[SRC]), %%" VR2(r)", %%" VR2(r) "\n" \ 80 "vpxor 0x60(%[SRC]), %%" VR3(r)", %%" VR3(r) "\n" \ 81 : : [SRC] "r" (src)); \ 82 break; \ 83 case 2: \ 84 __asm( \ 85 "vpxor 0x00(%[SRC]), %%" VR0(r)", %%" VR0(r) "\n" \ 86 "vpxor 0x20(%[SRC]), %%" VR1(r)", %%" VR1(r) "\n" \ 87 : : [SRC] "r" (src)); \ 88 break; \ 89 default: \ 90 ZFS_ASM_BUG(); \ 91 } \ 92 } 93 94 #define XOR(r...) \ 95 { \ 96 switch (REG_CNT(r)) { \ 97 case 8: \ 98 __asm( \ 99 "vpxor %" VR0(r) ", %" VR4(r)", %" VR4(r) "\n" \ 100 "vpxor %" VR1(r) ", %" VR5(r)", %" VR5(r) "\n" \ 101 "vpxor %" VR2(r) ", %" VR6(r)", %" VR6(r) "\n" \ 102 "vpxor %" VR3(r) ", %" VR7(r)", %" VR7(r)); \ 103 break; \ 104 case 4: \ 105 __asm( \ 106 "vpxor %" VR0(r) ", %" VR2(r)", %" VR2(r) "\n" \ 107 "vpxor %" VR1(r) ", %" VR3(r)", %" VR3(r)); \ 108 break; \ 109 default: \ 110 ZFS_ASM_BUG(); \ 111 } \ 112 } 113 114 #define ZERO(r...) XOR(r, r) 115 116 #define COPY(r...) \ 117 { \ 118 switch (REG_CNT(r)) { \ 119 case 8: \ 120 __asm( \ 121 "vmovdqa %" VR0(r) ", %" VR4(r) "\n" \ 122 "vmovdqa %" VR1(r) ", %" VR5(r) "\n" \ 123 "vmovdqa %" VR2(r) ", %" VR6(r) "\n" \ 124 "vmovdqa %" VR3(r) ", %" VR7(r)); \ 125 break; \ 126 case 4: \ 127 __asm( \ 128 "vmovdqa %" VR0(r) ", %" VR2(r) "\n" \ 129 "vmovdqa %" VR1(r) ", %" VR3(r)); \ 130 break; \ 131 default: \ 132 ZFS_ASM_BUG(); \ 133 } \ 134 } 135 136 #define LOAD(src, r...) \ 137 { \ 138 switch (REG_CNT(r)) { \ 139 case 4: \ 140 __asm( \ 141 "vmovdqa 0x00(%[SRC]), %%" VR0(r) "\n" \ 142 "vmovdqa 0x20(%[SRC]), %%" VR1(r) "\n" \ 143 "vmovdqa 0x40(%[SRC]), %%" VR2(r) "\n" \ 144 "vmovdqa 0x60(%[SRC]), %%" VR3(r) "\n" \ 145 : : [SRC] "r" (src)); \ 146 break; \ 147 case 2: \ 148 __asm( \ 149 "vmovdqa 0x00(%[SRC]), %%" VR0(r) "\n" \ 150 "vmovdqa 0x20(%[SRC]), %%" VR1(r) "\n" \ 151 : : [SRC] "r" (src)); \ 152 break; \ 153 default: \ 154 ZFS_ASM_BUG(); \ 155 } \ 156 } 157 158 #define STORE(dst, r...) \ 159 { \ 160 switch (REG_CNT(r)) { \ 161 case 4: \ 162 __asm( \ 163 "vmovdqa %%" VR0(r) ", 0x00(%[DST])\n" \ 164 "vmovdqa %%" VR1(r) ", 0x20(%[DST])\n" \ 165 "vmovdqa %%" VR2(r) ", 0x40(%[DST])\n" \ 166 "vmovdqa %%" VR3(r) ", 0x60(%[DST])\n" \ 167 : : [DST] "r" (dst)); \ 168 break; \ 169 case 2: \ 170 __asm( \ 171 "vmovdqa %%" VR0(r) ", 0x00(%[DST])\n" \ 172 "vmovdqa %%" VR1(r) ", 0x20(%[DST])\n" \ 173 : : [DST] "r" (dst)); \ 174 break; \ 175 default: \ 176 ZFS_ASM_BUG(); \ 177 } \ 178 } 179 180 #define FLUSH() \ 181 { \ 182 __asm("vzeroupper"); \ 183 } 184 185 #define MUL2_SETUP() \ 186 { \ 187 __asm("vmovq %0, %%xmm14" :: "r"(0x1d1d1d1d1d1d1d1d)); \ 188 __asm("vpbroadcastq %xmm14, %ymm14"); \ 189 __asm("vpxor %ymm15, %ymm15 ,%ymm15"); \ 190 } 191 192 #define _MUL2(r...) \ 193 { \ 194 switch (REG_CNT(r)) { \ 195 case 2: \ 196 __asm( \ 197 "vpcmpgtb %" VR0(r)", %ymm15, %ymm12\n" \ 198 "vpcmpgtb %" VR1(r)", %ymm15, %ymm13\n" \ 199 "vpaddb %" VR0(r)", %" VR0(r)", %" VR0(r) "\n" \ 200 "vpaddb %" VR1(r)", %" VR1(r)", %" VR1(r) "\n" \ 201 "vpand %ymm14, %ymm12, %ymm12\n" \ 202 "vpand %ymm14, %ymm13, %ymm13\n" \ 203 "vpxor %ymm12, %" VR0(r)", %" VR0(r) "\n" \ 204 "vpxor %ymm13, %" VR1(r)", %" VR1(r)); \ 205 break; \ 206 default: \ 207 ZFS_ASM_BUG(); \ 208 } \ 209 } 210 211 #define MUL2(r...) \ 212 { \ 213 switch (REG_CNT(r)) { \ 214 case 4: \ 215 _MUL2(R_01(r)); \ 216 _MUL2(R_23(r)); \ 217 break; \ 218 case 2: \ 219 _MUL2(r); \ 220 break; \ 221 default: \ 222 ZFS_ASM_BUG(); \ 223 } \ 224 } 225 226 #define MUL4(r...) \ 227 { \ 228 MUL2(r); \ 229 MUL2(r); \ 230 } 231 232 #define _0f "ymm15" 233 #define _as "ymm14" 234 #define _bs "ymm13" 235 #define _ltmod "ymm12" 236 #define _ltmul "ymm11" 237 #define _ta "ymm10" 238 #define _tb "ymm15" 239 240 static const uint8_t __attribute__((aligned(32))) _mul_mask = 0x0F; 241 242 #define _MULx2(c, r...) \ 243 { \ 244 switch (REG_CNT(r)) { \ 245 case 2: \ 246 __asm( \ 247 "vpbroadcastb (%[mask]), %%" _0f "\n" \ 248 /* upper bits */ \ 249 "vbroadcasti128 0x00(%[lt]), %%" _ltmod "\n" \ 250 "vbroadcasti128 0x10(%[lt]), %%" _ltmul "\n" \ 251 \ 252 "vpsraw $0x4, %%" VR0(r) ", %%"_as "\n" \ 253 "vpsraw $0x4, %%" VR1(r) ", %%"_bs "\n" \ 254 "vpand %%" _0f ", %%" VR0(r) ", %%" VR0(r) "\n" \ 255 "vpand %%" _0f ", %%" VR1(r) ", %%" VR1(r) "\n" \ 256 "vpand %%" _0f ", %%" _as ", %%" _as "\n" \ 257 "vpand %%" _0f ", %%" _bs ", %%" _bs "\n" \ 258 \ 259 "vpshufb %%" _as ", %%" _ltmod ", %%" _ta "\n" \ 260 "vpshufb %%" _bs ", %%" _ltmod ", %%" _tb "\n" \ 261 "vpshufb %%" _as ", %%" _ltmul ", %%" _as "\n" \ 262 "vpshufb %%" _bs ", %%" _ltmul ", %%" _bs "\n" \ 263 /* lower bits */ \ 264 "vbroadcasti128 0x20(%[lt]), %%" _ltmod "\n" \ 265 "vbroadcasti128 0x30(%[lt]), %%" _ltmul "\n" \ 266 \ 267 "vpxor %%" _ta ", %%" _as ", %%" _as "\n" \ 268 "vpxor %%" _tb ", %%" _bs ", %%" _bs "\n" \ 269 \ 270 "vpshufb %%" VR0(r) ", %%" _ltmod ", %%" _ta "\n" \ 271 "vpshufb %%" VR1(r) ", %%" _ltmod ", %%" _tb "\n" \ 272 "vpshufb %%" VR0(r) ", %%" _ltmul ", %%" VR0(r) "\n"\ 273 "vpshufb %%" VR1(r) ", %%" _ltmul ", %%" VR1(r) "\n"\ 274 \ 275 "vpxor %%" _ta ", %%" VR0(r) ", %%" VR0(r) "\n" \ 276 "vpxor %%" _as ", %%" VR0(r) ", %%" VR0(r) "\n" \ 277 "vpxor %%" _tb ", %%" VR1(r) ", %%" VR1(r) "\n" \ 278 "vpxor %%" _bs ", %%" VR1(r) ", %%" VR1(r) "\n" \ 279 : : [mask] "r" (&_mul_mask), \ 280 [lt] "r" (gf_clmul_mod_lt[4*(c)])); \ 281 break; \ 282 default: \ 283 ZFS_ASM_BUG(); \ 284 } \ 285 } 286 287 #define MUL(c, r...) \ 288 { \ 289 switch (REG_CNT(r)) { \ 290 case 4: \ 291 _MULx2(c, R_01(r)); \ 292 _MULx2(c, R_23(r)); \ 293 break; \ 294 case 2: \ 295 _MULx2(c, R_01(r)); \ 296 break; \ 297 default: \ 298 ZFS_ASM_BUG(); \ 299 } \ 300 } 301 302 #define raidz_math_begin() kfpu_begin() 303 #define raidz_math_end() \ 304 { \ 305 FLUSH(); \ 306 kfpu_end(); \ 307 } 308 309 310 #define SYN_STRIDE 4 311 312 #define ZERO_STRIDE 4 313 #define ZERO_DEFINE() {} 314 #define ZERO_D 0, 1, 2, 3 315 316 #define COPY_STRIDE 4 317 #define COPY_DEFINE() {} 318 #define COPY_D 0, 1, 2, 3 319 320 #define ADD_STRIDE 4 321 #define ADD_DEFINE() {} 322 #define ADD_D 0, 1, 2, 3 323 324 #define MUL_STRIDE 4 325 #define MUL_DEFINE() {} 326 #define MUL_D 0, 1, 2, 3 327 328 #define GEN_P_STRIDE 4 329 #define GEN_P_DEFINE() {} 330 #define GEN_P_P 0, 1, 2, 3 331 332 #define GEN_PQ_STRIDE 4 333 #define GEN_PQ_DEFINE() {} 334 #define GEN_PQ_D 0, 1, 2, 3 335 #define GEN_PQ_C 4, 5, 6, 7 336 337 #define GEN_PQR_STRIDE 4 338 #define GEN_PQR_DEFINE() {} 339 #define GEN_PQR_D 0, 1, 2, 3 340 #define GEN_PQR_C 4, 5, 6, 7 341 342 #define SYN_Q_DEFINE() {} 343 #define SYN_Q_D 0, 1, 2, 3 344 #define SYN_Q_X 4, 5, 6, 7 345 346 #define SYN_R_DEFINE() {} 347 #define SYN_R_D 0, 1, 2, 3 348 #define SYN_R_X 4, 5, 6, 7 349 350 #define SYN_PQ_DEFINE() {} 351 #define SYN_PQ_D 0, 1, 2, 3 352 #define SYN_PQ_X 4, 5, 6, 7 353 354 #define REC_PQ_STRIDE 2 355 #define REC_PQ_DEFINE() {} 356 #define REC_PQ_X 0, 1 357 #define REC_PQ_Y 2, 3 358 #define REC_PQ_T 4, 5 359 360 #define SYN_PR_DEFINE() {} 361 #define SYN_PR_D 0, 1, 2, 3 362 #define SYN_PR_X 4, 5, 6, 7 363 364 #define REC_PR_STRIDE 2 365 #define REC_PR_DEFINE() {} 366 #define REC_PR_X 0, 1 367 #define REC_PR_Y 2, 3 368 #define REC_PR_T 4, 5 369 370 #define SYN_QR_DEFINE() {} 371 #define SYN_QR_D 0, 1, 2, 3 372 #define SYN_QR_X 4, 5, 6, 7 373 374 #define REC_QR_STRIDE 2 375 #define REC_QR_DEFINE() {} 376 #define REC_QR_X 0, 1 377 #define REC_QR_Y 2, 3 378 #define REC_QR_T 4, 5 379 380 #define SYN_PQR_DEFINE() {} 381 #define SYN_PQR_D 0, 1, 2, 3 382 #define SYN_PQR_X 4, 5, 6, 7 383 384 #define REC_PQR_STRIDE 2 385 #define REC_PQR_DEFINE() {} 386 #define REC_PQR_X 0, 1 387 #define REC_PQR_Y 2, 3 388 #define REC_PQR_Z 4, 5 389 #define REC_PQR_XS 6, 7 390 #define REC_PQR_YS 8, 9 391 392 393 #include <sys/vdev_raidz_impl.h> 394 #include "vdev_raidz_math_impl.h" 395 396 DEFINE_GEN_METHODS(avx2); 397 DEFINE_REC_METHODS(avx2); 398 399 static boolean_t 400 raidz_will_avx2_work(void) 401 { 402 return (kfpu_allowed() && zfs_avx_available() && zfs_avx2_available()); 403 } 404 405 const raidz_impl_ops_t vdev_raidz_avx2_impl = { 406 .init = NULL, 407 .fini = NULL, 408 .gen = RAIDZ_GEN_METHODS(avx2), 409 .rec = RAIDZ_REC_METHODS(avx2), 410 .is_supported = &raidz_will_avx2_work, 411 .name = "avx2" 412 }; 413 414 #endif /* defined(__x86_64) && defined(HAVE_AVX2) */ 415