Skip to content

Commit

Permalink
Add AltiVec RAID-Z
Browse files Browse the repository at this point in the history
Implements the RAID-Z function using AltiVec SIMD.
This is basically the NEON code translated to AltiVec.

Note that the 'fletcher' algorithm requires 64-bits
operations, and the initial implementations of AltiVec
(PPC74xx a.k.a. G4, PPC970 a.k.a. G5) only has up to
32-bits operations, so no 'fletcher'.

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Romain Dolbeau <[email protected]>
Closes openzfs#9539
  • Loading branch information
rdolbeau authored and behlendorf committed Jan 23, 2020
1 parent 1a69856 commit 35b0749
Show file tree
Hide file tree
Showing 12 changed files with 5,200 additions and 1 deletion.
1 change: 1 addition & 0 deletions cmd/raidz_test/raidz_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static const char *raidz_impl_names[] = {
"avx512bw",
"aarch64_neon",
"aarch64_neonx2",
"powerpc_altivec",
NULL
};

Expand Down
1 change: 1 addition & 0 deletions include/os/linux/kernel/linux/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ KERNEL_H = \
$(top_srcdir)/include/os/linux/kernel/linux/simd.h \
$(top_srcdir)/include/os/linux/kernel/linux/simd_x86.h \
$(top_srcdir)/include/os/linux/kernel/linux/simd_aarch64.h \
$(top_srcdir)/include/os/linux/kernel/linux/simd_powerpc.h \
$(top_srcdir)/include/os/linux/kernel/linux/mod_compat.h \
$(top_srcdir)/include/os/linux/kernel/linux/page_compat.h \
$(top_srcdir)/include/os/linux/kernel/linux/compiler_compat.h
Expand Down
3 changes: 3 additions & 0 deletions include/os/linux/kernel/linux/simd.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@

#elif defined(__aarch64__)
#include <linux/simd_aarch64.h>

#elif defined(__powerpc__)
#include <linux/simd_powerpc.h>
#else

#define kfpu_allowed() 0
Expand Down
109 changes: 109 additions & 0 deletions include/os/linux/kernel/linux/simd_powerpc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (C) 2019 Romain Dolbeau
* <[email protected]>
*/

/*
* USER API:
*
* Kernel fpu methods:
* kfpu_allowed()
* kfpu_begin()
* kfpu_end()
* kfpu_init()
* kfpu_fini()
*
* SIMD support:
*
* Following functions should be called to determine whether CPU feature
* is supported. All functions are usable in kernel and user space.
* If a SIMD algorithm is using more than one instruction set
* all relevant feature test functions should be called.
*
* Supported features:
* zfs_altivec_available()
*/

#ifndef _LINUX_SIMD_POWERPC_H
#define _LINUX_SIMD_POWERPC_H

/* only for __powerpc__ */
#if defined(__powerpc__)

#include <linux/preempt.h>
#include <linux/export.h>
#include <linux/sched.h>
#include <asm/switch_to.h>
#include <sys/types.h>
#include <linux/version.h>

