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