xref: /OK3568_Linux_fs/kernel/lib/raid6/vpermxor.uc (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/*
2*4882a593Smuzhiyun * Copyright 2017, Matt Brown, IBM Corp.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
5*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License
6*4882a593Smuzhiyun * as published by the Free Software Foundation; either version
7*4882a593Smuzhiyun * 2 of the License, or (at your option) any later version.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * vpermxor$#.c
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Based on H. Peter Anvin's paper - The mathematics of RAID-6
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * $#-way unrolled portable integer math RAID-6 instruction set
14*4882a593Smuzhiyun * This file is postprocessed using unroll.awk
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * vpermxor$#.c makes use of the vpermxor instruction to optimise the RAID6 Q
17*4882a593Smuzhiyun * syndrome calculations.
18*4882a593Smuzhiyun * This can be run on systems which have both Altivec and vpermxor instruction.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * This instruction was introduced in POWER8 - ISA v2.07.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun#include <linux/raid/pq.h>
24*4882a593Smuzhiyun#ifdef CONFIG_ALTIVEC
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun#include <altivec.h>
27*4882a593Smuzhiyun#ifdef __KERNEL__
28*4882a593Smuzhiyun#include <asm/cputable.h>
29*4882a593Smuzhiyun#include <asm/ppc-opcode.h>
30*4882a593Smuzhiyun#include <asm/switch_to.h>
31*4882a593Smuzhiyun#endif
32*4882a593Smuzhiyun
33*4882a593Smuzhiyuntypedef vector unsigned char unative_t;
34*4882a593Smuzhiyun#define NSIZE sizeof(unative_t)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyunstatic const vector unsigned char gf_low = {0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14,
37*4882a593Smuzhiyun					    0x12, 0x10, 0x0e, 0x0c, 0x0a, 0x08,
38*4882a593Smuzhiyun					    0x06, 0x04, 0x02,0x00};
39*4882a593Smuzhiyunstatic const vector unsigned char gf_high = {0xfd, 0xdd, 0xbd, 0x9d, 0x7d, 0x5d,
40*4882a593Smuzhiyun					     0x3d, 0x1d, 0xe0, 0xc0, 0xa0, 0x80,
41*4882a593Smuzhiyun					     0x60, 0x40, 0x20, 0x00};
42*4882a593Smuzhiyun
43*4882a593Smuzhiyunstatic void noinline raid6_vpermxor$#_gen_syndrome_real(int disks, size_t bytes,
44*4882a593Smuzhiyun							void **ptrs)
45*4882a593Smuzhiyun{
46*4882a593Smuzhiyun	u8 **dptr = (u8 **)ptrs;
47*4882a593Smuzhiyun	u8 *p, *q;
48*4882a593Smuzhiyun	int d, z, z0;
49*4882a593Smuzhiyun	unative_t wp$$, wq$$, wd$$;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun	z0 = disks - 3;		/* Highest data disk */
52*4882a593Smuzhiyun	p = dptr[z0+1];		/* XOR parity */
53*4882a593Smuzhiyun	q = dptr[z0+2];		/* RS syndrome */
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun	for (d = 0; d < bytes; d += NSIZE*$#) {
56*4882a593Smuzhiyun		wp$$ = wq$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE];
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun		for (z = z0-1; z>=0; z--) {
59*4882a593Smuzhiyun			wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE];
60*4882a593Smuzhiyun			/* P syndrome */
61*4882a593Smuzhiyun			wp$$ = vec_xor(wp$$, wd$$);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun			/* Q syndrome */
64*4882a593Smuzhiyun			asm(VPERMXOR(%0,%1,%2,%3):"=v"(wq$$):"v"(gf_high), "v"(gf_low), "v"(wq$$));
65*4882a593Smuzhiyun			wq$$ = vec_xor(wq$$, wd$$);
66*4882a593Smuzhiyun		}
67*4882a593Smuzhiyun		*(unative_t *)&p[d+NSIZE*$$] = wp$$;
68*4882a593Smuzhiyun		*(unative_t *)&q[d+NSIZE*$$] = wq$$;
69*4882a593Smuzhiyun	}
70*4882a593Smuzhiyun}
71*4882a593Smuzhiyun
72*4882a593Smuzhiyunstatic void raid6_vpermxor$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
73*4882a593Smuzhiyun{
74*4882a593Smuzhiyun	preempt_disable();
75*4882a593Smuzhiyun	enable_kernel_altivec();
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun	raid6_vpermxor$#_gen_syndrome_real(disks, bytes, ptrs);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun	disable_kernel_altivec();
80*4882a593Smuzhiyun	preempt_enable();
81*4882a593Smuzhiyun}
82*4882a593Smuzhiyun
83*4882a593Smuzhiyunint raid6_have_altivec_vpermxor(void);
84*4882a593Smuzhiyun#if $# == 1
85*4882a593Smuzhiyunint raid6_have_altivec_vpermxor(void)
86*4882a593Smuzhiyun{
87*4882a593Smuzhiyun	/* Check if arch has both altivec and the vpermxor instructions */
88*4882a593Smuzhiyun# ifdef __KERNEL__
89*4882a593Smuzhiyun	return (cpu_has_feature(CPU_FTR_ALTIVEC_COMP) &&
90*4882a593Smuzhiyun		cpu_has_feature(CPU_FTR_ARCH_207S));
91*4882a593Smuzhiyun# else
92*4882a593Smuzhiyun	return 1;
93*4882a593Smuzhiyun#endif
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun}
96*4882a593Smuzhiyun#endif
97*4882a593Smuzhiyun
98*4882a593Smuzhiyunconst struct raid6_calls raid6_vpermxor$# = {
99*4882a593Smuzhiyun	raid6_vpermxor$#_gen_syndrome,
100*4882a593Smuzhiyun	NULL,
101*4882a593Smuzhiyun	raid6_have_altivec_vpermxor,
102*4882a593Smuzhiyun	"vpermxor$#",
103*4882a593Smuzhiyun	0
104*4882a593Smuzhiyun};
105*4882a593Smuzhiyun#endif
106