xref: /spdk/lib/util/xor.c (revision 075d422f3480d3db11013734f833304606867da4)
169c448a3SArtur Paszkiewicz /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
369c448a3SArtur Paszkiewicz  *   All rights reserved.
469c448a3SArtur Paszkiewicz  */
569c448a3SArtur Paszkiewicz 
669c448a3SArtur Paszkiewicz #include "spdk/xor.h"
769c448a3SArtur Paszkiewicz #include "spdk/config.h"
869c448a3SArtur Paszkiewicz #include "spdk/assert.h"
969c448a3SArtur Paszkiewicz #include "spdk/util.h"
1069c448a3SArtur Paszkiewicz 
1169c448a3SArtur Paszkiewicz /* maximum number of source buffers */
1269c448a3SArtur Paszkiewicz #define SPDK_XOR_MAX_SRC	256
1369c448a3SArtur Paszkiewicz 
1469c448a3SArtur Paszkiewicz static inline bool
is_aligned(void * ptr,size_t alignment)1569c448a3SArtur Paszkiewicz is_aligned(void *ptr, size_t alignment)
1669c448a3SArtur Paszkiewicz {
1769c448a3SArtur Paszkiewicz 	uintptr_t p = (uintptr_t)ptr;
1869c448a3SArtur Paszkiewicz 
1969c448a3SArtur Paszkiewicz 	return p == SPDK_ALIGN_FLOOR(p, alignment);
2069c448a3SArtur Paszkiewicz }
2169c448a3SArtur Paszkiewicz 
2269c448a3SArtur Paszkiewicz static bool
buffers_aligned(void * dest,void ** sources,uint32_t n,size_t alignment)2369c448a3SArtur Paszkiewicz buffers_aligned(void *dest, void **sources, uint32_t n, size_t alignment)
2469c448a3SArtur Paszkiewicz {
2569c448a3SArtur Paszkiewicz 	uint32_t i;
2669c448a3SArtur Paszkiewicz 
2769c448a3SArtur Paszkiewicz 	for (i = 0; i < n; i++) {
2869c448a3SArtur Paszkiewicz 		if (!is_aligned(sources[i], alignment)) {
2969c448a3SArtur Paszkiewicz 			return false;
3069c448a3SArtur Paszkiewicz 		}
3169c448a3SArtur Paszkiewicz 	}
3269c448a3SArtur Paszkiewicz 
3369c448a3SArtur Paszkiewicz 	return is_aligned(dest, alignment);
3469c448a3SArtur Paszkiewicz }
3569c448a3SArtur Paszkiewicz 
3669c448a3SArtur Paszkiewicz static void
xor_gen_unaligned(void * dest,void ** sources,uint32_t n,uint32_t len)3769c448a3SArtur Paszkiewicz xor_gen_unaligned(void *dest, void **sources, uint32_t n, uint32_t len)
3869c448a3SArtur Paszkiewicz {
3969c448a3SArtur Paszkiewicz 	uint32_t i, j;
4069c448a3SArtur Paszkiewicz 
4169c448a3SArtur Paszkiewicz 	for (i = 0; i < len; i++) {
4269c448a3SArtur Paszkiewicz 		uint8_t b = 0;
4369c448a3SArtur Paszkiewicz 
4469c448a3SArtur Paszkiewicz 		for (j = 0; j < n; j++) {
4569c448a3SArtur Paszkiewicz 			b ^= ((uint8_t *)sources[j])[i];
4669c448a3SArtur Paszkiewicz 		}
4769c448a3SArtur Paszkiewicz 		((uint8_t *)dest)[i] = b;
4869c448a3SArtur Paszkiewicz 	}
4969c448a3SArtur Paszkiewicz }
5069c448a3SArtur Paszkiewicz 
5169c448a3SArtur Paszkiewicz static void
xor_gen_basic(void * dest,void ** sources,uint32_t n,uint32_t len)5269c448a3SArtur Paszkiewicz xor_gen_basic(void *dest, void **sources, uint32_t n, uint32_t len)
5369c448a3SArtur Paszkiewicz {
5469c448a3SArtur Paszkiewicz 	uint32_t shift;
5569c448a3SArtur Paszkiewicz 	uint32_t len_div, len_rem;
5669c448a3SArtur Paszkiewicz 	uint32_t i, j;
5769c448a3SArtur Paszkiewicz 
5869c448a3SArtur Paszkiewicz 	if (!buffers_aligned(dest, sources, n, sizeof(uint64_t))) {
5969c448a3SArtur Paszkiewicz 		xor_gen_unaligned(dest, sources, n, len);
6069c448a3SArtur Paszkiewicz 		return;
6169c448a3SArtur Paszkiewicz 	}
6269c448a3SArtur Paszkiewicz 
6369c448a3SArtur Paszkiewicz 	shift = spdk_u32log2(sizeof(uint64_t));
6469c448a3SArtur Paszkiewicz 	len_div = len >> shift;
6569c448a3SArtur Paszkiewicz 	len_rem = len_div << shift;
6669c448a3SArtur Paszkiewicz 
6769c448a3SArtur Paszkiewicz 	for (i = 0; i < len_div; i++) {
6869c448a3SArtur Paszkiewicz 		uint64_t w = 0;
6969c448a3SArtur Paszkiewicz 
7069c448a3SArtur Paszkiewicz 		for (j = 0; j < n; j++) {
7169c448a3SArtur Paszkiewicz 			w ^= ((uint64_t *)sources[j])[i];
7269c448a3SArtur Paszkiewicz 		}
7369c448a3SArtur Paszkiewicz 		((uint64_t *)dest)[i] = w;
7469c448a3SArtur Paszkiewicz 	}
7569c448a3SArtur Paszkiewicz 
7669c448a3SArtur Paszkiewicz 	if (len_rem < len) {
7769c448a3SArtur Paszkiewicz 		void *sources2[SPDK_XOR_MAX_SRC];
7869c448a3SArtur Paszkiewicz 
7969c448a3SArtur Paszkiewicz 		for (j = 0; j < n; j++) {
80*075d422fSKonrad Sztyber 			sources2[j] = (uint8_t *)sources[j] + len_rem;
8169c448a3SArtur Paszkiewicz 		}
8269c448a3SArtur Paszkiewicz 
83*075d422fSKonrad Sztyber 		xor_gen_unaligned((uint8_t *)dest + len_rem, sources2, n, len - len_rem);
8469c448a3SArtur Paszkiewicz 	}
8569c448a3SArtur Paszkiewicz }
8669c448a3SArtur Paszkiewicz 
8769c448a3SArtur Paszkiewicz #ifdef SPDK_CONFIG_ISAL
8869c448a3SArtur Paszkiewicz #include "isa-l/include/raid.h"
8969c448a3SArtur Paszkiewicz 
9069c448a3SArtur Paszkiewicz #define SPDK_XOR_BUF_ALIGN 32
9169c448a3SArtur Paszkiewicz 
9269c448a3SArtur Paszkiewicz static int
do_xor_gen(void * dest,void ** sources,uint32_t n,uint32_t len)9369c448a3SArtur Paszkiewicz do_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
9469c448a3SArtur Paszkiewicz {
9569c448a3SArtur Paszkiewicz 	if (buffers_aligned(dest, sources, n, SPDK_XOR_BUF_ALIGN)) {
9669c448a3SArtur Paszkiewicz 		void *buffers[SPDK_XOR_MAX_SRC + 1];
9769c448a3SArtur Paszkiewicz 
9869c448a3SArtur Paszkiewicz 		if (n >= INT_MAX) {
9969c448a3SArtur Paszkiewicz 			return -EINVAL;
10069c448a3SArtur Paszkiewicz 		}
10169c448a3SArtur Paszkiewicz 
10269c448a3SArtur Paszkiewicz 		memcpy(buffers, sources, n * sizeof(buffers[0]));
10369c448a3SArtur Paszkiewicz 		buffers[n] = dest;
10469c448a3SArtur Paszkiewicz 
10569c448a3SArtur Paszkiewicz 		if (xor_gen(n + 1, len, buffers)) {
10669c448a3SArtur Paszkiewicz 			return -EINVAL;
10769c448a3SArtur Paszkiewicz 		}
10869c448a3SArtur Paszkiewicz 	} else {
10969c448a3SArtur Paszkiewicz 		xor_gen_basic(dest, sources, n, len);
11069c448a3SArtur Paszkiewicz 	}
11169c448a3SArtur Paszkiewicz 
11269c448a3SArtur Paszkiewicz 	return 0;
11369c448a3SArtur Paszkiewicz }
11469c448a3SArtur Paszkiewicz 
11569c448a3SArtur Paszkiewicz #else
11669c448a3SArtur Paszkiewicz 
11769c448a3SArtur Paszkiewicz #define SPDK_XOR_BUF_ALIGN sizeof(uint64_t)
11869c448a3SArtur Paszkiewicz 
11969c448a3SArtur Paszkiewicz static inline int
do_xor_gen(void * dest,void ** sources,uint32_t n,uint32_t len)12069c448a3SArtur Paszkiewicz do_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
12169c448a3SArtur Paszkiewicz {
12269c448a3SArtur Paszkiewicz 	xor_gen_basic(dest, sources, n, len);
12369c448a3SArtur Paszkiewicz 	return 0;
12469c448a3SArtur Paszkiewicz }
12569c448a3SArtur Paszkiewicz 
12669c448a3SArtur Paszkiewicz #endif
12769c448a3SArtur Paszkiewicz 
12869c448a3SArtur Paszkiewicz int
spdk_xor_gen(void * dest,void ** sources,uint32_t n,uint32_t len)12969c448a3SArtur Paszkiewicz spdk_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
13069c448a3SArtur Paszkiewicz {
13169c448a3SArtur Paszkiewicz 	if (n < 2 || n > SPDK_XOR_MAX_SRC) {
13269c448a3SArtur Paszkiewicz 		return -EINVAL;
13369c448a3SArtur Paszkiewicz 	}
13469c448a3SArtur Paszkiewicz 
13569c448a3SArtur Paszkiewicz 	return do_xor_gen(dest, sources, n, len);
13669c448a3SArtur Paszkiewicz }
13769c448a3SArtur Paszkiewicz 
13869c448a3SArtur Paszkiewicz size_t
spdk_xor_get_optimal_alignment(void)13969c448a3SArtur Paszkiewicz spdk_xor_get_optimal_alignment(void)
14069c448a3SArtur Paszkiewicz {
14169c448a3SArtur Paszkiewicz 	return SPDK_XOR_BUF_ALIGN;
14269c448a3SArtur Paszkiewicz }
14369c448a3SArtur Paszkiewicz 
14469c448a3SArtur Paszkiewicz SPDK_STATIC_ASSERT(SPDK_XOR_BUF_ALIGN > 0 && !(SPDK_XOR_BUF_ALIGN & (SPDK_XOR_BUF_ALIGN - 1)),
14569c448a3SArtur Paszkiewicz 		   "Must be power of 2");
146