18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012 Intel Corporation
48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/raid/pq.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifdef __KERNEL__
108c2ecf20Sopenharmony_ci#include <asm/neon.h>
118c2ecf20Sopenharmony_ci#else
128c2ecf20Sopenharmony_ci#define kernel_neon_begin()
138c2ecf20Sopenharmony_ci#define kernel_neon_end()
148c2ecf20Sopenharmony_ci#define cpu_has_neon()		(1)
158c2ecf20Sopenharmony_ci#endif
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic int raid6_has_neon(void)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	return cpu_has_neon();
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_civoid __raid6_2data_recov_neon(int bytes, uint8_t *p, uint8_t *q, uint8_t *dp,
238c2ecf20Sopenharmony_ci			      uint8_t *dq, const uint8_t *pbmul,
248c2ecf20Sopenharmony_ci			      const uint8_t *qmul);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid __raid6_datap_recov_neon(int bytes, uint8_t *p, uint8_t *q, uint8_t *dq,
278c2ecf20Sopenharmony_ci			      const uint8_t *qmul);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void raid6_2data_recov_neon(int disks, size_t bytes, int faila,
308c2ecf20Sopenharmony_ci		int failb, void **ptrs)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	u8 *p, *q, *dp, *dq;
338c2ecf20Sopenharmony_ci	const u8 *pbmul;	/* P multiplier table for B data */
348c2ecf20Sopenharmony_ci	const u8 *qmul;		/* Q multiplier table (for both) */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	p = (u8 *)ptrs[disks - 2];
378c2ecf20Sopenharmony_ci	q = (u8 *)ptrs[disks - 1];
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	/*
408c2ecf20Sopenharmony_ci	 * Compute syndrome with zero for the missing data pages
418c2ecf20Sopenharmony_ci	 * Use the dead data pages as temporary storage for
428c2ecf20Sopenharmony_ci	 * delta p and delta q
438c2ecf20Sopenharmony_ci	 */
448c2ecf20Sopenharmony_ci	dp = (u8 *)ptrs[faila];
458c2ecf20Sopenharmony_ci	ptrs[faila] = (void *)raid6_empty_zero_page;
468c2ecf20Sopenharmony_ci	ptrs[disks - 2] = dp;
478c2ecf20Sopenharmony_ci	dq = (u8 *)ptrs[failb];
488c2ecf20Sopenharmony_ci	ptrs[failb] = (void *)raid6_empty_zero_page;
498c2ecf20Sopenharmony_ci	ptrs[disks - 1] = dq;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	raid6_call.gen_syndrome(disks, bytes, ptrs);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	/* Restore pointer table */
548c2ecf20Sopenharmony_ci	ptrs[faila]     = dp;
558c2ecf20Sopenharmony_ci	ptrs[failb]     = dq;
568c2ecf20Sopenharmony_ci	ptrs[disks - 2] = p;
578c2ecf20Sopenharmony_ci	ptrs[disks - 1] = q;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* Now, pick the proper data tables */
608c2ecf20Sopenharmony_ci	pbmul = raid6_vgfmul[raid6_gfexi[failb-faila]];
618c2ecf20Sopenharmony_ci	qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^
628c2ecf20Sopenharmony_ci					 raid6_gfexp[failb]]];
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	kernel_neon_begin();
658c2ecf20Sopenharmony_ci	__raid6_2data_recov_neon(bytes, p, q, dp, dq, pbmul, qmul);
668c2ecf20Sopenharmony_ci	kernel_neon_end();
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void raid6_datap_recov_neon(int disks, size_t bytes, int faila,
708c2ecf20Sopenharmony_ci		void **ptrs)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	u8 *p, *q, *dq;
738c2ecf20Sopenharmony_ci	const u8 *qmul;		/* Q multiplier table */
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	p = (u8 *)ptrs[disks - 2];
768c2ecf20Sopenharmony_ci	q = (u8 *)ptrs[disks - 1];
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/*
798c2ecf20Sopenharmony_ci	 * Compute syndrome with zero for the missing data page
808c2ecf20Sopenharmony_ci	 * Use the dead data page as temporary storage for delta q
818c2ecf20Sopenharmony_ci	 */
828c2ecf20Sopenharmony_ci	dq = (u8 *)ptrs[faila];
838c2ecf20Sopenharmony_ci	ptrs[faila] = (void *)raid6_empty_zero_page;
848c2ecf20Sopenharmony_ci	ptrs[disks - 1] = dq;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	raid6_call.gen_syndrome(disks, bytes, ptrs);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	/* Restore pointer table */
898c2ecf20Sopenharmony_ci	ptrs[faila]     = dq;
908c2ecf20Sopenharmony_ci	ptrs[disks - 1] = q;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* Now, pick the proper data tables */
938c2ecf20Sopenharmony_ci	qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]];
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	kernel_neon_begin();
968c2ecf20Sopenharmony_ci	__raid6_datap_recov_neon(bytes, p, q, dq, qmul);
978c2ecf20Sopenharmony_ci	kernel_neon_end();
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ciconst struct raid6_recov_calls raid6_recov_neon = {
1018c2ecf20Sopenharmony_ci	.data2		= raid6_2data_recov_neon,
1028c2ecf20Sopenharmony_ci	.datap		= raid6_datap_recov_neon,
1038c2ecf20Sopenharmony_ci	.valid		= raid6_has_neon,
1048c2ecf20Sopenharmony_ci	.name		= "neon",
1058c2ecf20Sopenharmony_ci	.priority	= 10,
1068c2ecf20Sopenharmony_ci};
107