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 4 : is_aligned(void *ptr, size_t alignment)
16 : {
17 4 : uintptr_t p = (uintptr_t)ptr;
18 :
19 4 : return p == SPDK_ALIGN_FLOOR(p, alignment);
20 : }
21 :
22 : static bool
23 2 : buffers_aligned(void *dest, void **sources, uint32_t n, size_t alignment)
24 : {
25 : uint32_t i;
26 :
27 4 : for (i = 0; i < n; i++) {
28 3 : if (!is_aligned(sources[i], alignment)) {
29 1 : return false;
30 : }
31 2 : }
32 :
33 1 : return is_aligned(dest, alignment);
34 2 : }
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 0 : }
47 0 : ((uint8_t *)dest)[i] = b;
48 0 : }
49 0 : }
50 :
51 : static void
52 1 : 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 1 : if (!buffers_aligned(dest, sources, n, sizeof(uint64_t))) {
59 0 : xor_gen_unaligned(dest, sources, n, len);
60 0 : return;
61 : }
62 :
63 1 : shift = spdk_u32log2(sizeof(uint64_t));
64 1 : len_div = len >> shift;
65 1 : len_rem = len_div << shift;
66 :
67 9 : for (i = 0; i < len_div; i++) {
68 8 : uint64_t w = 0;
69 :
70 24 : for (j = 0; j < n; j++) {
71 16 : w ^= ((uint64_t *)sources[j])[i];
72 16 : }
73 8 : ((uint64_t *)dest)[i] = w;
74 8 : }
75 :
76 1 : if (len_rem < len) {
77 : 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 0 : }
82 :
83 0 : xor_gen_unaligned((uint8_t *)dest + len_rem, sources2, n, len - len_rem);
84 0 : }
85 1 : }
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 : void *buffers[SPDK_XOR_MAX_SRC + 1];
97 :
98 0 : if (n >= INT_MAX) {
99 0 : return -EINVAL;
100 : }
101 :
102 0 : memcpy(buffers, sources, n * sizeof(buffers[0]));
103 0 : buffers[n] = dest;
104 :
105 0 : if (xor_gen(n + 1, len, buffers)) {
106 0 : return -EINVAL;
107 : }
108 0 : } else {
109 1 : xor_gen_basic(dest, sources, n, len);
110 : }
111 :
112 1 : return 0;
113 1 : }
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 1 : }
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");
|