xref: /linux/lib/raid/xor/xor-core.c (revision 440d6635b20037bc9ad46b20817d7b61cef0fc1b)
19e229025SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-or-later
29e229025SChristoph Hellwig /*
39e229025SChristoph Hellwig  * Copyright (C) 1996, 1997, 1998, 1999, 2000,
49e229025SChristoph Hellwig  * Ingo Molnar, Matti Aarnio, Jakub Jelinek, Richard Henderson.
59e229025SChristoph Hellwig  *
67c6e6b2bSChristoph Hellwig  * Dispatch optimized XOR parity functions.
79e229025SChristoph Hellwig  */
89e229025SChristoph Hellwig 
99e229025SChristoph Hellwig #include <linux/module.h>
109e229025SChristoph Hellwig #include <linux/gfp.h>
119e229025SChristoph Hellwig #include <linux/raid/xor.h>
129e229025SChristoph Hellwig #include <linux/jiffies.h>
139e229025SChristoph Hellwig #include <linux/preempt.h>
14*a21921ddSChristoph Hellwig #include <linux/static_call.h>
15e20043b4SChristoph Hellwig #include "xor_impl.h"
169e229025SChristoph Hellwig 
17*a21921ddSChristoph Hellwig DEFINE_STATIC_CALL_NULL(xor_gen_impl, *xor_block_8regs.xor_gen);
189e229025SChristoph Hellwig 
19e420f0a8SChristoph Hellwig /**
20e420f0a8SChristoph Hellwig  * xor_gen - generate RAID-style XOR information
21e420f0a8SChristoph Hellwig  * @dest:	destination vector
22e420f0a8SChristoph Hellwig  * @srcs:	source vectors
23e420f0a8SChristoph Hellwig  * @src_cnt:	number of source vectors
24e420f0a8SChristoph Hellwig  * @bytes:	length in bytes of each vector
25e420f0a8SChristoph Hellwig  *
26e420f0a8SChristoph Hellwig  * Performs bit-wise XOR operation into @dest for each of the @src_cnt vectors
27e420f0a8SChristoph Hellwig  * in @srcs for a length of @bytes bytes.  @src_cnt must be non-zero, and the
28e420f0a8SChristoph Hellwig  * memory pointed to by @dest and each member of @srcs must be at least 64-byte
29e420f0a8SChristoph Hellwig  * aligned.  @bytes must be non-zero and a multiple of 512.
30e420f0a8SChristoph Hellwig  *
31e420f0a8SChristoph Hellwig  * Note: for typical RAID uses, @dest either needs to be zeroed, or filled with
32e420f0a8SChristoph Hellwig  * the first disk, which then needs to be removed from @srcs.
33e420f0a8SChristoph Hellwig  */
34e420f0a8SChristoph Hellwig void xor_gen(void *dest, void **srcs, unsigned int src_cnt, unsigned int bytes)
35e420f0a8SChristoph Hellwig {
3680dcf0a7SChristoph Hellwig 	WARN_ON_ONCE(!in_task() || irqs_disabled() || softirq_count());
37e420f0a8SChristoph Hellwig 	WARN_ON_ONCE(bytes == 0);
38e420f0a8SChristoph Hellwig 	WARN_ON_ONCE(bytes & 511);
39e420f0a8SChristoph Hellwig 
40*a21921ddSChristoph Hellwig 	static_call(xor_gen_impl)(dest, srcs, src_cnt, bytes);
41e420f0a8SChristoph Hellwig }
42e420f0a8SChristoph Hellwig EXPORT_SYMBOL(xor_gen);
43e420f0a8SChristoph Hellwig 
449e229025SChristoph Hellwig /* Set of all registered templates.  */
459e229025SChristoph Hellwig static struct xor_block_template *__initdata template_list;
46*a21921ddSChristoph Hellwig static struct xor_block_template *forced_template;
479e229025SChristoph Hellwig 
4835ebc4deSChristoph Hellwig /**
4935ebc4deSChristoph Hellwig  * xor_register - register a XOR template
5035ebc4deSChristoph Hellwig  * @tmpl:	template to register
5135ebc4deSChristoph Hellwig  *
5235ebc4deSChristoph Hellwig  * Register a XOR implementation with the core.  Registered implementations
5335ebc4deSChristoph Hellwig  * will be measured by a trivial benchmark, and the fastest one is chosen
5435ebc4deSChristoph Hellwig  * unless an implementation is forced using xor_force().
5535ebc4deSChristoph Hellwig  */
5635ebc4deSChristoph Hellwig void __init xor_register(struct xor_block_template *tmpl)
579e229025SChristoph Hellwig {
589e229025SChristoph Hellwig 	tmpl->next = template_list;
599e229025SChristoph Hellwig 	template_list = tmpl;
609e229025SChristoph Hellwig }
619e229025SChristoph Hellwig 
6235ebc4deSChristoph Hellwig /**
6335ebc4deSChristoph Hellwig  * xor_force - force use of a XOR template
6435ebc4deSChristoph Hellwig  * @tmpl:	template to register
6535ebc4deSChristoph Hellwig  *
6635ebc4deSChristoph Hellwig  * Register a XOR implementation with the core and force using it.  Forcing
6735ebc4deSChristoph Hellwig  * an implementation will make the core ignore any template registered using
6835ebc4deSChristoph Hellwig  * xor_register(), or any previous implementation forced using xor_force().
6935ebc4deSChristoph Hellwig  */
7035ebc4deSChristoph Hellwig void __init xor_force(struct xor_block_template *tmpl)
7135ebc4deSChristoph Hellwig {
72*a21921ddSChristoph Hellwig 	forced_template = tmpl;
7335ebc4deSChristoph Hellwig }
7435ebc4deSChristoph Hellwig 
759e229025SChristoph Hellwig #define BENCH_SIZE	4096
769e229025SChristoph Hellwig #define REPS		800U
779e229025SChristoph Hellwig 
789e229025SChristoph Hellwig static void __init
799e229025SChristoph Hellwig do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
809e229025SChristoph Hellwig {
819e229025SChristoph Hellwig 	int speed;
829e229025SChristoph Hellwig 	unsigned long reps;
839e229025SChristoph Hellwig 	ktime_t min, start, t0;
8480dcf0a7SChristoph Hellwig 	void *srcs[1] = { b2 };
859e229025SChristoph Hellwig 
869e229025SChristoph Hellwig 	preempt_disable();
879e229025SChristoph Hellwig 
889e229025SChristoph Hellwig 	reps = 0;
899e229025SChristoph Hellwig 	t0 = ktime_get();
909e229025SChristoph Hellwig 	/* delay start until time has advanced */
919e229025SChristoph Hellwig 	while ((start = ktime_get()) == t0)
929e229025SChristoph Hellwig 		cpu_relax();
939e229025SChristoph Hellwig 	do {
949e229025SChristoph Hellwig 		mb(); /* prevent loop optimization */
9580dcf0a7SChristoph Hellwig 		tmpl->xor_gen(b1, srcs, 1, BENCH_SIZE);
969e229025SChristoph Hellwig 		mb();
979e229025SChristoph Hellwig 	} while (reps++ < REPS || (t0 = ktime_get()) == start);
989e229025SChristoph Hellwig 	min = ktime_sub(t0, start);
999e229025SChristoph Hellwig 
1009e229025SChristoph Hellwig 	preempt_enable();
1019e229025SChristoph Hellwig 
1029e229025SChristoph Hellwig 	// bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s]
1039e229025SChristoph Hellwig 	speed = (1000 * reps * BENCH_SIZE) / (unsigned int)ktime_to_ns(min);
1049e229025SChristoph Hellwig 	tmpl->speed = speed;
1059e229025SChristoph Hellwig 
1069e229025SChristoph Hellwig 	pr_info("   %-16s: %5d MB/sec\n", tmpl->name, speed);
1079e229025SChristoph Hellwig }
1089e229025SChristoph Hellwig 
1090471415fSChristoph Hellwig static int __init calibrate_xor_blocks(void)
1109e229025SChristoph Hellwig {
1119e229025SChristoph Hellwig 	void *b1, *b2;
1129e229025SChristoph Hellwig 	struct xor_block_template *f, *fastest;
1139e229025SChristoph Hellwig 
114*a21921ddSChristoph Hellwig 	if (forced_template)
1150471415fSChristoph Hellwig 		return 0;
1169e229025SChristoph Hellwig 
1179e229025SChristoph Hellwig 	b1 = (void *) __get_free_pages(GFP_KERNEL, 2);
1189e229025SChristoph Hellwig 	if (!b1) {
1190471415fSChristoph Hellwig 		pr_warn("xor: Yikes!  No memory available.\n");
1209e229025SChristoph Hellwig 		return -ENOMEM;
1219e229025SChristoph Hellwig 	}
1229e229025SChristoph Hellwig 	b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE;
1239e229025SChristoph Hellwig 
1240471415fSChristoph Hellwig 	pr_info("xor: measuring software checksum speed\n");
1259e229025SChristoph Hellwig 	fastest = template_list;
1260471415fSChristoph Hellwig 	for (f = template_list; f; f = f->next) {
1270471415fSChristoph Hellwig 		do_xor_speed(f, b1, b2);
1289e229025SChristoph Hellwig 		if (f->speed > fastest->speed)
1299e229025SChristoph Hellwig 			fastest = f;
1300471415fSChristoph Hellwig 	}
131*a21921ddSChristoph Hellwig 	static_call_update(xor_gen_impl, fastest->xor_gen);
1329e229025SChristoph Hellwig 	pr_info("xor: using function: %s (%d MB/sec)\n",
1339e229025SChristoph Hellwig 	       fastest->name, fastest->speed);
1349e229025SChristoph Hellwig 
1359e229025SChristoph Hellwig 	free_pages((unsigned long)b1, 2);
1369e229025SChristoph Hellwig 	return 0;
1379e229025SChristoph Hellwig }
1389e229025SChristoph Hellwig 
139e20043b4SChristoph Hellwig #ifdef CONFIG_XOR_BLOCKS_ARCH
140e20043b4SChristoph Hellwig #include "xor_arch.h" /* $SRCARCH/xor_arch.h */
14135ebc4deSChristoph Hellwig #else
142e20043b4SChristoph Hellwig static void __init arch_xor_init(void)
143e20043b4SChristoph Hellwig {
14435ebc4deSChristoph Hellwig 	xor_register(&xor_block_8regs);
14535ebc4deSChristoph Hellwig 	xor_register(&xor_block_8regs_p);
14635ebc4deSChristoph Hellwig 	xor_register(&xor_block_32regs);
14735ebc4deSChristoph Hellwig 	xor_register(&xor_block_32regs_p);
148e20043b4SChristoph Hellwig }
149e20043b4SChristoph Hellwig #endif /* CONFIG_XOR_BLOCKS_ARCH */
150e20043b4SChristoph Hellwig 
151e20043b4SChristoph Hellwig static int __init xor_init(void)
152e20043b4SChristoph Hellwig {
153e20043b4SChristoph Hellwig 	arch_xor_init();
15435ebc4deSChristoph Hellwig 
1550471415fSChristoph Hellwig 	/*
1560471415fSChristoph Hellwig 	 * If this arch/cpu has a short-circuited selection, don't loop through
1570471415fSChristoph Hellwig 	 * all the possible functions, just use the best one.
1580471415fSChristoph Hellwig 	 */
159*a21921ddSChristoph Hellwig 	if (forced_template) {
1600471415fSChristoph Hellwig 		pr_info("xor: automatically using best checksumming function   %-10s\n",
161*a21921ddSChristoph Hellwig 			forced_template->name);
162*a21921ddSChristoph Hellwig 		static_call_update(xor_gen_impl, forced_template->xor_gen);
1630471415fSChristoph Hellwig 		return 0;
1640471415fSChristoph Hellwig 	}
1650471415fSChristoph Hellwig 
1660471415fSChristoph Hellwig #ifdef MODULE
1670471415fSChristoph Hellwig 	return calibrate_xor_blocks();
1680471415fSChristoph Hellwig #else
1690471415fSChristoph Hellwig 	/*
1700471415fSChristoph Hellwig 	 * Pick the first template as the temporary default until calibration
1710471415fSChristoph Hellwig 	 * happens.
1720471415fSChristoph Hellwig 	 */
173*a21921ddSChristoph Hellwig 	static_call_update(xor_gen_impl, template_list->xor_gen);
1740471415fSChristoph Hellwig 	return 0;
1750471415fSChristoph Hellwig #endif
1760471415fSChristoph Hellwig }
1770471415fSChristoph Hellwig 
1780471415fSChristoph Hellwig static __exit void xor_exit(void)
1790471415fSChristoph Hellwig {
1800471415fSChristoph Hellwig }
1819e229025SChristoph Hellwig 
1829e229025SChristoph Hellwig MODULE_DESCRIPTION("RAID-5 checksumming functions");
1839e229025SChristoph Hellwig MODULE_LICENSE("GPL");
1849e229025SChristoph Hellwig 
1850471415fSChristoph Hellwig /*
1860471415fSChristoph Hellwig  * When built-in we must register the default template before md, but we don't
1870471415fSChristoph Hellwig  * want calibration to run that early as that would delay the boot process.
1880471415fSChristoph Hellwig  */
1899e229025SChristoph Hellwig #ifndef MODULE
1900471415fSChristoph Hellwig __initcall(calibrate_xor_blocks);
1919e229025SChristoph Hellwig #endif
1920471415fSChristoph Hellwig core_initcall(xor_init);
1939e229025SChristoph Hellwig module_exit(xor_exit);
194