diff options
Diffstat (limited to 'fs/btrfs/crc32c.h')
-rw-r--r-- | fs/btrfs/crc32c.h | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/fs/btrfs/crc32c.h b/fs/btrfs/crc32c.h new file mode 100644 index 000000000000..1eaf11d334fd --- /dev/null +++ b/fs/btrfs/crc32c.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef __BTRFS_CRC32C__ +#define __BTRFS_CRC32C__ +#include <asm/byteorder.h> +#include <linux/crc32c.h> +#include <linux/version.h> + +/* #define CONFIG_BTRFS_HW_SUM 1 */ + +#ifdef CONFIG_BTRFS_HW_SUM +#ifdef CONFIG_X86 +/* + * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal. + * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE) + * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at: + * http://www.intel.com/products/processor/manuals/ + * Intel(R) 64 and IA-32 Architectures Software Developer's Manual + * Volume 2A: Instruction Set Reference, A-M + */ + +#include <asm/cpufeature.h> +#include <asm/processor.h> + +#define X86_FEATURE_XMM4_2 (4*32+20) /* Streaming SIMD Extensions-4.2 */ +#define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2) + +#ifdef CONFIG_X86_64 +#define REX_PRE "0x48, " +#define SCALE_F 8 +#else +#define REX_PRE +#define SCALE_F 4 +#endif + +static inline u32 btrfs_crc32c_le_hw_byte(u32 crc, unsigned char const *data, + size_t length) +{ + while (length--) { + __asm__ __volatile__( + ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1" + :"=S"(crc) + :"0"(crc), "c"(*data) + ); + data++; + } + + return crc; +} + +static inline u32 __pure btrfs_crc32c_le_hw(u32 crc, unsigned char const *p, + size_t len) +{ + unsigned int iquotient = len / SCALE_F; + unsigned int iremainder = len % SCALE_F; +#ifdef CONFIG_X86_64 + u64 *ptmp = (u64 *)p; +#else + u32 *ptmp = (u32 *)p; +#endif + + while (iquotient--) { + __asm__ __volatile__( + ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;" + :"=S"(crc) + :"0"(crc), "c"(*ptmp) + ); + ptmp++; + } + + if (iremainder) + crc = btrfs_crc32c_le_hw_byte(crc, (unsigned char *)ptmp, + iremainder); + + return crc; +} +#endif /* CONFIG_BTRFS_HW_SUM */ + +static inline u32 __btrfs_crc32c(u32 crc, unsigned char const *address, + size_t len) +{ +#ifdef CONFIG_BTRFS_HW_SUM + if (cpu_has_xmm4_2) + return btrfs_crc32c_le_hw(crc, address, len); +#endif + return crc32c_le(crc, address, len); +} + +#else + +#define __btrfs_crc32c(seed, data, length) crc32c(seed, data, length) + +#endif /* CONFIG_X86 */ + +/** + * implementation of crc32c_le() changed in linux-2.6.23, + * has of v0.13 btrfs-progs is using the latest version. + * We must workaround older implementations of crc32c_le() + * found on older kernel versions. + */ +#define btrfs_crc32c(seed, data, length) \ + __btrfs_crc32c(seed, (unsigned char const *)data, length) +#endif + |