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