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