2017-08-04 06:42:32 +03:00
/ *
* Copyright 2017 , Matt Brown , IBM Corp .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* vpermxor$ # . c
*
* Based on H . Peter Anvin ' s paper - The mathematics of RAID - 6
*
* $ # - way unrolled portable integer math RAID - 6 instruction set
* This file is postprocessed using unroll . awk
*
* vpermxor$ # . c makes use of the vpermxor instruction to optimise the RAID6 Q
* syndrome calculations .
* This can be run on systems which have both Altivec and vpermxor instruction .
*
* This instruction was introduced in POWER8 - ISA v2 . 07.
* /
# include < linux / raid / pq . h >
# ifdef CONFIG _ALTIVEC
# include < altivec . h >
2022-02-08 18:21:50 +03:00
# include < asm / ppc - opcode . h >
2017-08-04 06:42:32 +03:00
# ifdef _ _KERNEL _ _
# include < asm / cputable . h >
# include < asm / switch _to . h >
# endif
typedef vector unsigned char unative _t ;
# define NSIZE sizeof ( unative _t )
static const vector unsigned char gf _low = { 0x1e , 0x1c , 0x1a , 0x18 , 0x16 , 0x14 ,
0x12 , 0x10 , 0x0e , 0x0c , 0x0a , 0x08 ,
0x06 , 0x04 , 0x02 , 0x00 } ;
static const vector unsigned char gf _high = { 0xfd , 0xdd , 0xbd , 0x9d , 0x7d , 0x5d ,
0x3d , 0x1d , 0xe0 , 0xc0 , 0xa0 , 0x80 ,
0x60 , 0x40 , 0x20 , 0x00 } ;
static void noinline raid6 _vpermxor$ # _gen _syndrome _real ( int disks , size _t bytes ,
void * * ptrs )
{
u8 * * dptr = ( u8 * * ) ptrs ;
u8 * p , * q ;
int d , z , z0 ;
unative _t wp$$ , wq$$ , wd$$ ;
z0 = disks - 3 ; /* Highest data disk */
p = dptr [ z0 + 1 ] ; /* XOR parity */
q = dptr [ z0 + 2 ] ; /* RS syndrome */
for ( d = 0 ; d < bytes ; d += NSIZE * $ # ) {
wp$$ = wq$$ = * ( unative _t * ) & dptr [ z0 ] [ d + $$ * NSIZE ] ;
for ( z = z0 - 1 ; z >= 0 ; z -- ) {
wd$$ = * ( unative _t * ) & dptr [ z ] [ d + $$ * NSIZE ] ;
/* P syndrome */
wp$$ = vec _xor ( wp$$ , wd$$ ) ;
/* Q syndrome */
asm ( VPERMXOR ( % 0 , % 1 , % 2 , % 3 ) : "=v" ( wq$$ ) : "v" ( gf _high ) , "v" ( gf _low ) , "v" ( wq$$ ) ) ;
wq$$ = vec _xor ( wq$$ , wd$$ ) ;
}
* ( unative _t * ) & p [ d + NSIZE * $$ ] = wp$$ ;
* ( unative _t * ) & q [ d + NSIZE * $$ ] = wq$$ ;
}
}
static void raid6 _vpermxor$ # _gen _syndrome ( int disks , size _t bytes , void * * ptrs )
{
preempt _disable ( ) ;
enable _kernel _altivec ( ) ;
raid6 _vpermxor$ # _gen _syndrome _real ( disks , bytes , ptrs ) ;
disable _kernel _altivec ( ) ;
preempt _enable ( ) ;
}
int raid6 _have _altivec _vpermxor ( void ) ;
# if $ # == 1
int raid6 _have _altivec _vpermxor ( void )
{
/* Check if arch has both altivec and the vpermxor instructions */
# ifdef _ _KERNEL _ _
return ( cpu _has _feature ( CPU _FTR _ALTIVEC _COMP ) &&
cpu _has _feature ( CPU _FTR _ARCH _207S ) ) ;
# else
return 1 ;
# endif
}
# endif
const struct raid6 _calls raid6 _vpermxor$ # = {
raid6 _vpermxor$ # _gen _syndrome ,
NULL ,
raid6 _have _altivec _vpermxor ,
"vpermxor$#" ,
0
} ;
# endif