#define kfpu_allowed() 1
#define kfpu_begin() \
{ \
preempt_disable(); \
enable_kernel_altivec(); \
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
#define kfpu_end() \
{ \
disable_kernel_altivec(); \
preempt_enable(); \
}
#else
/* seems that before 4.5 no-one bothered disabling ... */
#define kfpu_end() preempt_enable()
#endif
#define kfpu_init() 0
#define kfpu_fini() ((void) 0)

/*
* Check if AltiVec instruction set is available
*/
static inline boolean_t
zfs_altivec_available(void)
{
boolean_t res;
/* suggested by macallan at netbsd dot org */
#if defined(__powerpc64__)
u64 msr;
#else
u32 msr;
#endif
kfpu_begin();
__asm volatile("mfmsr %0" : "=r"(msr));
/*
* 64 bits -> need to check bit 38
* Power ISA Version 3.0B
* p944
* 32 bits -> Need to check bit 6
* AltiVec Technology Programming Environments Manual
* p49 (2-9)
* They are the same, as ppc counts 'backward' ...
*/
res = (msr & 0x2000000) != 0;
kfpu_end();
return (res);
}
#endif /* defined(__powerpc) */

#endif /* _LINUX_SIMD_POWERPC_H */
5 changes: 4 additions & 1 deletion include/sys/vdev_raidz_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ typedef boolean_t (*will_work_f)(void);
typedef void (*init_impl_f)(void);
typedef void (*fini_impl_f)(void);

#define RAIDZ_IMPL_NAME_MAX (16)
#define RAIDZ_IMPL_NAME_MAX (20)

typedef struct raidz_impl_ops {
init_impl_f init;
Expand Down Expand Up @@ -152,6 +152,9 @@ extern const raidz_impl_ops_t vdev_raidz_avx512bw_impl;
extern const raidz_impl_ops_t vdev_raidz_aarch64_neon_impl;
extern const raidz_impl_ops_t vdev_raidz_aarch64_neonx2_impl;
#endif
#if defined(__powerpc__)
extern const raidz_impl_ops_t vdev_raidz_powerpc_altivec_impl;
#endif

/*
* Commonly used raidz_map helpers
Expand Down
40 changes: 40 additions & 0 deletions lib/libspl/include/sys/simd.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,46 @@ zfs_avx512vbmi_available(void)
#define kfpu_begin() do {} while (0)
#define kfpu_end() do {} while (0)

#elif defined(__powerpc__)

#define kfpu_allowed() 1
#define kfpu_initialize(tsk) do {} while (0)
#define kfpu_begin() do {} while (0)
#define kfpu_end() do {} while (0)

/*
* Check if AltiVec instruction set is available
* No easy way beyond 'altivec works' :-(
*/
#include <signal.h>
#include <setjmp.h>

#ifdef __ALTIVEC__
static jmp_buf env;
static void sigillhandler(int x)
{
longjmp(env, 1);
}
#endif

static inline boolean_t
zfs_altivec_available(void)
{
boolean_t has_altivec = B_FALSE;
#ifdef __ALTIVEC__
sighandler_t savesig;
savesig = signal(SIGILL, sigillhandler);
if (setjmp(env)) {
signal(SIGILL, savesig);
has_altivec = B_FALSE;
} else {
__asm__ __volatile__("vor 0,0,0\n" : : : "v0");
signal(SIGILL, savesig);
has_altivec = B_TRUE;
}
#endif
return (has_altivec);
}
#else

#define kfpu_allowed() 0
Expand Down
6 changes: 6 additions & 0 deletions lib/libzpool/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ KERNEL_C = \
vdev_raidz_math_scalar.c \
vdev_raidz_math_sse2.c \
vdev_raidz_math_ssse3.c \
vdev_raidz_math_powerpc_altivec.c \
vdev_removal.c \
vdev_root.c \
vdev_trim.c \
Expand Down Expand Up @@ -201,3 +202,8 @@ libzpool_la_LIBADD += $(ZLIB) -ldl
libzpool_la_LDFLAGS = -pthread -version-info 2:0:0

EXTRA_DIST = $(USER_C)

if TARGET_CPU_POWERPC
vdev_raidz_math_powerpc_altivec.$(OBJEXT): CFLAGS += -maltivec
vdev_raidz_math_powerpc_altivec.l$(OBJEXT): CFLAGS += -maltivec
endif
1 change: 1 addition & 0 deletions man/man5/zfs-module-parameters.5
Original file line number Diff line number Diff line change
Expand Up @@ -3374,6 +3374,7 @@ Possible options are:
avx512bw - implementation using AVX512F & AVX512BW instruction sets (64bit x86 only)
aarch64_neon - implementation using NEON (Aarch64/64 bit ARMv8 only)
aarch64_neonx2 - implementation using NEON with more unrolling (Aarch64/64 bit ARMv8 only)
powerpc_altivec - implementation using Altivec (PowerPC only)
.sp
Default value: \fBfastest\fR.
.RE
Expand Down
7 changes: 7 additions & 0 deletions module/zfs/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,11 @@ $(MODULE)-$(CONFIG_X86) += vdev_raidz_math_avx512bw.o
$(MODULE)-$(CONFIG_ARM64) += vdev_raidz_math_aarch64_neon.o
$(MODULE)-$(CONFIG_ARM64) += vdev_raidz_math_aarch64_neonx2.o

$(MODULE)-$(CONFIG_PPC) += vdev_raidz_math_powerpc_altivec.o
$(MODULE)-$(CONFIG_PPC64) += vdev_raidz_math_powerpc_altivec.o

ifeq ($(CONFIG_ALTIVEC),y)
$(obj)/vdev_raidz_math_powerpc_altivec.o: c_flags += -maltivec
endif

-include @abs_top_builddir@/module/os/linux/zfs/Makefile
3 changes: 3 additions & 0 deletions module/zfs/vdev_raidz_math.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ const raidz_impl_ops_t *raidz_all_maths[] = {
&vdev_raidz_aarch64_neon_impl,
&vdev_raidz_aarch64_neonx2_impl,
#endif
#if defined(__powerpc__)
&vdev_raidz_powerpc_altivec_impl,
#endif
};

/* Indicate that benchmark has been completed */
Expand Down
Loading

0 comments on commit 35b0749

Please sign in to comment.