linux/crypto/xor.c
<<
>>
Prefs
   1/*
   2 * xor.c : Multiple Devices driver for Linux
   3 *
   4 * Copyright (C) 1996, 1997, 1998, 1999, 2000,
   5 * Ingo Molnar, Matti Aarnio, Jakub Jelinek, Richard Henderson.
   6 *
   7 * Dispatch optimized RAID-5 checksumming functions.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2, or (at your option)
  12 * any later version.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * (for example /usr/src/linux/COPYING); if not, write to the Free
  16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17 */
  18
  19#define BH_TRACE 0
  20#include <linux/module.h>
  21#include <linux/gfp.h>
  22#include <linux/raid/xor.h>
  23#include <linux/jiffies.h>
  24#include <asm/xor.h>
  25
  26/* The xor routines to use.  */
  27static struct xor_block_template *active_template;
  28
  29void
  30xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
  31{
  32        unsigned long *p1, *p2, *p3, *p4;
  33
  34        p1 = (unsigned long *) srcs[0];
  35        if (src_count == 1) {
  36                active_template->do_2(bytes, dest, p1);
  37                return;
  38        }
  39
  40        p2 = (unsigned long *) srcs[1];
  41        if (src_count == 2) {
  42                active_template->do_3(bytes, dest, p1, p2);
  43                return;
  44        }
  45
  46        p3 = (unsigned long *) srcs[2];
  47        if (src_count == 3) {
  48                active_template->do_4(bytes, dest, p1, p2, p3);
  49                return;
  50        }
  51
  52        p4 = (unsigned long *) srcs[3];
  53        active_template->do_5(bytes, dest, p1, p2, p3, p4);
  54}
  55EXPORT_SYMBOL(xor_blocks);
  56
  57/* Set of all registered templates.  */
  58static struct xor_block_template *template_list;
  59
  60#define BENCH_SIZE (PAGE_SIZE)
  61
  62static void
  63do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
  64{
  65        int speed;
  66        unsigned long now;
  67        int i, count, max;
  68
  69        tmpl->next = template_list;
  70        template_list = tmpl;
  71
  72        /*
  73         * Count the number of XORs done during a whole jiffy, and use
  74         * this to calculate the speed of checksumming.  We use a 2-page
  75         * allocation to have guaranteed color L1-cache layout.
  76         */
  77        max = 0;
  78        for (i = 0; i < 5; i++) {
  79                now = jiffies;
  80                count = 0;
  81                while (jiffies == now) {
  82                        mb(); /* prevent loop optimzation */
  83                        tmpl->do_2(BENCH_SIZE, b1, b2);
  84                        mb();
  85                        count++;
  86                        mb();
  87                }
  88                if (count > max)
  89                        max = count;
  90        }
  91
  92        speed = max * (HZ * BENCH_SIZE / 1024);
  93        tmpl->speed = speed;
  94
  95        printk(KERN_INFO "   %-10s: %5d.%03d MB/sec\n", tmpl->name,
  96               speed / 1000, speed % 1000);
  97}
  98
  99static int __init
 100calibrate_xor_blocks(void)
 101{
 102        void *b1, *b2;
 103        struct xor_block_template *f, *fastest;
 104
 105        /*
 106         * Note: Since the memory is not actually used for _anything_ but to
 107         * test the XOR speed, we don't really want kmemcheck to warn about
 108         * reading uninitialized bytes here.
 109         */
 110        b1 = (void *) __get_free_pages(GFP_KERNEL | __GFP_NOTRACK, 2);
 111        if (!b1) {
 112                printk(KERN_WARNING "xor: Yikes!  No memory available.\n");
 113                return -ENOMEM;
 114        }
 115        b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE;
 116
 117        /*
 118         * If this arch/cpu has a short-circuited selection, don't loop through
 119         * all the possible functions, just test the best one
 120         */
 121
 122        fastest = NULL;
 123
 124#ifdef XOR_SELECT_TEMPLATE
 125                fastest = XOR_SELECT_TEMPLATE(fastest);
 126#endif
 127
 128#define xor_speed(templ)        do_xor_speed((templ), b1, b2)
 129
 130        if (fastest) {
 131                printk(KERN_INFO "xor: automatically using best "
 132                        "checksumming function: %s\n",
 133                        fastest->name);
 134                xor_speed(fastest);
 135        } else {
 136                printk(KERN_INFO "xor: measuring software checksum speed\n");
 137                XOR_TRY_TEMPLATES;
 138                fastest = template_list;
 139                for (f = fastest; f; f = f->next)
 140                        if (f->speed > fastest->speed)
 141                                fastest = f;
 142        }
 143
 144        printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
 145               fastest->name, fastest->speed / 1000, fastest->speed % 1000);
 146
 147#undef xor_speed
 148
 149        free_pages((unsigned long)b1, 2);
 150
 151        active_template = fastest;
 152        return 0;
 153}
 154
 155static __exit void xor_exit(void) { }
 156
 157MODULE_LICENSE("GPL");
 158
 159/* when built-in xor.o must initialize before drivers/md/md.o */
 160core_initcall(calibrate_xor_blocks);
 161module_exit(xor_exit);
 162