xref: /spdk/lib/util/xor.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2022 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/xor.h"
7 #include "spdk/config.h"
8 #include "spdk/assert.h"
9 #include "spdk/util.h"
10 
11 /* maximum number of source buffers */
12 #define SPDK_XOR_MAX_SRC	256
13 
14 static inline bool
15 is_aligned(void *ptr, size_t alignment)
16 {
17 	uintptr_t p = (uintptr_t)ptr;
18 
19 	return p == SPDK_ALIGN_FLOOR(p, alignment);
20 }
21 
22 static bool
23 buffers_aligned(void *dest, void **sources, uint32_t n, size_t alignment)
24 {
25 	uint32_t i;
26 
27 	for (i = 0; i < n; i++) {
28 		if (!is_aligned(sources[i], alignment)) {
29 			return false;
30 		}
31 	}
32 
33 	return is_aligned(dest, alignment);
34 }
35 
36 static void
37 xor_gen_unaligned(void *dest, void **sources, uint32_t n, uint32_t len)
38 {
39 	uint32_t i, j;
40 
41 	for (i = 0; i < len; i++) {
42 		uint8_t b = 0;
43 
44 		for (j = 0; j < n; j++) {
45 			b ^= ((uint8_t *)sources[j])[i];
46 		}
47 		((uint8_t *)dest)[i] = b;
48 	}
49 }
50 
51 static void
52 xor_gen_basic(void *dest, void **sources, uint32_t n, uint32_t len)
53 {
54 	uint32_t shift;
55 	uint32_t len_div, len_rem;
56 	uint32_t i, j;
57 
58 	if (!buffers_aligned(dest, sources, n, sizeof(uint64_t))) {
59 		xor_gen_unaligned(dest, sources, n, len);
60 		return;
61 	}
62 
63 	shift = spdk_u32log2(sizeof(uint64_t));
64 	len_div = len >> shift;
65 	len_rem = len_div << shift;
66 
67 	for (i = 0; i < len_div; i++) {
68 		uint64_t w = 0;
69 
70 		for (j = 0; j < n; j++) {
71 			w ^= ((uint64_t *)sources[j])[i];
72 		}
73 		((uint64_t *)dest)[i] = w;
74 	}
75 
76 	if (len_rem < len) {
77 		void *sources2[SPDK_XOR_MAX_SRC];
78 
79 		for (j = 0; j < n; j++) {
80 			sources2[j] = (uint8_t *)sources[j] + len_rem;
81 		}
82 
83 		xor_gen_unaligned((uint8_t *)dest + len_rem, sources2, n, len - len_rem);
84 	}
85 }
86 
87 #ifdef SPDK_CONFIG_ISAL
88 #include "isa-l/include/raid.h"
89 
90 #define SPDK_XOR_BUF_ALIGN 32
91 
92 static int
93 do_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
94 {
95 	if (buffers_aligned(dest, sources, n, SPDK_XOR_BUF_ALIGN)) {
96 		void *buffers[SPDK_XOR_MAX_SRC + 1];
97 
98 		if (n >= INT_MAX) {
99 			return -EINVAL;
100 		}
101 
102 		memcpy(buffers, sources, n * sizeof(buffers[0]));
103 		buffers[n] = dest;
104 
105 		if (xor_gen(n + 1, len, buffers)) {
106 			return -EINVAL;
107 		}
108 	} else {
109 		xor_gen_basic(dest, sources, n, len);
110 	}
111 
112 	return 0;
113 }
114 
115 #else
116 
117 #define SPDK_XOR_BUF_ALIGN sizeof(uint64_t)
118 
119 static inline int
120 do_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
121 {
122 	xor_gen_basic(dest, sources, n, len);
123 	return 0;
124 }
125 
126 #endif
127 
128 int
129 spdk_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
130 {
131 	if (n < 2 || n > SPDK_XOR_MAX_SRC) {
132 		return -EINVAL;
133 	}
134 
135 	return do_xor_gen(dest, sources, n, len);
136 }
137 
138 size_t
139 spdk_xor_get_optimal_alignment(void)
140 {
141 	return SPDK_XOR_BUF_ALIGN;
142 }
143 
144 SPDK_STATIC_ASSERT(SPDK_XOR_BUF_ALIGN > 0 && !(SPDK_XOR_BUF_ALIGN & (SPDK_XOR_BUF_ALIGN - 1)),
145 		   "Must be power of 2");
146