Back to home page

OSCL-LXR

 
 

    


0001 /* -*- linux-c -*- ------------------------------------------------------- *
0002  *
0003  *   Copyright 2002-2004 H. Peter Anvin - All Rights Reserved
0004  *
0005  *   This program is free software; you can redistribute it and/or modify
0006  *   it under the terms of the GNU General Public License as published by
0007  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
0008  *   Boston MA 02111-1307, USA; either version 2 of the License, or
0009  *   (at your option) any later version; incorporated herein by reference.
0010  *
0011  * ----------------------------------------------------------------------- */
0012 
0013 /*
0014  * raid6altivec$#.c
0015  *
0016  * $#-way unrolled portable integer math RAID-6 instruction set
0017  *
0018  * This file is postprocessed using unroll.awk
0019  *
0020  * <benh> hpa: in process,
0021  * you can just "steal" the vec unit with enable_kernel_altivec() (but
0022  * bracked this with preempt_disable/enable or in a lock)
0023  */
0024 
0025 #include <linux/raid/pq.h>
0026 
0027 #ifdef CONFIG_ALTIVEC
0028 
0029 #include <altivec.h>
0030 #ifdef __KERNEL__
0031 # include <asm/cputable.h>
0032 # include <asm/switch_to.h>
0033 #endif /* __KERNEL__ */
0034 
0035 /*
0036  * This is the C data type to use.  We use a vector of
0037  * signed char so vec_cmpgt() will generate the right
0038  * instruction.
0039  */
0040 
0041 typedef vector signed char unative_t;
0042 
0043 #define NBYTES(x) ((vector signed char) {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x})
0044 #define NSIZE   sizeof(unative_t)
0045 
0046 /*
0047  * The SHLBYTE() operation shifts each byte left by 1, *not*
0048  * rolling over into the next byte
0049  */
0050 static inline __attribute_const__ unative_t SHLBYTE(unative_t v)
0051 {
0052         return vec_add(v,v);
0053 }
0054 
0055 /*
0056  * The MASK() operation returns 0xFF in any byte for which the high
0057  * bit is 1, 0x00 for any byte for which the high bit is 0.
0058  */
0059 static inline __attribute_const__ unative_t MASK(unative_t v)
0060 {
0061         unative_t zv = NBYTES(0);
0062 
0063         /* vec_cmpgt returns a vector bool char; thus the need for the cast */
0064         return (unative_t)vec_cmpgt(zv, v);
0065 }
0066 
0067 
0068 /* This is noinline to make damned sure that gcc doesn't move any of the
0069    Altivec code around the enable/disable code */
0070 static void noinline
0071 raid6_altivec$#_gen_syndrome_real(int disks, size_t bytes, void **ptrs)
0072 {
0073         u8 **dptr = (u8 **)ptrs;
0074         u8 *p, *q;
0075         int d, z, z0;
0076 
0077         unative_t wd$$, wq$$, wp$$, w1$$, w2$$;
0078         unative_t x1d = NBYTES(0x1d);
0079 
0080         z0 = disks - 3;         /* Highest data disk */
0081         p = dptr[z0+1];         /* XOR parity */
0082         q = dptr[z0+2];         /* RS syndrome */
0083 
0084         for ( d = 0 ; d < bytes ; d += NSIZE*$# ) {
0085                 wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE];
0086                 for ( z = z0-1 ; z >= 0 ; z-- ) {
0087                         wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE];
0088                         wp$$ = vec_xor(wp$$, wd$$);
0089                         w2$$ = MASK(wq$$);
0090                         w1$$ = SHLBYTE(wq$$);
0091                         w2$$ = vec_and(w2$$, x1d);
0092                         w1$$ = vec_xor(w1$$, w2$$);
0093                         wq$$ = vec_xor(w1$$, wd$$);
0094                 }
0095                 *(unative_t *)&p[d+NSIZE*$$] = wp$$;
0096                 *(unative_t *)&q[d+NSIZE*$$] = wq$$;
0097         }
0098 }
0099 
0100 static void raid6_altivec$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
0101 {
0102         preempt_disable();
0103         enable_kernel_altivec();
0104 
0105         raid6_altivec$#_gen_syndrome_real(disks, bytes, ptrs);
0106 
0107         disable_kernel_altivec();
0108         preempt_enable();
0109 }
0110 
0111 int raid6_have_altivec(void);
0112 #if $# == 1
0113 int raid6_have_altivec(void)
0114 {
0115         /* This assumes either all CPUs have Altivec or none does */
0116 # ifdef __KERNEL__
0117         return cpu_has_feature(CPU_FTR_ALTIVEC);
0118 # else
0119         return 1;
0120 # endif
0121 }
0122 #endif
0123 
0124 const struct raid6_calls raid6_altivec$# = {
0125         raid6_altivec$#_gen_syndrome,
0126         NULL,                   /* XOR not yet implemented */
0127         raid6_have_altivec,
0128         "altivecx$#",
0129         0
0130 };
0131 
0132 #endif /* CONFIG_ALTIVEC */