Blame view

lib/raid6/altivec.uc 3.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /* -*- linux-c -*- ------------------------------------------------------- *
   *
   *   Copyright 2002-2004 H. Peter Anvin - All Rights Reserved
   *
   *   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, Inc., 53 Temple Place Ste 330,
93ed05e2a   Atsushi SAKAI   md: fix typo in F...
8
   *   Boston MA 02111-1307, USA; either version 2 of the License, or
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
17
   *   (at your option) any later version; incorporated herein by reference.
   *
   * ----------------------------------------------------------------------- */
  
  /*
   * raid6altivec$#.c
   *
   * $#-way unrolled portable integer math RAID-6 instruction set
   *
dce3a7a42   Vladimir Dronnikov   md: drivers/md/un...
18
   * This file is postprocessed using unroll.awk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
   *
   * <benh> hpa: in process,
   * you can just "steal" the vec unit with enable_kernel_altivec() (but
   * bracked this with preempt_disable/enable or in a lock)
   */
f701d589a   Dan Williams   md/raid6: move ra...
24
  #include <linux/raid/pq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <altivec.h>
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
27
  #ifdef __KERNEL__
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
28
  # include <asm/cputable.h>
ae3a197e3   David Howells   Disintegrate asm/...
29
  # include <asm/switch_to.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  
  /*
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
32
33
34
   * This is the C data type to use.  We use a vector of
   * signed char so vec_cmpgt() will generate the right
   * instruction.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
   */
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
36
  typedef vector signed char unative_t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
38
  #define NBYTES(x) ((vector signed char) {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x})
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  #define NSIZE	sizeof(unative_t)
  
  /*
   * The SHLBYTE() operation shifts each byte left by 1, *not*
   * rolling over into the next byte
   */
  static inline __attribute_const__ unative_t SHLBYTE(unative_t v)
  {
  	return vec_add(v,v);
  }
  
  /*
   * The MASK() operation returns 0xFF in any byte for which the high
   * bit is 1, 0x00 for any byte for which the high bit is 0.
   */
  static inline __attribute_const__ unative_t MASK(unative_t v)
  {
  	unative_t zv = NBYTES(0);
  
  	/* vec_cmpgt returns a vector bool char; thus the need for the cast */
  	return (unative_t)vec_cmpgt(zv, v);
  }
  
  
  /* This is noinline to make damned sure that gcc doesn't move any of the
     Altivec code around the enable/disable code */
  static void noinline
  raid6_altivec$#_gen_syndrome_real(int disks, size_t bytes, void **ptrs)
  {
  	u8 **dptr = (u8 **)ptrs;
  	u8 *p, *q;
  	int d, z, z0;
  
  	unative_t wd$$, wq$$, wp$$, w1$$, w2$$;
  	unative_t x1d = NBYTES(0x1d);
  
  	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*$# ) {
  		wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE];
  		for ( z = z0-1 ; z >= 0 ; z-- ) {
  			wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE];
  			wp$$ = vec_xor(wp$$, wd$$);
  			w2$$ = MASK(wq$$);
  			w1$$ = SHLBYTE(wq$$);
  			w2$$ = vec_and(w2$$, x1d);
  			w1$$ = vec_xor(w1$$, w2$$);
  			wq$$ = vec_xor(w1$$, wd$$);
  		}
  		*(unative_t *)&p[d+NSIZE*$$] = wp$$;
  		*(unative_t *)&q[d+NSIZE*$$] = wq$$;
  	}
  }
  
  static void raid6_altivec$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
  {
  	preempt_disable();
  	enable_kernel_altivec();
  
  	raid6_altivec$#_gen_syndrome_real(disks, bytes, ptrs);
dc4fbba11   Anton Blanchard   powerpc: Create d...
101
  	disable_kernel_altivec();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
109
  	preempt_enable();
  }
  
  int raid6_have_altivec(void);
  #if $# == 1
  int raid6_have_altivec(void)
  {
  	/* This assumes either all CPUs have Altivec or none does */
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
110
  # ifdef __KERNEL__
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  	return cpu_has_feature(CPU_FTR_ALTIVEC);
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
112
113
114
  # else
  	return 1;
  # endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
  }
  #endif
  
  const struct raid6_calls raid6_altivec$# = {
  	raid6_altivec$#_gen_syndrome,
fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
120
  	NULL,			/* XOR not yet implemented */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
  	raid6_have_altivec,
  	"altivecx$#",
  	0
  };
  
  #endif /* CONFIG_ALTIVEC */