2005-04-17 02:20:36 +04:00
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright 2002 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 ,
2009-03-31 07:57:37 +04:00
* Boston MA 02111 - 1307 , USA ; either version 2 of the License , or
2005-04-17 02:20:36 +04:00
* ( at your option ) any later version ; incorporated herein by reference .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
2010-08-12 00:44:54 +04:00
* raid6 / algos . c
2005-04-17 02:20:36 +04:00
*
* Algorithm list and algorithm selection for RAID - 6
*/
2009-03-31 08:09:39 +04:00
# include <linux/raid/pq.h>
2011-07-03 21:58:33 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# ifndef __KERNEL__
# include <sys/mman.h>
2005-09-17 06:27:29 +04:00
# include <stdio.h>
2009-03-31 08:09:39 +04:00
# else
2010-08-12 00:38:24 +04:00
# include <linux/gfp.h>
2009-03-31 08:09:39 +04:00
# if !RAID6_USE_EMPTY_ZERO_PAGE
/* In .bss so it's zeroed */
const char raid6_empty_zero_page [ PAGE_SIZE ] __attribute__ ( ( aligned ( 256 ) ) ) ;
EXPORT_SYMBOL ( raid6_empty_zero_page ) ;
# endif
2005-04-17 02:20:36 +04:00
# endif
struct raid6_calls raid6_call ;
2009-03-31 08:09:39 +04:00
EXPORT_SYMBOL_GPL ( raid6_call ) ;
2005-04-17 02:20:36 +04:00
const struct raid6_calls * const raid6_algos [ ] = {
& raid6_intx1 ,
& raid6_intx2 ,
& raid6_intx4 ,
& raid6_intx8 ,
# if defined(__ia64__)
& raid6_intx16 ,
& raid6_intx32 ,
# endif
2007-10-29 07:31:16 +03:00
# if defined(__i386__) && !defined(__arch_um__)
2005-04-17 02:20:36 +04:00
& raid6_mmxx1 ,
& raid6_mmxx2 ,
& raid6_sse1x1 ,
& raid6_sse1x2 ,
& raid6_sse2x1 ,
& raid6_sse2x2 ,
# endif
2007-10-29 07:31:16 +03:00
# if defined(__x86_64__) && !defined(__arch_um__)
2005-04-17 02:20:36 +04:00
& raid6_sse2x1 ,
& raid6_sse2x2 ,
& raid6_sse2x4 ,
# endif
# ifdef CONFIG_ALTIVEC
& raid6_altivec1 ,
& raid6_altivec2 ,
& raid6_altivec4 ,
& raid6_altivec8 ,
# endif
NULL
} ;
# ifdef __KERNEL__
# define RAID6_TIME_JIFFIES_LG2 4
# else
/* Need more time to be stable in userspace */
# define RAID6_TIME_JIFFIES_LG2 9
2009-03-31 08:09:39 +04:00
# define time_before(x, y) ((x) < (y))
2005-04-17 02:20:36 +04:00
# endif
/* Try to pick the best algorithm */
/* This code uses the gfmul table as convenient data set to abuse */
int __init raid6_select_algo ( void )
{
const struct raid6_calls * const * algo ;
const struct raid6_calls * best ;
char * syndromes ;
void * dptrs [ ( 65536 / PAGE_SIZE ) + 2 ] ;
int i , disks ;
unsigned long perf , bestperf ;
int bestprefer ;
unsigned long j0 , j1 ;
disks = ( 65536 / PAGE_SIZE ) + 2 ;
for ( i = 0 ; i < disks - 2 ; i + + ) {
dptrs [ i ] = ( ( char * ) raid6_gfmul ) + PAGE_SIZE * i ;
}
/* Normal code - use a 2-page allocation to avoid D$ conflict */
syndromes = ( void * ) __get_free_pages ( GFP_KERNEL , 1 ) ;
if ( ! syndromes ) {
printk ( " raid6: Yikes! No memory available. \n " ) ;
return - ENOMEM ;
}
dptrs [ disks - 2 ] = syndromes ;
dptrs [ disks - 1 ] = syndromes + PAGE_SIZE ;
bestperf = 0 ; bestprefer = 0 ; best = NULL ;
for ( algo = raid6_algos ; * algo ; algo + + ) {
if ( ! ( * algo ) - > valid | | ( * algo ) - > valid ( ) ) {
perf = 0 ;
preempt_disable ( ) ;
j0 = jiffies ;
while ( ( j1 = jiffies ) = = j0 )
cpu_relax ( ) ;
2008-04-28 13:15:56 +04:00
while ( time_before ( jiffies ,
j1 + ( 1 < < RAID6_TIME_JIFFIES_LG2 ) ) ) {
2005-04-17 02:20:36 +04:00
( * algo ) - > gen_syndrome ( disks , PAGE_SIZE , dptrs ) ;
perf + + ;
}
preempt_enable ( ) ;
if ( ( * algo ) - > prefer > bestprefer | |
( ( * algo ) - > prefer = = bestprefer & &
perf > bestperf ) ) {
best = * algo ;
bestprefer = best - > prefer ;
bestperf = perf ;
}
printk ( " raid6: %-8s %5ld MB/s \n " , ( * algo ) - > name ,
( perf * HZ ) > > ( 20 - 16 + RAID6_TIME_JIFFIES_LG2 ) ) ;
}
}
2006-06-23 13:05:59 +04:00
if ( best ) {
2005-04-17 02:20:36 +04:00
printk ( " raid6: using algorithm %s (%ld MB/s) \n " ,
best - > name ,
( bestperf * HZ ) > > ( 20 - 16 + RAID6_TIME_JIFFIES_LG2 ) ) ;
2006-06-23 13:05:59 +04:00
raid6_call = * best ;
} else
2005-04-17 02:20:36 +04:00
printk ( " raid6: Yikes! No algorithm found! \n " ) ;
free_pages ( ( unsigned long ) syndromes , 1 ) ;
return best ? 0 : - EINVAL ;
}
2009-03-31 08:09:39 +04:00
static void raid6_exit ( void )
{
do { } while ( 0 ) ;
}
subsys_initcall ( raid6_select_algo ) ;
module_exit ( raid6_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-12-14 04:49:58 +03:00
MODULE_DESCRIPTION ( " RAID6 Q-syndrome calculations " ) ;