Branch data Line data Source code
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. */
28 : : static struct xor_block_template *active_template;
29 : :
30 : : void
31 : 0 : xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
32 : : {
33 : : unsigned long *p1, *p2, *p3, *p4;
34 : :
35 : 0 : p1 = (unsigned long *) srcs[0];
36 [ # # ]: 0 : if (src_count == 1) {
37 : 0 : active_template->do_2(bytes, dest, p1);
38 : 0 : return;
39 : : }
40 : :
41 : 0 : p2 = (unsigned long *) srcs[1];
42 [ # # ]: 0 : if (src_count == 2) {
43 : 0 : active_template->do_3(bytes, dest, p1, p2);
44 : 0 : return;
45 : : }
46 : :
47 : 0 : p3 = (unsigned long *) srcs[2];
48 [ # # ]: 0 : if (src_count == 3) {
49 : 0 : active_template->do_4(bytes, dest, p1, p2, p3);
50 : 0 : return;
51 : : }
52 : :
53 : 0 : p4 = (unsigned long *) srcs[3];
54 : 0 : active_template->do_5(bytes, dest, p1, p2, p3, p4);
55 : : }
56 : : EXPORT_SYMBOL(xor_blocks);
57 : :
58 : : /* Set of all registered templates. */
59 : : static struct xor_block_template *__initdata template_list;
60 : :
61 : : #define BENCH_SIZE (PAGE_SIZE)
62 : :
63 : : static void __init
64 : 0 : do_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 : 0 : tmpl->next = template_list;
71 : 0 : template_list = tmpl;
72 : :
73 : 0 : 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 [ # # ]: 0 : for (i = 0; i < 5; i++) {
82 : 0 : j = jiffies;
83 : : count = 0;
84 [ # # ]: 0 : while ((now = jiffies) == j)
85 : 0 : cpu_relax();
86 [ # # ]: 0 : while (time_before(jiffies, now + 1)) {
87 : 0 : mb(); /* prevent loop optimzation */
88 : 0 : tmpl->do_2(BENCH_SIZE, b1, b2);
89 : 0 : mb();
90 : 0 : count++;
91 : 0 : mb();
92 : : }
93 [ # # ]: 0 : if (count > max)
94 : : max = count;
95 : : }
96 : :
97 : 0 : preempt_enable();
98 : :
99 : 0 : speed = max * (HZ * BENCH_SIZE / 1024);
100 : 0 : tmpl->speed = speed;
101 : :
102 : 0 : printk(KERN_INFO " %-10s: %5d.%03d MB/sec\n", tmpl->name,
103 : : speed / 1000, speed % 1000);
104 : 0 : }
105 : :
106 : : static int __init
107 : 0 : calibrate_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 : 0 : b1 = (void *) __get_free_pages(GFP_KERNEL | __GFP_NOTRACK, 2);
118 [ # # ]: 0 : if (!b1) {
119 : 0 : printk(KERN_WARNING "xor: Yikes! No memory available.\n");
120 : 0 : return -ENOMEM;
121 : : }
122 : 0 : 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 : 0 : printk(KERN_INFO "xor: measuring software checksum speed\n");
144 : 0 : XOR_TRY_TEMPLATES;
145 : 0 : fastest = template_list;
146 [ # # ]: 0 : for (f = fastest; f; f = f->next)
147 [ # # ]: 0 : if (f->speed > fastest->speed)
148 : : fastest = f;
149 : : }
150 : :
151 : 0 : printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
152 : 0 : fastest->name, fastest->speed / 1000, fastest->speed % 1000);
153 : :
154 : : #undef xor_speed
155 : :
156 : : out:
157 : 0 : free_pages((unsigned long)b1, 2);
158 : :
159 : 0 : active_template = fastest;
160 : 0 : return 0;
161 : : }
162 : :
163 : 0 : static __exit void xor_exit(void) { }
164 : :
165 : : MODULE_LICENSE("GPL");
166 : :
167 : : /* when built-in xor.o must initialize before drivers/md/md.o */
168 : : core_initcall(calibrate_xor_blocks);
169 : : module_exit(xor_exit);
|