hd_crc.h revision 10777:66a375946c31
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2009, Intel Corporation.
24 * All rights reserved.
25 */
26
27/*
28 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
29 * Use is subject to license terms.
30 */
31
32#ifndef	_CRC_HD_H
33#define	_CRC_HD_H
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39#include <sys/types.h>
40
41#ifdef __cplusplus
42#ifndef INLINE
43#define	INLINE inline
44#endif
45#else
46#ifndef INLINE
47#define	INLINE
48#endif
49#endif
50
51#if defined(__i386) || defined(__amd_64) || defined(__x86_64)
52
53#define	INTEL_CPU_FEATURE_SSE42	0x0100000
54
55static INLINE unsigned int
56#ifdef _KERNEL
57/*LINTED:E_FUNC_ARG_UNUSED*/
58cpuid_ecx(unsigned int op)
59#else
60cpuid_ecx(unsigned int op)
61#endif /* _KERNEL */
62{
63	/*LINTED:E_FUNC_VAR_UNUSED*/
64	unsigned int eax, ecx;
65	__asm__ __volatile__("cpuid"
66	    : "=a" (eax), "=c" (ecx)
67	    : "0" (op)
68	    : "bx", "dx");
69	/*LINTED:E_VAR_USED_BEFORE_SET*/
70	return (ecx);
71}
72
73static INLINE uint32_t
74#ifdef _KERNEL
75/*LINTED:E_FUNC_ARG_UNUSED*/
76mm_crc32_u8(uint32_t crc, uint8_t *data)
77#else
78mm_crc32_u8(uint32_t crc, uint8_t *data)
79#endif /* _KERNEL */
80{
81	__asm__ __volatile__(
82	    /* "crc32 r32, r/m8" */
83	    ".byte 0xF2, 0x0F, 0x38, 0xF0, 0xF1"
84	    : "=S" (crc)
85	    : "0" (crc), "c" (*data));
86
87	return (crc);
88}
89
90#if defined(__amd64) || defined(__x86_64)
91
92static INLINE uint32_t
93#ifdef _KERNEL
94/*LINTED:E_FUNC_ARG_UNUSED*/
95mm_crc32_u64(uint32_t crc, uint64_t *data)
96#else
97mm_crc32_u64(uint32_t crc, uint64_t *data)
98#endif /* _KERNEL */
99{
100	__asm__ __volatile__(
101	    /* "crc32 r32, r/m64" */
102	    ".byte 0xF2, 0x48, 0x0F, 0x38, 0xF1, 0xF1"
103	    : "=S" (crc)
104	    : "0" (crc), "c" (*data));
105
106	return (crc);
107}
108
109#define	INTEL_CRC_ALIGN_MASK 0x7
110#define	INTEL_CRC_SIZE 8
111#define	INTEL_CRC_DATA_TYPE uint64_t
112#define	INTEL_CRC_FUNC mm_crc32_u64
113
114#else
115
116static INLINE uint32_t
117#ifdef _KERNEL
118/*LINTED:E_FUNC_ARG_UNUSED*/
119mm_crc32_u32(uint32_t crc, uint32_t *data)
120#else
121mm_crc32_u32(uint32_t crc, uint32_t *data)
122#endif /* _KERNEL */
123{
124	__asm__ __volatile__(
125	    /* "crc32 r32, r/m32" */
126	    ".byte 0xF2, 0x0F, 0x38, 0xF1, 0xF1"
127	    : "=S" (crc)
128	    : "0" (crc), "c" (*data));
129
130	return (crc);
131}
132
133#define	INTEL_CRC_ALIGN_MASK 0x3
134#define	INTEL_CRC_SIZE 4
135#define	INTEL_CRC_DATA_TYPE uint32_t
136#define	INTEL_CRC_FUNC mm_crc32_u32
137
138#endif
139
140static INLINE uint32_t
141intel_crc32c(uint8_t *address, unsigned long length, uint32_t crc)
142{
143	uint32_t i = (uintptr_t)address & INTEL_CRC_ALIGN_MASK;
144	uint8_t *data = address;
145
146	/* Process unaligned header data */
147	while ((length > 0) && (i > 0)) {
148		crc = mm_crc32_u8(crc, data);
149		++ data;
150		-- length;
151		i ++;
152		i &= INTEL_CRC_ALIGN_MASK;
153	}
154
155	/* aligned data part */
156	while (length >= INTEL_CRC_SIZE) {
157		/*LINTED:E_BAD_PTR_CAST_ALIGN*/
158		crc = INTEL_CRC_FUNC(crc, (INTEL_CRC_DATA_TYPE *)data);
159		data += INTEL_CRC_SIZE;
160		length -= INTEL_CRC_SIZE;
161	}
162
163	/* unaligned tail data */
164	while (length > 0) {
165		crc = mm_crc32_u8(crc, data);
166		++ data;
167		-- length;
168	}
169
170	return (crc ^ 0xFFFFFFFF);
171}
172
173#define	HW_CRC32(buffer, length, crc) (intel_crc32c((buffer), (length), (crc)))
174#define	HW_CRC32_CONT(buffer, length, crc) \
175	(intel_crc32c((buffer), (length), (crc) ^ 0xFFFFFFFF))
176#else
177#define	HW_CRC32(buffer, length, crc)		0
178#define	HW_CRC32_CONT(buffer, length, crc)	0
179#endif
180
181static INLINE boolean_t
182#if defined(_KERNEL) && !defined(__i386) && !defined(__amd_64) &&\
183	!defined(__x86_64)
184/*LINTED:E_FUNC_ARG_UNUSED*/
185hd_crc32_avail(uint32_t *crc32_table)
186#else
187hd_crc32_avail(uint32_t *crc32_table)
188#endif
189{
190#if defined(__i386) || defined(__amd_64) || defined(__x86_64)
191	int i;
192	/* poly = 0x1EDC6F41 */
193	static const uint32_t _intel_crc32_hd_table[256] = {
194		0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
195		0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
196		0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
197		0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
198		0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
199		0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
200		0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
201		0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
202		0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
203		0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
204		0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
205		0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
206		0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
207		0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
208		0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
209		0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
210		0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
211		0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
212		0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
213		0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
214		0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
215		0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
216		0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
217		0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
218		0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
219		0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
220		0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
221		0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
222		0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
223		0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
224		0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
225		0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
226		0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
227		0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
228		0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
229		0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
230		0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
231		0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
232		0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
233		0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
234		0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
235		0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
236		0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
237		0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
238		0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
239		0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
240		0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
241		0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
242		0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
243		0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
244		0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
245		0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
246		0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
247		0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
248		0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
249		0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
250		0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
251		0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
252		0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
253		0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
254		0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
255		0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
256		0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
257		0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
258	};
259
260	if ((cpuid_ecx(1) & INTEL_CPU_FEATURE_SSE42) != 0) {
261		for (i = 0; i < 256; i++) {
262			if (crc32_table[i] != _intel_crc32_hd_table[i])
263				return (B_FALSE);
264		}
265		return (B_TRUE);
266	}
267#endif
268	return (B_FALSE);
269}
270
271#ifdef __cplusplus
272}
273#endif
274
275#endif /* _CRC_HD_H */
276