]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/crc32c_ppc.c
update sources to v12.1.0
[ceph.git] / ceph / src / common / crc32c_ppc.c
1 /* Copyright (C) 2017 International Business Machines Corp.
2 * All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9 #define CRC_TABLE
10 #define FAST_ZERO_TABLE
11
12 #include "acconfig.h"
13 #include "include/int_types.h"
14 #include "crc32c_ppc_constants.h"
15 #include "reverse.h"
16
17 #include <stdlib.h>
18 #include <strings.h>
19
20 #define VMX_ALIGN 16
21 #define VMX_ALIGN_MASK (VMX_ALIGN-1)
22
23 #ifdef REFLECT
24 static unsigned int crc32_align(unsigned int crc, unsigned char const *p,
25 unsigned long len)
26 {
27 while (len--)
28 crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
29 return crc;
30 }
31 #else
32 static unsigned int crc32_align(unsigned int crc, unsigned char const *p,
33 unsigned long len)
34 {
35 while (len--)
36 crc = crc_table[((crc >> 24) ^ *p++) & 0xff] ^ (crc << 8);
37 return crc;
38 }
39 #endif
40
41 #ifdef HAVE_POWER8
42 static inline unsigned long polynomial_multiply(unsigned int a, unsigned int b) {
43 vector unsigned int va = {a, 0, 0, 0};
44 vector unsigned int vb = {b, 0, 0, 0};
45 vector unsigned long vt;
46
47 __asm__("vpmsumw %0,%1,%2" : "=v"(vt) : "v"(va), "v"(vb));
48
49 return vt[0];
50 }
51
52 unsigned int barrett_reduction(unsigned long val);
53
54 static inline unsigned int gf_multiply(unsigned int a, unsigned int b) {
55 return barrett_reduction(polynomial_multiply(a, b));
56 }
57
58 unsigned int append_zeros(unsigned int crc, unsigned long length) {
59 unsigned long i = 0;
60
61 while (length) {
62 if (length & 1) {
63 crc = gf_multiply(crc, crc_zero[i]);
64 }
65 i++;
66 length /= 2;
67 }
68
69 return crc;
70 }
71
72
73 unsigned int __crc32_vpmsum(unsigned int crc, unsigned char const *p,
74 unsigned long len);
75
76 static uint32_t crc32_vpmsum(uint32_t crc, unsigned char const *data,
77 unsigned len)
78 {
79 unsigned int prealign;
80 unsigned int tail;
81
82 #ifdef CRC_XOR
83 crc ^= 0xffffffff;
84 #endif
85
86 if (len < VMX_ALIGN + VMX_ALIGN_MASK) {
87 crc = crc32_align(crc, data, (unsigned long)len);
88 goto out;
89 }
90
91 if ((unsigned long)data & VMX_ALIGN_MASK) {
92 prealign = VMX_ALIGN - ((unsigned long)data & VMX_ALIGN_MASK);
93 crc = crc32_align(crc, data, prealign);
94 len -= prealign;
95 data += prealign;
96 }
97
98 crc = __crc32_vpmsum(crc, data, (unsigned long)len & ~VMX_ALIGN_MASK);
99
100 tail = len & VMX_ALIGN_MASK;
101 if (tail) {
102 data += len & ~VMX_ALIGN_MASK;
103 crc = crc32_align(crc, data, tail);
104 }
105
106 out:
107 #ifdef CRC_XOR
108 crc ^= 0xffffffff;
109 #endif
110
111 return crc;
112 }
113
114 /* This wrapper function works around the fact that crc32_vpmsum
115 * does not gracefully handle the case where the data pointer is NULL.
116 */
117 uint32_t ceph_crc32c_ppc(uint32_t crc, unsigned char const *data, unsigned len)
118 {
119 if (!data) {
120 /* Handle the NULL buffer case. */
121 #ifdef REFLECT
122 crc = reverse_bits(crc);
123 #endif
124
125 crc = append_zeros(crc, len);
126
127 #ifdef REFLECT
128 crc = reverse_bits(crc);
129 #endif
130 } else {
131 /* Handle the valid buffer case. */
132 crc = crc32_vpmsum(crc, data, (unsigned long)len);
133 }
134 return crc;
135 }
136
137 #else /* HAVE_POWER8 */
138
139 /* This symbol has to exist on non-ppc architectures (and on legacy
140 * ppc systems using power7 or below) in order to compile properly
141 * there, even though it won't be called.
142 */
143 uint32_t ceph_crc32c_ppc(uint32_t crc, unsigned char const *data, unsigned len)
144 {
145 return 0;
146 }
147
148 #endif /* HAVE_POWER8 */