xref: /linux/lib/raid6/vpermxor.uc (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1751ba79cSMatt Brown/*
2751ba79cSMatt Brown * Copyright 2017, Matt Brown, IBM Corp.
3751ba79cSMatt Brown *
4751ba79cSMatt Brown * This program is free software; you can redistribute it and/or
5751ba79cSMatt Brown * modify it under the terms of the GNU General Public License
6751ba79cSMatt Brown * as published by the Free Software Foundation; either version
7751ba79cSMatt Brown * 2 of the License, or (at your option) any later version.
8751ba79cSMatt Brown *
9751ba79cSMatt Brown * vpermxor$#.c
10751ba79cSMatt Brown *
11751ba79cSMatt Brown * Based on H. Peter Anvin's paper - The mathematics of RAID-6
12751ba79cSMatt Brown *
13751ba79cSMatt Brown * $#-way unrolled portable integer math RAID-6 instruction set
14751ba79cSMatt Brown * This file is postprocessed using unroll.awk
15751ba79cSMatt Brown *
16751ba79cSMatt Brown * vpermxor$#.c makes use of the vpermxor instruction to optimise the RAID6 Q
17751ba79cSMatt Brown * syndrome calculations.
18751ba79cSMatt Brown * This can be run on systems which have both Altivec and vpermxor instruction.
19751ba79cSMatt Brown *
20751ba79cSMatt Brown * This instruction was introduced in POWER8 - ISA v2.07.
21751ba79cSMatt Brown */
22751ba79cSMatt Brown
23751ba79cSMatt Brown#include <linux/raid/pq.h>
24751ba79cSMatt Brown#ifdef CONFIG_ALTIVEC
25751ba79cSMatt Brown
26751ba79cSMatt Brown#include <altivec.h>
27*5b401e4eSPaul Menzel#include <asm/ppc-opcode.h>
28751ba79cSMatt Brown#ifdef __KERNEL__
29751ba79cSMatt Brown#include <asm/cputable.h>
30751ba79cSMatt Brown#include <asm/switch_to.h>
31751ba79cSMatt Brown#endif
32751ba79cSMatt Brown
33751ba79cSMatt Browntypedef vector unsigned char unative_t;
34751ba79cSMatt Brown#define NSIZE sizeof(unative_t)
35751ba79cSMatt Brown
36751ba79cSMatt Brownstatic const vector unsigned char gf_low = {0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14,
37751ba79cSMatt Brown					    0x12, 0x10, 0x0e, 0x0c, 0x0a, 0x08,
38751ba79cSMatt Brown					    0x06, 0x04, 0x02,0x00};
39751ba79cSMatt Brownstatic const vector unsigned char gf_high = {0xfd, 0xdd, 0xbd, 0x9d, 0x7d, 0x5d,
40751ba79cSMatt Brown					     0x3d, 0x1d, 0xe0, 0xc0, 0xa0, 0x80,
41751ba79cSMatt Brown					     0x60, 0x40, 0x20, 0x00};
42751ba79cSMatt Brown
43751ba79cSMatt Brownstatic void noinline raid6_vpermxor$#_gen_syndrome_real(int disks, size_t bytes,
44751ba79cSMatt Brown							void **ptrs)
45751ba79cSMatt Brown{
46751ba79cSMatt Brown	u8 **dptr = (u8 **)ptrs;
47751ba79cSMatt Brown	u8 *p, *q;
48751ba79cSMatt Brown	int d, z, z0;
49751ba79cSMatt Brown	unative_t wp$$, wq$$, wd$$;
50751ba79cSMatt Brown
51751ba79cSMatt Brown	z0 = disks - 3;		/* Highest data disk */
52751ba79cSMatt Brown	p = dptr[z0+1];		/* XOR parity */
53751ba79cSMatt Brown	q = dptr[z0+2];		/* RS syndrome */
54751ba79cSMatt Brown
55751ba79cSMatt Brown	for (d = 0; d < bytes; d += NSIZE*$#) {
56751ba79cSMatt Brown		wp$$ = wq$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE];
57751ba79cSMatt Brown
58751ba79cSMatt Brown		for (z = z0-1; z>=0; z--) {
59751ba79cSMatt Brown			wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE];
60751ba79cSMatt Brown			/* P syndrome */
61751ba79cSMatt Brown			wp$$ = vec_xor(wp$$, wd$$);
62751ba79cSMatt Brown
63751ba79cSMatt Brown			/* Q syndrome */
64751ba79cSMatt Brown			asm(VPERMXOR(%0,%1,%2,%3):"=v"(wq$$):"v"(gf_high), "v"(gf_low), "v"(wq$$));
65751ba79cSMatt Brown			wq$$ = vec_xor(wq$$, wd$$);
66751ba79cSMatt Brown		}
67751ba79cSMatt Brown		*(unative_t *)&p[d+NSIZE*$$] = wp$$;
68751ba79cSMatt Brown		*(unative_t *)&q[d+NSIZE*$$] = wq$$;
69751ba79cSMatt Brown	}
70751ba79cSMatt Brown}
71751ba79cSMatt Brown
72751ba79cSMatt Brownstatic void raid6_vpermxor$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
73751ba79cSMatt Brown{
74751ba79cSMatt Brown	preempt_disable();
75751ba79cSMatt Brown	enable_kernel_altivec();
76751ba79cSMatt Brown
77751ba79cSMatt Brown	raid6_vpermxor$#_gen_syndrome_real(disks, bytes, ptrs);
78751ba79cSMatt Brown
79751ba79cSMatt Brown	disable_kernel_altivec();
80751ba79cSMatt Brown	preempt_enable();
81751ba79cSMatt Brown}
82751ba79cSMatt Brown
83751ba79cSMatt Brownint raid6_have_altivec_vpermxor(void);
84751ba79cSMatt Brown#if $# == 1
85751ba79cSMatt Brownint raid6_have_altivec_vpermxor(void)
86751ba79cSMatt Brown{
87751ba79cSMatt Brown	/* Check if arch has both altivec and the vpermxor instructions */
88751ba79cSMatt Brown# ifdef __KERNEL__
89751ba79cSMatt Brown	return (cpu_has_feature(CPU_FTR_ALTIVEC_COMP) &&
90751ba79cSMatt Brown		cpu_has_feature(CPU_FTR_ARCH_207S));
91751ba79cSMatt Brown# else
92751ba79cSMatt Brown	return 1;
93751ba79cSMatt Brown#endif
94751ba79cSMatt Brown
95751ba79cSMatt Brown}
96751ba79cSMatt Brown#endif
97751ba79cSMatt Brown
98751ba79cSMatt Brownconst struct raid6_calls raid6_vpermxor$# = {
99751ba79cSMatt Brown	raid6_vpermxor$#_gen_syndrome,
100751ba79cSMatt Brown	NULL,
101751ba79cSMatt Brown	raid6_have_altivec_vpermxor,
102751ba79cSMatt Brown	"vpermxor$#",
103751ba79cSMatt Brown	0
104751ba79cSMatt Brown};
105751ba79cSMatt Brown#endif
106