add support for the Gateworks Laguna family (Cavium Networks Econa CNS3xxx)
[openwrt.git] / target / linux / cns3xxx / patches-2.6.31 / 206-cns3xxx_raid_support.patch
1 --- a/crypto/xor.c
2 +++ b/crypto/xor.c
3 @@ -25,6 +25,26 @@
4  /* The xor routines to use.  */
5  static struct xor_block_template *active_template;
6  
7 +#ifdef CONFIG_CNS3XXX_RAID
8 +extern void do_cns_rdma_xorgen(unsigned int src_no, unsigned int bytes,
9 +                              void **bh_ptr, void *dst_ptr);
10 +/**
11 + * xor_blocks - one pass xor
12 + * @src_count: source count
13 + * @bytes: length in bytes
14 + * @dest: dest
15 + * @srcs: srcs
16 + *
17 + * Desc:
18 + * 1. dest = xor(srcs[0...src_count-1]) within one calc
19 + * 2. don't care if dest also be placed in srcs list or not.
20 + */
21 +void xor_blocks(unsigned int src_count, unsigned int bytes, void *dest,
22 +               void **srcs)
23 +{
24 +       do_cns_rdma_xorgen(src_count, bytes, srcs, dest);
25 +}
26 +#else
27  void
28  xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
29  {
30 @@ -51,6 +71,7 @@ xor_blocks(unsigned int src_count, unsig
31         p4 = (unsigned long *) srcs[3];
32         active_template->do_5(bytes, dest, p1, p2, p3, p4);
33  }
34 +#endif /* CONFIG_CNS3XXX_RAID */
35  EXPORT_SYMBOL(xor_blocks);
36  
37  /* Set of all registered templates.  */
38 @@ -95,7 +116,11 @@ do_xor_speed(struct xor_block_template *
39                speed / 1000, speed % 1000);
40  }
41  
42 +#ifdef CONFIG_CNS3XXX_RAID
43 +int
44 +#else
45  static int __init
46 +#endif                         /* CONFIG_CNS3XXX_RAID */
47  calibrate_xor_blocks(void)
48  {
49         void *b1, *b2;
50 @@ -139,7 +164,10 @@ calibrate_xor_blocks(void)
51                         if (f->speed > fastest->speed)
52                                 fastest = f;
53         }
54 -
55 +#ifdef CONFIG_CNS3XXX_RAID
56 +       /* preferred */
57 +       fastest = template_list;
58 +#endif /* CONFIG_CNS3XXX_RAID */
59         printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
60                fastest->name, fastest->speed / 1000, fastest->speed % 1000);
61  
62 @@ -151,10 +179,20 @@ calibrate_xor_blocks(void)
63         return 0;
64  }
65  
66 -static __exit void xor_exit(void) { }
67 +#ifndef        CONFIG_CNS3XXX_RAID
68 +static __exit void xor_exit(void)
69 +{
70 +}
71 +#endif /* ! CONFIG_CNS3XXX_RAID */
72  
73  MODULE_LICENSE("GPL");
74  
75 +#ifdef CONFIG_CNS3XXX_RAID
76 +/*
77 + * Calibrate in R5 init.
78 + */
79 +#else
80  /* when built-in xor.o must initialize before drivers/md/md.o */
81  core_initcall(calibrate_xor_blocks);
82  module_exit(xor_exit);
83 +#endif /* ! CONFIG_CNS3XXX_RAID */
84 --- a/drivers/md/Makefile
85 +++ b/drivers/md/Makefile
86 @@ -17,7 +17,7 @@ raid6_pq-y    += raid6algos.o raid6recov.o 
87                    raid6int8.o raid6int16.o raid6int32.o \
88                    raid6altivec1.o raid6altivec2.o raid6altivec4.o \
89                    raid6altivec8.o \
90 -                  raid6mmx.o raid6sse1.o raid6sse2.o
91 +                  raid6mmx.o raid6sse1.o raid6sse2.o raid6cns.o
92  hostprogs-y    += mktables
93  
94  # Note: link order is important.  All raid personalities
95 --- a/drivers/md/raid5.c
96 +++ b/drivers/md/raid5.c
97 @@ -1817,11 +1817,30 @@ static void compute_block_2(struct strip
98                         compute_parity6(sh, UPDATE_PARITY);
99                         return;
100                 } else {
101 +#ifdef  CONFIG_CNS3XXX_RAID
102 +                       void *ptrs[disks];
103 +
104 +                       count = 0;
105 +                       i = d0_idx;
106 +                       do {
107 +                               ptrs[count++] = page_address(sh->dev[i].page);
108 +                               i = raid6_next_disk(i, disks);
109 +                               if (i != dd_idx1 && i != dd_idx2 &&
110 +                                   !test_bit(R5_UPTODATE, &sh->dev[i].flags))
111 +                                       printk
112 +                                           ("compute_2 with missing block %d/%d\n",
113 +                                            count, i);
114 +                       } while (i != d0_idx);
115 +
116 +                       raid6_dataq_recov(disks, STRIPE_SIZE, faila, ptrs);
117 +#else
118 +
119                         /* We're missing D+Q; recompute D from P */
120                         compute_block_1(sh, ((dd_idx1 == sh->qd_idx) ?
121                                              dd_idx2 : dd_idx1),
122                                         0);
123                         compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */
124 +#endif /* CONFIG_CNS3XXX_RAID */
125                         return;
126                 }
127         }
128 @@ -5412,8 +5431,21 @@ static struct mdk_personality raid4_pers
129         .quiesce        = raid5_quiesce,
130  };
131  
132 +#ifdef CONFIG_CNS3XXX_RAID
133 +extern int calibrate_xor_blocks(void);
134 +#endif /* CONFIG_CNS3XXX_RAID */
135 +
136  static int __init raid5_init(void)
137  {
138 +
139 +#ifdef  CONFIG_CNS3XXX_RAID
140 +       /* Just execute calibrate xor blocks */
141 +       int e;
142 +       e = calibrate_xor_blocks();
143 +       if (e)
144 +               return e;
145 +#endif /* CONFIG_CNS3XXX_RAID */
146 +
147         register_md_personality(&raid6_personality);
148         register_md_personality(&raid5_personality);
149         register_md_personality(&raid4_personality);
150 --- a/drivers/md/raid6algos.c
151 +++ b/drivers/md/raid6algos.c
152 @@ -49,6 +49,9 @@ extern const struct raid6_calls raid6_al
153  extern const struct raid6_calls raid6_altivec2;
154  extern const struct raid6_calls raid6_altivec4;
155  extern const struct raid6_calls raid6_altivec8;
156 +#ifdef CONFIG_CNS3XXX_RAID
157 +extern const struct raid6_calls raid6_cns_raid;
158 +#endif /* CONFIG_CNS3XXX_RAID */
159  
160  const struct raid6_calls * const raid6_algos[] = {
161         &raid6_intx1,
162 @@ -78,6 +81,11 @@ const struct raid6_calls * const raid6_a
163         &raid6_altivec4,
164         &raid6_altivec8,
165  #endif
166 +#ifdef CONFIG_CNS3XXX_RAID
167 +       /* CNS3000 HW RAID acceleration */
168 +       &raid6_cns_raid,
169 +#endif /* CONFIG_CNS3XXX_RAID */
170 +
171         NULL
172  };
173  
174 @@ -125,7 +133,9 @@ int __init raid6_select_algo(void)
175                 if ( !(*algo)->valid || (*algo)->valid() ) {
176                         perf = 0;
177  
178 +#ifndef        CONFIG_CNS3XXX_RAID
179                         preempt_disable();
180 +#endif
181                         j0 = jiffies;
182                         while ( (j1 = jiffies) == j0 )
183                                 cpu_relax();
184 @@ -134,7 +144,9 @@ int __init raid6_select_algo(void)
185                                 (*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs);
186                                 perf++;
187                         }
188 +#ifndef        CONFIG_CNS3XXX_RAID
189                         preempt_enable();
190 +#endif
191  
192                         if ( (*algo)->prefer > bestprefer ||
193                              ((*algo)->prefer == bestprefer &&
194 --- /dev/null
195 +++ b/drivers/md/raid6cns.c
196 @@ -0,0 +1,38 @@
197 +/* 
198 + * raid6cns.c
199 + *
200 + * CNS3xxx xor & gen_syndrome functions
201 + *
202 + */
203 +
204 +#ifdef CONFIG_CNS3XXX_RAID
205 +
206 +#include <linux/raid/pq.h>
207 +
208 +extern void do_cns_rdma_gfgen(unsigned int src_no, unsigned int bytes, void **bh_ptr, 
209 +                               void *p_dst, void *q_dst);
210 +
211 +/**
212 + * raid6_cnsraid_gen_syndrome - CNSRAID Syndrome Generate
213 + *
214 + * @disks: raid disks
215 + * @bytes: length
216 + * @ptrs:  already arranged stripe ptrs, 
217 + *         disk0=[0], diskNNN=[disks-3], 
218 + *         P/Q=[z0+1] & [z0+2], or, [disks-2], [disks-1]
219 + */
220 +static void raid6_cnsraid_gen_syndrome(int disks, size_t bytes, void **ptrs)
221 +{
222 +       do_cns_rdma_gfgen(disks - 2, bytes, ptrs, ptrs[disks-2], ptrs[disks-1]);
223 +}
224 +
225 +const struct raid6_calls raid6_cns_raid = {
226 +       raid6_cnsraid_gen_syndrome,     /* callback */
227 +       NULL,                                           /* always valid */
228 +       "CNS-RAID",                                     /* name */
229 +       1                                                       /* preferred: revise it to "0" to compare/compete with others algos */
230 +};
231 +
232 +EXPORT_SYMBOL(raid6_cns_raid);
233 +
234 +#endif /* CONFIG_CNS3XXX_RAID */
235 --- a/drivers/md/raid6recov.c
236 +++ b/drivers/md/raid6recov.c
237 @@ -20,6 +20,136 @@
238  
239  #include <linux/raid/pq.h>
240  
241 +#ifdef CONFIG_CNS3XXX_RAID
242 +#define        R6_RECOV_PD             1
243 +#define        R6_RECOV_DD             2
244 +#define        R6_RECOV_DQ             3
245 +extern void do_cns_rdma_gfgen_pd_dd_dq(unsigned int src_no, unsigned int bytes,
246 +                                      void **bh_ptr, void *w1_dst,
247 +                                      void *w2_dst, int pd_dd_qd,
248 +                                      unsigned int w1_idx, unsigned int w2_idx,
249 +                                      unsigned int *src_idx);
250 +
251 +/**
252 + * @disks: nr_disks
253 + * @bytes: len
254 + * @faila: 1st failed DD
255 + * @ptrs:  ptrs by order {d0, d1, ..., da, ..., dn, P, Q}
256 + *
257 + * Desc:
258 + *     new_read_ptrs = {d0, d1, ... dn, Q}
259 + *     dd1 = faila
260 + *     p_dst = P
261 + */
262 +void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
263 +{
264 +       int cnt = 0;
265 +       int count = 0;
266 +       void *p_dst, *q;
267 +       void *dd1_dst;
268 +       void *new_read_ptrs[disks - 2];
269 +       unsigned int read_idx[disks - 2];
270 +
271 +       q = ptrs[disks - 1];
272 +       p_dst = ptrs[disks - 2];
273 +       dd1_dst = ptrs[faila];
274 +
275 +       while (cnt < disks) {
276 +               if (cnt != faila && cnt != disks - 2) {
277 +                       new_read_ptrs[count] = ptrs[cnt];
278 +                       read_idx[count] = cnt;
279 +                       count++;
280 +               }
281 +               cnt++;
282 +       }
283 +
284 +       do_cns_rdma_gfgen_pd_dd_dq(disks - 2, bytes,
285 +                                  new_read_ptrs, p_dst, dd1_dst,
286 +                                  R6_RECOV_PD, disks - 1, faila + 1, read_idx);
287 +}
288 +
289 +/**
290 + * @disks: nr_disks
291 + * @bytes: len
292 + * @faila: 1st failed DD
293 + * @failb: 2nd failed DD
294 + * @ptrs:  ptrs by order {d0, d1, ..., da, ..., db, ..., dn, P, Q}
295 + *
296 + * Desc:
297 + *     new_read_ptrs = {d0, d1, ... dn, P, Q}
298 + *     dd1_dst = faila
299 + *     dd2_dst = failb
300 + */
301 +void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
302 +                      void **ptrs)
303 +{
304 +
305 +       int cnt = 0;
306 +       int count = 0;
307 +       void *p, *q;
308 +       void *dd1_dst, *dd2_dst;
309 +       void *new_read_ptrs[disks - 2];
310 +       unsigned int read_idx[disks - 2];
311 +
312 +       q = ptrs[disks - 1];
313 +       p = ptrs[disks - 2];
314 +       dd1_dst = ptrs[faila];
315 +       dd2_dst = ptrs[failb];
316 +
317 +       while (cnt < disks) {
318 +               if (cnt != faila && cnt != failb) {
319 +                       new_read_ptrs[count] = ptrs[cnt];
320 +                       read_idx[count] = cnt;
321 +                       count++;
322 +               }
323 +               cnt++;
324 +       }
325 +
326 +       do_cns_rdma_gfgen_pd_dd_dq(disks - 2, bytes,
327 +                                  new_read_ptrs, dd1_dst, dd2_dst,
328 +                                  R6_RECOV_DD, faila + 1, failb + 1, read_idx);
329 +}
330 +
331 +/**
332 + * @disks: nr_disks
333 + * @bytes: len
334 + * @faila: 1st failed DD
335 + * @ptrs:  ptrs by order {d0, d1, ..., da, ..., dn, P, Q}
336 + *
337 + * Desc:
338 + *     new_read_ptrs = {d0, d1, ... dn, P}
339 + *     dd1 = faila
340 + *     q_dst = Q
341 + */
342 +void raid6_dataq_recov(int disks, size_t bytes, int faila, void **ptrs)
343 +{
344 +       int cnt = 0;
345 +       int count = 0;
346 +       void *q_dst, *p;
347 +       void *dd1_dst;
348 +       void *new_read_ptrs[disks - 2];
349 +       unsigned int read_idx[disks - 2];
350 +
351 +       p = ptrs[disks - 2];
352 +       q_dst = ptrs[disks - 1];
353 +       dd1_dst = ptrs[faila];
354 +
355 +       while (cnt < disks) {
356 +               if (cnt != faila && cnt != disks - 1) {
357 +                       new_read_ptrs[count] = ptrs[cnt];
358 +                       read_idx[count] = cnt;
359 +                       count++;
360 +               }
361 +               cnt++;
362 +       }
363 +
364 +       do_cns_rdma_gfgen_pd_dd_dq(disks - 2, bytes,
365 +                                  new_read_ptrs, dd1_dst, q_dst,
366 +                                  R6_RECOV_DQ, faila + 1, disks, read_idx);
367 +}
368 +
369 +#else /* CONFIG_CNS3XXX_RAID
370 +
371  /* Recover two failed data blocks. */
372  void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
373                        void **ptrs)
374 @@ -96,6 +226,7 @@ void raid6_datap_recov(int disks, size_t
375         }
376  }
377  EXPORT_SYMBOL_GPL(raid6_datap_recov);
378 +#endif /* CONFIG_CNS3XXX_RAID */
379  
380  #ifndef __KERNEL__
381  /* Testing only */
382 --- a/include/linux/raid/pq.h
383 +++ b/include/linux/raid/pq.h
384 @@ -100,6 +100,9 @@ void raid6_2data_recov(int disks, size_t
385  void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs);
386  void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
387                       void **ptrs);
388 +#ifdef  CONFIG_CNS3XXX_RAID
389 +void raid6_dataq_recov(int disks, size_t bytes, int faila, void **ptrs);
390 +#endif /* CONFIG_CNS3XXX_RAID */
391  
392  /* Some definitions to allow code to be compiled for testing in userspace */
393  #ifndef __KERNEL__
394 --- a/include/linux/raid/xor.h
395 +++ b/include/linux/raid/xor.h
396 @@ -1,7 +1,11 @@
397  #ifndef _XOR_H
398  #define _XOR_H
399  
400 +#ifdef CONFIG_CNS3XXX_RAID
401 +#define        MAX_XOR_BLOCKS 32
402 +#else
403  #define MAX_XOR_BLOCKS 4
404 +#endif /* CONFIG_CNS3XXX_RAID */
405  
406  extern void xor_blocks(unsigned int count, unsigned int bytes,
407         void *dest, void **srcs);
408 --- a/mm/mempool.c
409 +++ b/mm/mempool.c
410 @@ -250,6 +250,28 @@ repeat_alloc:
411  }
412  EXPORT_SYMBOL(mempool_alloc);
413  
414 +#ifdef CONFIG_CNS3XXX_RAID
415 +/**
416 + * acs_mempool_alloc - allocate an element from a specific memory pool
417 + * @pool:      pointer to the memory pool which was allocated via
418 + *             mempool_create().
419 + *
420 + * this function differs from mempool_alloc by directly allocating an element
421 + * from @pool without calling @pool->alloc().
422 + */
423 +void *acs_mempool_alloc(mempool_t * pool)
424 +{
425 +       unsigned long flags;
426 +       void *element = NULL;
427 +
428 +       spin_lock_irqsave(&pool->lock, flags);
429 +       if (likely(pool->curr_nr))
430 +               element = remove_element(pool);
431 +       spin_unlock_irqrestore(&pool->lock, flags);
432 +       return element;
433 +}
434 +#endif /* CONFIG_CNS3XXX_RAID */
435 +
436  /**
437   * mempool_free - return an element to the pool.
438   * @element:   pool element pointer.