Input: i8042 - fix strange behavior of touchpad on Clevo NS70PU
[platform/kernel/linux-rpi.git] / lib / raid6 / recov_loongarch_simd.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * RAID6 recovery algorithms in LoongArch SIMD (LSX & LASX)
4  *
5  * Copyright (C) 2023 WANG Xuerui <git@xen0n.name>
6  *
7  * Originally based on recov_avx2.c and recov_ssse3.c:
8  *
9  * Copyright (C) 2012 Intel Corporation
10  * Author: Jim Kukunas <james.t.kukunas@linux.intel.com>
11  */
12
13 #include <linux/raid/pq.h>
14 #include "loongarch.h"
15
16 /*
17  * Unlike with the syndrome calculation algorithms, there's no boot-time
18  * selection of recovery algorithms by benchmarking, so we have to specify
19  * the priorities and hope the future cores will all have decent vector
20  * support (i.e. no LASX slower than LSX, or even scalar code).
21  */
22
23 #ifdef CONFIG_CPU_HAS_LSX
24 static int raid6_has_lsx(void)
25 {
26         return cpu_has_lsx;
27 }
28
29 static void raid6_2data_recov_lsx(int disks, size_t bytes, int faila,
30                                   int failb, void **ptrs)
31 {
32         u8 *p, *q, *dp, *dq;
33         const u8 *pbmul;        /* P multiplier table for B data */
34         const u8 *qmul;         /* Q multiplier table (for both) */
35
36         p = (u8 *)ptrs[disks - 2];
37         q = (u8 *)ptrs[disks - 1];
38
39         /*
40          * Compute syndrome with zero for the missing data pages
41          * Use the dead data pages as temporary storage for
42          * delta p and delta q
43          */
44         dp = (u8 *)ptrs[faila];
45         ptrs[faila] = (void *)raid6_empty_zero_page;
46         ptrs[disks - 2] = dp;
47         dq = (u8 *)ptrs[failb];
48         ptrs[failb] = (void *)raid6_empty_zero_page;
49         ptrs[disks - 1] = dq;
50
51         raid6_call.gen_syndrome(disks, bytes, ptrs);
52
53         /* Restore pointer table */
54         ptrs[faila] = dp;
55         ptrs[failb] = dq;
56         ptrs[disks - 2] = p;
57         ptrs[disks - 1] = q;
58
59         /* Now, pick the proper data tables */
60         pbmul = raid6_vgfmul[raid6_gfexi[failb - faila]];
61         qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^ raid6_gfexp[failb]]];
62
63         kernel_fpu_begin();
64
65         /*
66          * vr20, vr21: qmul
67          * vr22, vr23: pbmul
68          */
69         asm volatile("vld $vr20, %0" : : "m" (qmul[0]));
70         asm volatile("vld $vr21, %0" : : "m" (qmul[16]));
71         asm volatile("vld $vr22, %0" : : "m" (pbmul[0]));
72         asm volatile("vld $vr23, %0" : : "m" (pbmul[16]));
73
74         while (bytes) {
75                 /* vr4 - vr7: Q */
76                 asm volatile("vld $vr4, %0" : : "m" (q[0]));
77                 asm volatile("vld $vr5, %0" : : "m" (q[16]));
78                 asm volatile("vld $vr6, %0" : : "m" (q[32]));
79                 asm volatile("vld $vr7, %0" : : "m" (q[48]));
80                 /*  vr4 - vr7: Q + Qxy */
81                 asm volatile("vld $vr8, %0" : : "m" (dq[0]));
82                 asm volatile("vld $vr9, %0" : : "m" (dq[16]));
83                 asm volatile("vld $vr10, %0" : : "m" (dq[32]));
84                 asm volatile("vld $vr11, %0" : : "m" (dq[48]));
85                 asm volatile("vxor.v $vr4, $vr4, $vr8");
86                 asm volatile("vxor.v $vr5, $vr5, $vr9");
87                 asm volatile("vxor.v $vr6, $vr6, $vr10");
88                 asm volatile("vxor.v $vr7, $vr7, $vr11");
89                 /* vr0 - vr3: P */
90                 asm volatile("vld $vr0, %0" : : "m" (p[0]));
91                 asm volatile("vld $vr1, %0" : : "m" (p[16]));
92                 asm volatile("vld $vr2, %0" : : "m" (p[32]));
93                 asm volatile("vld $vr3, %0" : : "m" (p[48]));
94                 /* vr0 - vr3: P + Pxy */
95                 asm volatile("vld $vr8, %0" : : "m" (dp[0]));
96                 asm volatile("vld $vr9, %0" : : "m" (dp[16]));
97                 asm volatile("vld $vr10, %0" : : "m" (dp[32]));
98                 asm volatile("vld $vr11, %0" : : "m" (dp[48]));
99                 asm volatile("vxor.v $vr0, $vr0, $vr8");
100                 asm volatile("vxor.v $vr1, $vr1, $vr9");
101                 asm volatile("vxor.v $vr2, $vr2, $vr10");
102                 asm volatile("vxor.v $vr3, $vr3, $vr11");
103
104                 /* vr8 - vr11: higher 4 bits of each byte of (Q + Qxy) */
105                 asm volatile("vsrli.b $vr8, $vr4, 4");
106                 asm volatile("vsrli.b $vr9, $vr5, 4");
107                 asm volatile("vsrli.b $vr10, $vr6, 4");
108                 asm volatile("vsrli.b $vr11, $vr7, 4");
109                 /* vr4 - vr7: lower 4 bits of each byte of (Q + Qxy) */
110                 asm volatile("vandi.b $vr4, $vr4, 0x0f");
111                 asm volatile("vandi.b $vr5, $vr5, 0x0f");
112                 asm volatile("vandi.b $vr6, $vr6, 0x0f");
113                 asm volatile("vandi.b $vr7, $vr7, 0x0f");
114                 /* lookup from qmul[0] */
115                 asm volatile("vshuf.b $vr4, $vr20, $vr20, $vr4");
116                 asm volatile("vshuf.b $vr5, $vr20, $vr20, $vr5");
117                 asm volatile("vshuf.b $vr6, $vr20, $vr20, $vr6");
118                 asm volatile("vshuf.b $vr7, $vr20, $vr20, $vr7");
119                 /* lookup from qmul[16] */
120                 asm volatile("vshuf.b $vr8, $vr21, $vr21, $vr8");
121                 asm volatile("vshuf.b $vr9, $vr21, $vr21, $vr9");
122                 asm volatile("vshuf.b $vr10, $vr21, $vr21, $vr10");
123                 asm volatile("vshuf.b $vr11, $vr21, $vr21, $vr11");
124                 /* vr16 - vr19: B(Q + Qxy) */
125                 asm volatile("vxor.v $vr16, $vr8, $vr4");
126                 asm volatile("vxor.v $vr17, $vr9, $vr5");
127                 asm volatile("vxor.v $vr18, $vr10, $vr6");
128                 asm volatile("vxor.v $vr19, $vr11, $vr7");
129
130                 /* vr4 - vr7: higher 4 bits of each byte of (P + Pxy) */
131                 asm volatile("vsrli.b $vr4, $vr0, 4");
132                 asm volatile("vsrli.b $vr5, $vr1, 4");
133                 asm volatile("vsrli.b $vr6, $vr2, 4");
134                 asm volatile("vsrli.b $vr7, $vr3, 4");
135                 /* vr12 - vr15: lower 4 bits of each byte of (P + Pxy) */
136                 asm volatile("vandi.b $vr12, $vr0, 0x0f");
137                 asm volatile("vandi.b $vr13, $vr1, 0x0f");
138                 asm volatile("vandi.b $vr14, $vr2, 0x0f");
139                 asm volatile("vandi.b $vr15, $vr3, 0x0f");
140                 /* lookup from pbmul[0] */
141                 asm volatile("vshuf.b $vr12, $vr22, $vr22, $vr12");
142                 asm volatile("vshuf.b $vr13, $vr22, $vr22, $vr13");
143                 asm volatile("vshuf.b $vr14, $vr22, $vr22, $vr14");
144                 asm volatile("vshuf.b $vr15, $vr22, $vr22, $vr15");
145                 /* lookup from pbmul[16] */
146                 asm volatile("vshuf.b $vr4, $vr23, $vr23, $vr4");
147                 asm volatile("vshuf.b $vr5, $vr23, $vr23, $vr5");
148                 asm volatile("vshuf.b $vr6, $vr23, $vr23, $vr6");
149                 asm volatile("vshuf.b $vr7, $vr23, $vr23, $vr7");
150                 /* vr4 - vr7: A(P + Pxy) */
151                 asm volatile("vxor.v $vr4, $vr4, $vr12");
152                 asm volatile("vxor.v $vr5, $vr5, $vr13");
153                 asm volatile("vxor.v $vr6, $vr6, $vr14");
154                 asm volatile("vxor.v $vr7, $vr7, $vr15");
155
156                 /* vr4 - vr7: A(P + Pxy) + B(Q + Qxy) = Dx */
157                 asm volatile("vxor.v $vr4, $vr4, $vr16");
158                 asm volatile("vxor.v $vr5, $vr5, $vr17");
159                 asm volatile("vxor.v $vr6, $vr6, $vr18");
160                 asm volatile("vxor.v $vr7, $vr7, $vr19");
161                 asm volatile("vst $vr4, %0" : "=m" (dq[0]));
162                 asm volatile("vst $vr5, %0" : "=m" (dq[16]));
163                 asm volatile("vst $vr6, %0" : "=m" (dq[32]));
164                 asm volatile("vst $vr7, %0" : "=m" (dq[48]));
165
166                 /* vr0 - vr3: P + Pxy + Dx = Dy */
167                 asm volatile("vxor.v $vr0, $vr0, $vr4");
168                 asm volatile("vxor.v $vr1, $vr1, $vr5");
169                 asm volatile("vxor.v $vr2, $vr2, $vr6");
170                 asm volatile("vxor.v $vr3, $vr3, $vr7");
171                 asm volatile("vst $vr0, %0" : "=m" (dp[0]));
172                 asm volatile("vst $vr1, %0" : "=m" (dp[16]));
173                 asm volatile("vst $vr2, %0" : "=m" (dp[32]));
174                 asm volatile("vst $vr3, %0" : "=m" (dp[48]));
175
176                 bytes -= 64;
177                 p += 64;
178                 q += 64;
179                 dp += 64;
180                 dq += 64;
181         }
182
183         kernel_fpu_end();
184 }
185
186 static void raid6_datap_recov_lsx(int disks, size_t bytes, int faila,
187                                   void **ptrs)
188 {
189         u8 *p, *q, *dq;
190         const u8 *qmul;         /* Q multiplier table */
191
192         p = (u8 *)ptrs[disks - 2];
193         q = (u8 *)ptrs[disks - 1];
194
195         /*
196          * Compute syndrome with zero for the missing data page
197          * Use the dead data page as temporary storage for delta q
198          */
199         dq = (u8 *)ptrs[faila];
200         ptrs[faila] = (void *)raid6_empty_zero_page;
201         ptrs[disks - 1] = dq;
202
203         raid6_call.gen_syndrome(disks, bytes, ptrs);
204
205         /* Restore pointer table */
206         ptrs[faila] = dq;
207         ptrs[disks - 1] = q;
208
209         /* Now, pick the proper data tables */
210         qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]];
211
212         kernel_fpu_begin();
213
214         /* vr22, vr23: qmul */
215         asm volatile("vld $vr22, %0" : : "m" (qmul[0]));
216         asm volatile("vld $vr23, %0" : : "m" (qmul[16]));
217
218         while (bytes) {
219                 /* vr0 - vr3: P + Dx */
220                 asm volatile("vld $vr0, %0" : : "m" (p[0]));
221                 asm volatile("vld $vr1, %0" : : "m" (p[16]));
222                 asm volatile("vld $vr2, %0" : : "m" (p[32]));
223                 asm volatile("vld $vr3, %0" : : "m" (p[48]));
224                 /* vr4 - vr7: Qx */
225                 asm volatile("vld $vr4, %0" : : "m" (dq[0]));
226                 asm volatile("vld $vr5, %0" : : "m" (dq[16]));
227                 asm volatile("vld $vr6, %0" : : "m" (dq[32]));
228                 asm volatile("vld $vr7, %0" : : "m" (dq[48]));
229                 /* vr4 - vr7: Q + Qx */
230                 asm volatile("vld $vr8, %0" : : "m" (q[0]));
231                 asm volatile("vld $vr9, %0" : : "m" (q[16]));
232                 asm volatile("vld $vr10, %0" : : "m" (q[32]));
233                 asm volatile("vld $vr11, %0" : : "m" (q[48]));
234                 asm volatile("vxor.v $vr4, $vr4, $vr8");
235                 asm volatile("vxor.v $vr5, $vr5, $vr9");
236                 asm volatile("vxor.v $vr6, $vr6, $vr10");
237                 asm volatile("vxor.v $vr7, $vr7, $vr11");
238
239                 /* vr8 - vr11: higher 4 bits of each byte of (Q + Qx) */
240                 asm volatile("vsrli.b $vr8, $vr4, 4");
241                 asm volatile("vsrli.b $vr9, $vr5, 4");
242                 asm volatile("vsrli.b $vr10, $vr6, 4");
243                 asm volatile("vsrli.b $vr11, $vr7, 4");
244                 /* vr4 - vr7: lower 4 bits of each byte of (Q + Qx) */
245                 asm volatile("vandi.b $vr4, $vr4, 0x0f");
246                 asm volatile("vandi.b $vr5, $vr5, 0x0f");
247                 asm volatile("vandi.b $vr6, $vr6, 0x0f");
248                 asm volatile("vandi.b $vr7, $vr7, 0x0f");
249                 /* lookup from qmul[0] */
250                 asm volatile("vshuf.b $vr4, $vr22, $vr22, $vr4");
251                 asm volatile("vshuf.b $vr5, $vr22, $vr22, $vr5");
252                 asm volatile("vshuf.b $vr6, $vr22, $vr22, $vr6");
253                 asm volatile("vshuf.b $vr7, $vr22, $vr22, $vr7");
254                 /* lookup from qmul[16] */
255                 asm volatile("vshuf.b $vr8, $vr23, $vr23, $vr8");
256                 asm volatile("vshuf.b $vr9, $vr23, $vr23, $vr9");
257                 asm volatile("vshuf.b $vr10, $vr23, $vr23, $vr10");
258                 asm volatile("vshuf.b $vr11, $vr23, $vr23, $vr11");
259                 /* vr4 - vr7: qmul(Q + Qx) = Dx */
260                 asm volatile("vxor.v $vr4, $vr4, $vr8");
261                 asm volatile("vxor.v $vr5, $vr5, $vr9");
262                 asm volatile("vxor.v $vr6, $vr6, $vr10");
263                 asm volatile("vxor.v $vr7, $vr7, $vr11");
264                 asm volatile("vst $vr4, %0" : "=m" (dq[0]));
265                 asm volatile("vst $vr5, %0" : "=m" (dq[16]));
266                 asm volatile("vst $vr6, %0" : "=m" (dq[32]));
267                 asm volatile("vst $vr7, %0" : "=m" (dq[48]));
268
269                 /* vr0 - vr3: P + Dx + Dx = P */
270                 asm volatile("vxor.v $vr0, $vr0, $vr4");
271                 asm volatile("vxor.v $vr1, $vr1, $vr5");
272                 asm volatile("vxor.v $vr2, $vr2, $vr6");
273                 asm volatile("vxor.v $vr3, $vr3, $vr7");
274                 asm volatile("vst $vr0, %0" : "=m" (p[0]));
275                 asm volatile("vst $vr1, %0" : "=m" (p[16]));
276                 asm volatile("vst $vr2, %0" : "=m" (p[32]));
277                 asm volatile("vst $vr3, %0" : "=m" (p[48]));
278
279                 bytes -= 64;
280                 p += 64;
281                 q += 64;
282                 dq += 64;
283         }
284
285         kernel_fpu_end();
286 }
287
288 const struct raid6_recov_calls raid6_recov_lsx = {
289         .data2 = raid6_2data_recov_lsx,
290         .datap = raid6_datap_recov_lsx,
291         .valid = raid6_has_lsx,
292         .name = "lsx",
293         .priority = 1,
294 };
295 #endif /* CONFIG_CPU_HAS_LSX */
296
297 #ifdef CONFIG_CPU_HAS_LASX
298 static int raid6_has_lasx(void)
299 {
300         return cpu_has_lasx;
301 }
302
303 static void raid6_2data_recov_lasx(int disks, size_t bytes, int faila,
304                                    int failb, void **ptrs)
305 {
306         u8 *p, *q, *dp, *dq;
307         const u8 *pbmul;        /* P multiplier table for B data */
308         const u8 *qmul;         /* Q multiplier table (for both) */
309
310         p = (u8 *)ptrs[disks - 2];
311         q = (u8 *)ptrs[disks - 1];
312
313         /*
314          * Compute syndrome with zero for the missing data pages
315          * Use the dead data pages as temporary storage for
316          * delta p and delta q
317          */
318         dp = (u8 *)ptrs[faila];
319         ptrs[faila] = (void *)raid6_empty_zero_page;
320         ptrs[disks - 2] = dp;
321         dq = (u8 *)ptrs[failb];
322         ptrs[failb] = (void *)raid6_empty_zero_page;
323         ptrs[disks - 1] = dq;
324
325         raid6_call.gen_syndrome(disks, bytes, ptrs);
326
327         /* Restore pointer table */
328         ptrs[faila] = dp;
329         ptrs[failb] = dq;
330         ptrs[disks - 2] = p;
331         ptrs[disks - 1] = q;
332
333         /* Now, pick the proper data tables */
334         pbmul = raid6_vgfmul[raid6_gfexi[failb - faila]];
335         qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^ raid6_gfexp[failb]]];
336
337         kernel_fpu_begin();
338
339         /*
340          * xr20, xr21: qmul
341          * xr22, xr23: pbmul
342          */
343         asm volatile("vld $vr20, %0" : : "m" (qmul[0]));
344         asm volatile("vld $vr21, %0" : : "m" (qmul[16]));
345         asm volatile("vld $vr22, %0" : : "m" (pbmul[0]));
346         asm volatile("vld $vr23, %0" : : "m" (pbmul[16]));
347         asm volatile("xvreplve0.q $xr20, $xr20");
348         asm volatile("xvreplve0.q $xr21, $xr21");
349         asm volatile("xvreplve0.q $xr22, $xr22");
350         asm volatile("xvreplve0.q $xr23, $xr23");
351
352         while (bytes) {
353                 /* xr0, xr1: Q */
354                 asm volatile("xvld $xr0, %0" : : "m" (q[0]));
355                 asm volatile("xvld $xr1, %0" : : "m" (q[32]));
356                 /* xr0, xr1: Q + Qxy */
357                 asm volatile("xvld $xr4, %0" : : "m" (dq[0]));
358                 asm volatile("xvld $xr5, %0" : : "m" (dq[32]));
359                 asm volatile("xvxor.v $xr0, $xr0, $xr4");
360                 asm volatile("xvxor.v $xr1, $xr1, $xr5");
361                 /* xr2, xr3: P */
362                 asm volatile("xvld $xr2, %0" : : "m" (p[0]));
363                 asm volatile("xvld $xr3, %0" : : "m" (p[32]));
364                 /* xr2, xr3: P + Pxy */
365                 asm volatile("xvld $xr4, %0" : : "m" (dp[0]));
366                 asm volatile("xvld $xr5, %0" : : "m" (dp[32]));
367                 asm volatile("xvxor.v $xr2, $xr2, $xr4");
368                 asm volatile("xvxor.v $xr3, $xr3, $xr5");
369
370                 /* xr4, xr5: higher 4 bits of each byte of (Q + Qxy) */
371                 asm volatile("xvsrli.b $xr4, $xr0, 4");
372                 asm volatile("xvsrli.b $xr5, $xr1, 4");
373                 /* xr0, xr1: lower 4 bits of each byte of (Q + Qxy) */
374                 asm volatile("xvandi.b $xr0, $xr0, 0x0f");
375                 asm volatile("xvandi.b $xr1, $xr1, 0x0f");
376                 /* lookup from qmul[0] */
377                 asm volatile("xvshuf.b $xr0, $xr20, $xr20, $xr0");
378                 asm volatile("xvshuf.b $xr1, $xr20, $xr20, $xr1");
379                 /* lookup from qmul[16] */
380                 asm volatile("xvshuf.b $xr4, $xr21, $xr21, $xr4");
381                 asm volatile("xvshuf.b $xr5, $xr21, $xr21, $xr5");
382                 /* xr6, xr7: B(Q + Qxy) */
383                 asm volatile("xvxor.v $xr6, $xr4, $xr0");
384                 asm volatile("xvxor.v $xr7, $xr5, $xr1");
385
386                 /* xr4, xr5: higher 4 bits of each byte of (P + Pxy) */
387                 asm volatile("xvsrli.b $xr4, $xr2, 4");
388                 asm volatile("xvsrli.b $xr5, $xr3, 4");
389                 /* xr0, xr1: lower 4 bits of each byte of (P + Pxy) */
390                 asm volatile("xvandi.b $xr0, $xr2, 0x0f");
391                 asm volatile("xvandi.b $xr1, $xr3, 0x0f");
392                 /* lookup from pbmul[0] */
393                 asm volatile("xvshuf.b $xr0, $xr22, $xr22, $xr0");
394                 asm volatile("xvshuf.b $xr1, $xr22, $xr22, $xr1");
395                 /* lookup from pbmul[16] */
396                 asm volatile("xvshuf.b $xr4, $xr23, $xr23, $xr4");
397                 asm volatile("xvshuf.b $xr5, $xr23, $xr23, $xr5");
398                 /* xr0, xr1: A(P + Pxy) */
399                 asm volatile("xvxor.v $xr0, $xr0, $xr4");
400                 asm volatile("xvxor.v $xr1, $xr1, $xr5");
401
402                 /* xr0, xr1: A(P + Pxy) + B(Q + Qxy) = Dx */
403                 asm volatile("xvxor.v $xr0, $xr0, $xr6");
404                 asm volatile("xvxor.v $xr1, $xr1, $xr7");
405
406                 /* xr2, xr3: P + Pxy + Dx = Dy */
407                 asm volatile("xvxor.v $xr2, $xr2, $xr0");
408                 asm volatile("xvxor.v $xr3, $xr3, $xr1");
409
410                 asm volatile("xvst $xr0, %0" : "=m" (dq[0]));
411                 asm volatile("xvst $xr1, %0" : "=m" (dq[32]));
412                 asm volatile("xvst $xr2, %0" : "=m" (dp[0]));
413                 asm volatile("xvst $xr3, %0" : "=m" (dp[32]));
414
415                 bytes -= 64;
416                 p += 64;
417                 q += 64;
418                 dp += 64;
419                 dq += 64;
420         }
421
422         kernel_fpu_end();
423 }
424
425 static void raid6_datap_recov_lasx(int disks, size_t bytes, int faila,
426                                    void **ptrs)
427 {
428         u8 *p, *q, *dq;
429         const u8 *qmul;         /* Q multiplier table */
430
431         p = (u8 *)ptrs[disks - 2];
432         q = (u8 *)ptrs[disks - 1];
433
434         /*
435          * Compute syndrome with zero for the missing data page
436          * Use the dead data page as temporary storage for delta q
437          */
438         dq = (u8 *)ptrs[faila];
439         ptrs[faila] = (void *)raid6_empty_zero_page;
440         ptrs[disks - 1] = dq;
441
442         raid6_call.gen_syndrome(disks, bytes, ptrs);
443
444         /* Restore pointer table */
445         ptrs[faila] = dq;
446         ptrs[disks - 1] = q;
447
448         /* Now, pick the proper data tables */
449         qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]];
450
451         kernel_fpu_begin();
452
453         /* xr22, xr23: qmul */
454         asm volatile("vld $vr22, %0" : : "m" (qmul[0]));
455         asm volatile("xvreplve0.q $xr22, $xr22");
456         asm volatile("vld $vr23, %0" : : "m" (qmul[16]));
457         asm volatile("xvreplve0.q $xr23, $xr23");
458
459         while (bytes) {
460                 /* xr0, xr1: P + Dx */
461                 asm volatile("xvld $xr0, %0" : : "m" (p[0]));
462                 asm volatile("xvld $xr1, %0" : : "m" (p[32]));
463                 /* xr2, xr3: Qx */
464                 asm volatile("xvld $xr2, %0" : : "m" (dq[0]));
465                 asm volatile("xvld $xr3, %0" : : "m" (dq[32]));
466                 /* xr2, xr3: Q + Qx */
467                 asm volatile("xvld $xr4, %0" : : "m" (q[0]));
468                 asm volatile("xvld $xr5, %0" : : "m" (q[32]));
469                 asm volatile("xvxor.v $xr2, $xr2, $xr4");
470                 asm volatile("xvxor.v $xr3, $xr3, $xr5");
471
472                 /* xr4, xr5: higher 4 bits of each byte of (Q + Qx) */
473                 asm volatile("xvsrli.b $xr4, $xr2, 4");
474                 asm volatile("xvsrli.b $xr5, $xr3, 4");
475                 /* xr2, xr3: lower 4 bits of each byte of (Q + Qx) */
476                 asm volatile("xvandi.b $xr2, $xr2, 0x0f");
477                 asm volatile("xvandi.b $xr3, $xr3, 0x0f");
478                 /* lookup from qmul[0] */
479                 asm volatile("xvshuf.b $xr2, $xr22, $xr22, $xr2");
480                 asm volatile("xvshuf.b $xr3, $xr22, $xr22, $xr3");
481                 /* lookup from qmul[16] */
482                 asm volatile("xvshuf.b $xr4, $xr23, $xr23, $xr4");
483                 asm volatile("xvshuf.b $xr5, $xr23, $xr23, $xr5");
484                 /* xr2, xr3: qmul(Q + Qx) = Dx */
485                 asm volatile("xvxor.v $xr2, $xr2, $xr4");
486                 asm volatile("xvxor.v $xr3, $xr3, $xr5");
487
488                 /* xr0, xr1: P + Dx + Dx = P */
489                 asm volatile("xvxor.v $xr0, $xr0, $xr2");
490                 asm volatile("xvxor.v $xr1, $xr1, $xr3");
491
492                 asm volatile("xvst $xr2, %0" : "=m" (dq[0]));
493                 asm volatile("xvst $xr3, %0" : "=m" (dq[32]));
494                 asm volatile("xvst $xr0, %0" : "=m" (p[0]));
495                 asm volatile("xvst $xr1, %0" : "=m" (p[32]));
496
497                 bytes -= 64;
498                 p += 64;
499                 q += 64;
500                 dq += 64;
501         }
502
503         kernel_fpu_end();
504 }
505
506 const struct raid6_recov_calls raid6_recov_lasx = {
507         .data2 = raid6_2data_recov_lasx,
508         .datap = raid6_datap_recov_lasx,
509         .valid = raid6_has_lasx,
510         .name = "lasx",
511         .priority = 2,
512 };
513 #endif /* CONFIG_CPU_HAS_LASX */