Line data Source code
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 3 : is_aligned(void *ptr, size_t alignment)
16 : {
17 3 : uintptr_t p = (uintptr_t)ptr;
18 :
19 3 : return p == SPDK_ALIGN_FLOOR(p, alignment);
20 : }
21 :
22 : static bool
23 1 : buffers_aligned(void *dest, void **sources, uint32_t n, size_t alignment)
24 : {
25 : uint32_t i;
26 :
27 3 : for (i = 0; i < n; i++) {
28 2 : if (!is_aligned(sources[i], alignment)) {
29 0 : return false;
30 : }
31 : }
32 :
33 1 : return is_aligned(dest, alignment);
34 : }
35 :
36 : static void
37 0 : xor_gen_unaligned(void *dest, void **sources, uint32_t n, uint32_t len)
38 : {
39 : uint32_t i, j;
40 :
41 0 : for (i = 0; i < len; i++) {
42 0 : uint8_t b = 0;
43 :
44 0 : for (j = 0; j < n; j++) {
45 0 : b ^= ((uint8_t *)sources[j])[i];
46 : }
47 0 : ((uint8_t *)dest)[i] = b;
48 : }
49 0 : }
50 :
51 : static void
52 0 : 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 0 : if (!buffers_aligned(dest, sources, n, sizeof(uint64_t))) {
59 0 : xor_gen_unaligned(dest, sources, n, len);
60 0 : return;
61 : }
62 :
63 0 : shift = spdk_u32log2(sizeof(uint64_t));
64 0 : len_div = len >> shift;
65 0 : len_rem = len_div << shift;
66 :
67 0 : for (i = 0; i < len_div; i++) {
68 0 : uint64_t w = 0;
69 :
70 0 : for (j = 0; j < n; j++) {
71 0 : w ^= ((uint64_t *)sources[j])[i];
72 : }
73 0 : ((uint64_t *)dest)[i] = w;
74 : }
75 :
76 0 : if (len_rem < len) {
77 0 : void *sources2[SPDK_XOR_MAX_SRC];
78 :
79 0 : for (j = 0; j < n; j++) {
80 0 : sources2[j] = (uint8_t *)sources[j] + len_rem;
81 : }
82 :
83 0 : 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 1 : do_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
94 : {
95 1 : if (buffers_aligned(dest, sources, n, SPDK_XOR_BUF_ALIGN)) {
96 1 : void *buffers[SPDK_XOR_MAX_SRC + 1];
97 :
98 1 : if (n >= INT_MAX) {
99 0 : return -EINVAL;
100 : }
101 :
102 1 : memcpy(buffers, sources, n * sizeof(buffers[0]));
103 1 : buffers[n] = dest;
104 :
105 1 : if (xor_gen(n + 1, len, buffers)) {
106 0 : return -EINVAL;
107 : }
108 : } else {
109 0 : xor_gen_basic(dest, sources, n, len);
110 : }
111 :
112 1 : 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 1 : spdk_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
130 : {
131 1 : if (n < 2 || n > SPDK_XOR_MAX_SRC) {
132 0 : return -EINVAL;
133 : }
134 :
135 1 : return do_xor_gen(dest, sources, n, len);
136 : }
137 :
138 : size_t
139 0 : spdk_xor_get_optimal_alignment(void)
140 : {
141 0 : 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");
|