Blame gfs2/libgfs2/crc32c.c

Packit 6ef888
/*
Packit 6ef888
 * Copied from btrfs-progs, kernel-lib/crc32c.c, which was:
Packit 6ef888
 * Copied from the kernel source code, lib/libcrc32c.c.
Packit 6ef888
 *
Packit 6ef888
 * This program is free software; you can redistribute it and/or modify it
Packit 6ef888
 * under the terms of the GNU General Public License as published by the Free
Packit 6ef888
 * Software Foundation; either version 2 of the License, or (at your option)
Packit 6ef888
 * any later version.
Packit 6ef888
 *
Packit 6ef888
 */
Packit 6ef888
#include <stdlib.h>
Packit 6ef888
#include <inttypes.h>
Packit 6ef888
#include "crc32c.h"
Packit 6ef888
Packit 6ef888
static uint32_t __crc32c_le(uint32_t crc, unsigned char const *data, size_t length);
Packit 6ef888
static uint32_t (*crc_function)(uint32_t crc, unsigned char const *data, size_t length) = __crc32c_le;
Packit 6ef888
Packit 6ef888
#ifdef __x86_64__
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * Based on a posting to lkml by Austin Zhang <austin.zhang@intel.com>
Packit 6ef888
 *
Packit 6ef888
 * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal.
Packit 6ef888
 * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE)
Packit 6ef888
 * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at:
Packit 6ef888
 * http://www.intel.com/products/processor/manuals/
Packit 6ef888
 * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
Packit 6ef888
 * Volume 2A: Instruction Set Reference, A-M
Packit 6ef888
 */
Packit 6ef888
#if  __SIZEOF_LONG__ == 8
Packit 6ef888
#define REX_PRE "0x48, "
Packit 6ef888
#define SCALE_F 8
Packit 6ef888
#else
Packit 6ef888
#define REX_PRE
Packit 6ef888
#define SCALE_F 4
Packit 6ef888
#endif
Packit 6ef888
Packit 6ef888
static int crc32c_probed = 0;
Packit 6ef888
static int crc32c_intel_available = 0;
Packit 6ef888
Packit 6ef888
static uint32_t crc32c_intel_le_hw_byte(uint32_t crc, unsigned char const *data,
Packit 6ef888
					unsigned long length)
