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/raid/xor.h>
  22#include <linux/jiffies.h>
  23#include <asm/xor.h>
  24
  25/* The xor routines to use.  */
  26static struct xor_block_template *active_template;
  27
  28void
  29xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
  30{
  31        unsigned long *p1, *p2, *p3, *p4;
  32
  33        p1 = (unsigned long *) srcs[0];
  34        if (src_count == 1) {
  35                active_template->do_2(bytes, dest, p1);
  36                return;
  37        }
  38
  39        p2 = (unsigned long *) srcs[1];
  40        if (src_count == 2) {
  41                active_template->do_3(bytes, dest, p1, p2);
  42                return;
  43        }
  44
  45        p3 = (unsigned long *) srcs[2];
  46        if (src_count == 3) {
  47                active_template->do_4(bytes, dest, p1, p2, p3);
  48                return;
  49        }
  50
  51        p4 = (unsigned long *) srcs[3];
  52        active_template->do_5(bytes, dest, p1, p2, p3, p4);
  53}
  54EXPORT_SYMBOL(xor_blocks);
  55
  56/* Set of all registered templates.  */
  57static struct xor_block_template *template_list;
  58
  59#define BENCH_SIZE (PAGE_SIZE)
  60
  61static void
  62do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
  63{
  64        int speed;
  65        unsigned long now;
  66        int i, count, max;
  67
  68        tmpl->next = template_list;
  69        template_list = tmpl;
  70
  71        /*
  72         * Count the number of XORs done during a whole jiffy, and use
  73         * this to calculate the speed of checksumming.  We use a 2-page
  74         * allocation to have guaranteed color L1-cache layout.
  75         */
  76        max = 0;
  77        for (i = 0; i < 5; i++) {
  78                now = jiffies;
  79                count = 0;
  80                while (jiffies == now) {
  81                        mb(); /* prevent loop optimzation */
  82                        tmpl->do_2(BENCH_SIZE, b1, b2);
  83                        mb();
  84                        count++;
  85                        mb();
  86                }
  87                if (count > max)
  88                        max = count;
  89        }
  90
  91        speed = max * (HZ * BENCH_SIZE / 1024);
  92        tmpl->speed = speed;
  93
  94        printk(KERN_INFO "   %-10s: %5d.%03d MB/sec\n", tmpl->name,
  95               speed / 1000, speed % 1000);
  96}
  97
  98static int __init
  99calibrate_xor_blocks(void)
 100{
 101        void *b1, *b2;
 102        struct xor_block_template *f, *fastest;
 103
 104        /*
 105         * Note: Since the memory is not actually used for _anything_ but to
 106         * test the XOR speed, we don't really want kmemcheck to warn about
 107         * reading uninitialized bytes here.
 108         */
 109        b1 = (void *) __get_free_pages(GFP_KERNEL | __GFP_NOTRACK, 2);
 110        if (!b1) {
 111                printk(KERN_WARNING "xor: Yikes!  No memory available.\n");
 112                return -ENOMEM;
 113        }
 114        b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE;
 115
 116        /*
 117         * If this arch/cpu has a short-circuited selection, don't loop through
 118         * all the possible functions, just test the best one
 119         */
 120
 121        fastest = NULL;
 122
 123#ifdef XOR_SELECT_TEMPLATE
 124                fastest = XOR_SELECT_TEMPLATE(fastest);
 125#endif
 126
 127#define xor_speed(templ)        do_xor_speed((templ), b1, b2)
 128
 129        if (fastest) {
 130                printk(KERN_INFO "xor: automatically using best "
 131                        "checksumming function: %s\n",
 132                        fastest->name);
 133                xor_speed(fastest);
 134        } else {
 135                printk(KERN_INFO "xor: measuring software checksum speed\n");
 136                XOR_TRY_TEMPLATES;
 137                fastest = template_list;
 138                for (f = fastest; f; f = f->next)
 139                        if (f->speed > fastest->speed)
 140                                fastest = f;
 141        }
 142
 143        printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
 144               fastest->name, fastest->speed / 1000, fastest->speed % 1000);
 145
 146#undef xor_speed
 147
 148        free_pages((unsigned long)b1, 2);
 149
 150        active_template = fastest;
 151        return 0;
 152}
 153
 154static __exit void xor_exit(void) { }
 155
 156MODULE_LICENSE("GPL");
 157
 158/* when built-in xor.o must initialize before drivers/md/md.o */
 159core_initcall(calibrate_xor_blocks);
 160module_exit(xor_exit);
 161