xref: /linux/arch/sparc/lib/crc32_glue.c (revision 37b33c68b00089a574ebd0a856a5d554eb3001b7)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Glue code for CRC32C optimized for sparc64 crypto opcodes.
3  *
4  * This is based largely upon arch/x86/crypto/crc32c-intel.c
5  *
6  * Copyright (C) 2008 Intel Corporation
7  * Authors: Austin Zhang <austin_zhang@linux.intel.com>
8  *          Kent Liu <kent.liu@intel.com>
9  */
10 
11 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
12 
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/crc32.h>
17 #include <asm/pstate.h>
18 #include <asm/elf.h>
19 
20 static DEFINE_STATIC_KEY_FALSE(have_crc32c_opcode);
21 
crc32_le_arch(u32 crc,const u8 * data,size_t len)22 u32 crc32_le_arch(u32 crc, const u8 *data, size_t len)
23 {
24 	return crc32_le_base(crc, data, len);
25 }
26 EXPORT_SYMBOL(crc32_le_arch);
27 
28 void crc32c_sparc64(u32 *crcp, const u64 *data, size_t len);
29 
crc32c_le_arch(u32 crc,const u8 * data,size_t len)30 u32 crc32c_le_arch(u32 crc, const u8 *data, size_t len)
31 {
32 	size_t n = -(uintptr_t)data & 7;
33 
34 	if (!static_branch_likely(&have_crc32c_opcode))
35 		return crc32c_le_base(crc, data, len);
36 
37 	if (n) {
38 		/* Data isn't 8-byte aligned.  Align it. */
39 		n = min(n, len);
40 		crc = crc32c_le_base(crc, data, n);
41 		data += n;
42 		len -= n;
43 	}
44 	n = len & ~7U;
45 	if (n) {
46 		crc32c_sparc64(&crc, (const u64 *)data, n);
47 		data += n;
48 		len -= n;
49 	}
50 	if (len)
51 		crc = crc32c_le_base(crc, data, len);
52 	return crc;
53 }
54 EXPORT_SYMBOL(crc32c_le_arch);
55 
crc32_be_arch(u32 crc,const u8 * data,size_t len)56 u32 crc32_be_arch(u32 crc, const u8 *data, size_t len)
57 {
58 	return crc32_be_base(crc, data, len);
59 }
60 EXPORT_SYMBOL(crc32_be_arch);
61 
crc32_sparc_init(void)62 static int __init crc32_sparc_init(void)
63 {
64 	unsigned long cfr;
65 
66 	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
67 		return 0;
68 
69 	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
70 	if (!(cfr & CFR_CRC32C))
71 		return 0;
72 
73 	static_branch_enable(&have_crc32c_opcode);
74 	pr_info("Using sparc64 crc32c opcode optimized CRC32C implementation\n");
75 	return 0;
76 }
77 arch_initcall(crc32_sparc_init);
78 
crc32_sparc_exit(void)79 static void __exit crc32_sparc_exit(void)
80 {
81 }
82 module_exit(crc32_sparc_exit);
83 
crc32_optimizations(void)84 u32 crc32_optimizations(void)
85 {
86 	if (static_key_enabled(&have_crc32c_opcode))
87 		return CRC32C_OPTIMIZATION;
88 	return 0;
89 }
90 EXPORT_SYMBOL(crc32_optimizations);
91 
92 MODULE_LICENSE("GPL");
93 MODULE_DESCRIPTION("CRC32c (Castagnoli), sparc64 crc32c opcode accelerated");
94