Packit 6ef888
{
Packit 6ef888
	while (length--) {
Packit 6ef888
		__asm__ __volatile__(
Packit 6ef888
			".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
Packit 6ef888
			:"=S"(crc)
Packit 6ef888
			:"0"(crc), "c"(*data)
Packit 6ef888
		);
Packit 6ef888
		data++;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return crc;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * Steps through buffer one byte at at time, calculates reflected 
Packit 6ef888
 * crc using table.
Packit 6ef888
 */
Packit 6ef888
static uint32_t crc32c_intel(uint32_t crc, unsigned char const *data, unsigned long length)
Packit 6ef888
{
Packit 6ef888
	unsigned int iquotient = length / SCALE_F;
Packit 6ef888
	unsigned int iremainder = length % SCALE_F;
Packit 6ef888
	unsigned long *ptmp = (unsigned long *)data;
Packit 6ef888
Packit 6ef888
	while (iquotient--) {
Packit 6ef888
		__asm__ __volatile__(
Packit 6ef888
			".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
Packit 6ef888
			:"=S"(crc)
Packit 6ef888
			:"0"(crc), "c"(*ptmp)
Packit 6ef888
		);
Packit 6ef888
		ptmp++;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (iremainder)
Packit 6ef888
		crc = crc32c_intel_le_hw_byte(crc, (unsigned char *)ptmp,
Packit 6ef888
				 iremainder);
Packit 6ef888
Packit 6ef888
	return crc;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void do_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
Packit 6ef888
		     unsigned int *edx)
Packit 6ef888
{
Packit 6ef888
	int id = *eax;
Packit 6ef888
Packit 6ef888
	asm("movl %4, %%eax;"
Packit 6ef888
	    "cpuid;"
Packit 6ef888
	    "movl %%eax, %0;"
Packit 6ef888
	    "movl %%ebx, %1;"
Packit 6ef888
	    "movl %%ecx, %2;"
Packit 6ef888
	    "movl %%edx, %3;"
Packit 6ef888
		: "=r" (*eax), "=r" (*ebx), "=r" (*ecx), "=r" (*edx)
Packit 6ef888
		: "r" (id)
Packit 6ef888
		: "eax", "ebx", "ecx", "edx");
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void crc32c_intel_probe(void)
Packit 6ef888
{
Packit 6ef888
	if (!crc32c_probed) {
Packit 6ef888
		unsigned int eax, ebx, ecx, edx;
Packit 6ef888
Packit 6ef888
		eax = 1;
Packit 6ef888
Packit 6ef888
		do_cpuid(&eax, &ebx, &ecx, &edx;;
Packit 6ef888
		crc32c_intel_available = (ecx & (1 << 20)) != 0;
Packit 6ef888
		crc32c_probed = 1;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void crc32c_optimization_init(void)
Packit 6ef888
{
Packit 6ef888
	crc32c_intel_probe();
Packit 6ef888
	if (crc32c_intel_available)
Packit 6ef888
		crc_function = crc32c_intel;
Packit 6ef888
}
Packit 6ef888
#else
Packit 6ef888
Packit 6ef888
void crc32c_optimization_init(void)
Packit 6ef888
{
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
#endif /* __x86_64__ */
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * This is the CRC-32C table
Packit 6ef888
 * Generated with:
Packit 6ef888
 * width = 32 bits
Packit 6ef888
 * poly = 0x1EDC6F41
Packit 6ef888
 * reflect input bytes = true
Packit 6ef888
 * reflect output bytes = true
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
static const uint32_t crc32c_table[256] = {
Packit 6ef888
	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
Packit 6ef888
	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
Packit 6ef888
	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
Packit 6ef888
	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
Packit 6ef888
	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
Packit 6ef888
	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
Packit 6ef888
	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
Packit 6ef888
	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
Packit 6ef888
	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
Packit 6ef888
	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
Packit 6ef888
	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
Packit 6ef888
	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
Packit 6ef888
	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
Packit 6ef888
	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
Packit 6ef888
	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
Packit 6ef888
	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
Packit 6ef888
	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
Packit 6ef888
	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
Packit 6ef888
	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
Packit 6ef888
	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
Packit 6ef888
	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
Packit 6ef888
	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
Packit 6ef888
	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
Packit 6ef888
	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
Packit 6ef888
	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
Packit 6ef888
	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
Packit 6ef888
	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
Packit 6ef888
	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
Packit 6ef888
	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
Packit 6ef888
	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
Packit 6ef888
	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
Packit 6ef888
	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
Packit 6ef888
	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
Packit 6ef888
	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
Packit 6ef888
	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
Packit 6ef888
	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
Packit 6ef888
	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
Packit 6ef888
	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
Packit 6ef888
	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
Packit 6ef888
	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
Packit 6ef888
	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
Packit 6ef888
	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
Packit 6ef888
	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
Packit 6ef888
	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
Packit 6ef888
	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
Packit 6ef888
	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
Packit 6ef888
	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
Packit 6ef888
	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
Packit 6ef888
	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
Packit 6ef888
	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
Packit 6ef888
	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
Packit 6ef888
	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
Packit 6ef888
	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
Packit 6ef888
	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
Packit 6ef888
	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
Packit 6ef888
	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
Packit 6ef888
	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
Packit 6ef888
	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
Packit 6ef888
	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
Packit 6ef888
	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
Packit 6ef888
	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
Packit 6ef888
	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
Packit 6ef888
	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
Packit 6ef888
	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * Steps through buffer one byte at at time, calculates reflected 
Packit 6ef888
 * crc using table.
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
static uint32_t __crc32c_le(uint32_t crc, unsigned char const *data, size_t length)
Packit 6ef888
{
Packit 6ef888
	while (length--)
Packit 6ef888
		crc =
Packit 6ef888
		    crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
Packit 6ef888
	return crc;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
uint32_t crc32c(uint32_t crc, unsigned char const *data, size_t length)
Packit 6ef888
{
Packit 6ef888
	/* Use by-byte access for unaligned buffers */
Packit 6ef888
	if ((unsigned long)data % sizeof(unsigned long))
Packit 6ef888
		return __crc32c_le(crc, data, length);
Packit 6ef888
Packit 6ef888
	return crc_function(crc, data, length);
Packit 6ef888
}