1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or https://opensource.org/licenses/CDDL-1.0.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (C) 2019 Romain Dolbeau
23  *           <romain.dolbeau@european-processor-initiative.eu>
24  * Copyright (C) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
25  */
26 
27 /*
28  * USER API:
29  *
30  * Kernel fpu methods:
31  *	kfpu_allowed()
32  *	kfpu_begin()
33  *	kfpu_end()
34  *	kfpu_init()
35  *	kfpu_fini()
36  *
37  * SIMD support:
38  *
39  * Following functions should be called to determine whether CPU feature
40  * is supported. All functions are usable in kernel and user space.
41  * If a SIMD algorithm is using more than one instruction set
42  * all relevant feature test functions should be called.
43  *
44  * Supported features:
45  *   zfs_altivec_available()
46  *   zfs_vsx_available()
47  *   zfs_isa207_available()
48  */
49 
50 #ifndef _LINUX_SIMD_POWERPC_H
51 #define	_LINUX_SIMD_POWERPC_H
52 
53 #include <linux/preempt.h>
54 #include <linux/export.h>
55 #include <linux/sched.h>
56 #include <asm/switch_to.h>
57 #include <sys/types.h>
58 #include <linux/version.h>
59 
60 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
61 #include <asm/cpufeature.h>
62 #else
63 #include <asm/cputable.h>
64 #endif
65 
66 #define	kfpu_allowed()			1
67 
68 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
69 #ifdef	CONFIG_ALTIVEC
70 #define	ENABLE_KERNEL_ALTIVEC	enable_kernel_altivec();
71 #define	DISABLE_KERNEL_ALTIVEC	disable_kernel_altivec();
72 #else
73 #define	ENABLE_KERNEL_ALTIVEC
74 #define	DISABLE_KERNEL_ALTIVEC
75 #endif
76 #ifdef	CONFIG_VSX
77 #define	ENABLE_KERNEL_VSX	enable_kernel_vsx();
78 #define	DISABLE_KERNEL_VSX	disable_kernel_vsx();
79 #else
80 #define	ENABLE_KERNEL_VSX
81 #define	DISABLE_KERNEL_VSX
82 #endif
83 #ifdef	CONFIG_SPE
84 #define	ENABLE_KERNEL_SPE	enable_kernel_spe();
85 #define	DISABLE_KERNEL_SPE	disable_kernel_spe();
86 #else
87 #define	ENABLE_KERNEL_SPE
88 #define	DISABLE_KERNEL_SPE
89 #endif
90 #define	kfpu_begin()				\
91 	{					\
92 		preempt_disable();		\
93 		ENABLE_KERNEL_ALTIVEC		\
94 		ENABLE_KERNEL_VSX		\
95 		ENABLE_KERNEL_SPE		\
96 	}
97 #define	kfpu_end()				\
98 	{					\
99 		DISABLE_KERNEL_SPE		\
100 		DISABLE_KERNEL_VSX		\
101 		DISABLE_KERNEL_ALTIVEC		\
102 		preempt_enable();		\
103 	}
104 #else
105 /* seems that before 4.5 no-one bothered */
106 #define	kfpu_begin()
107 #define	kfpu_end()		preempt_enable()
108 #endif	/* Linux version >= 4.5 */
109 
110 #define	kfpu_init()		0
111 #define	kfpu_fini()		((void) 0)
112 
113 /*
114  * Linux 4.7 makes cpu_has_feature to use jump labels on powerpc if
115  * CONFIG_JUMP_LABEL_FEATURE_CHECKS is enabled, in this case however it
116  * references GPL-only symbol cpu_feature_keys. Therefore we overrides this
117  * interface when it is detected being GPL-only.
118  */
119 #if defined(CONFIG_JUMP_LABEL_FEATURE_CHECKS) && \
120     defined(HAVE_CPU_HAS_FEATURE_GPL_ONLY)
121 #define	cpu_has_feature(feature)	early_cpu_has_feature(feature)
122 #endif
123 
124 /*
125  * Check if AltiVec instruction set is available
126  */
127 static inline boolean_t
zfs_altivec_available(void)128 zfs_altivec_available(void)
129 {
130 	return (cpu_has_feature(CPU_FTR_ALTIVEC));
131 }
132 
133 /*
134  * Check if VSX is available
135  */
136 static inline boolean_t
zfs_vsx_available(void)137 zfs_vsx_available(void)
138 {
139 	return (cpu_has_feature(CPU_FTR_VSX));
140 }
141 
142 /*
143  * Check if POWER ISA 2.07 is available (SHA2)
144  */
145 static inline boolean_t
zfs_isa207_available(void)146 zfs_isa207_available(void)
147 {
148 	return (cpu_has_feature(CPU_FTR_ARCH_207S));
149 }
150 
151 #endif /* _LINUX_SIMD_POWERPC_H */
152