168411521cc6055edc6274e03ab3210a5893533baHerbert Xu/* 268411521cc6055edc6274e03ab3210a5893533baHerbert Xu * Cryptographic API. 368411521cc6055edc6274e03ab3210a5893533baHerbert Xu * 468411521cc6055edc6274e03ab3210a5893533baHerbert Xu * T10 Data Integrity Field CRC16 Crypto Transform using PCLMULQDQ Instructions 568411521cc6055edc6274e03ab3210a5893533baHerbert Xu * 668411521cc6055edc6274e03ab3210a5893533baHerbert Xu * Copyright (C) 2013 Intel Corporation 768411521cc6055edc6274e03ab3210a5893533baHerbert Xu * Author: Tim Chen <tim.c.chen@linux.intel.com> 868411521cc6055edc6274e03ab3210a5893533baHerbert Xu * 968411521cc6055edc6274e03ab3210a5893533baHerbert Xu * This program is free software; you can redistribute it and/or modify it 1068411521cc6055edc6274e03ab3210a5893533baHerbert Xu * under the terms of the GNU General Public License as published by the Free 1168411521cc6055edc6274e03ab3210a5893533baHerbert Xu * Software Foundation; either version 2 of the License, or (at your option) 1268411521cc6055edc6274e03ab3210a5893533baHerbert Xu * any later version. 1368411521cc6055edc6274e03ab3210a5893533baHerbert Xu * 1468411521cc6055edc6274e03ab3210a5893533baHerbert Xu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1568411521cc6055edc6274e03ab3210a5893533baHerbert Xu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1668411521cc6055edc6274e03ab3210a5893533baHerbert Xu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1768411521cc6055edc6274e03ab3210a5893533baHerbert Xu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 1868411521cc6055edc6274e03ab3210a5893533baHerbert Xu * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1968411521cc6055edc6274e03ab3210a5893533baHerbert Xu * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2068411521cc6055edc6274e03ab3210a5893533baHerbert Xu * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2168411521cc6055edc6274e03ab3210a5893533baHerbert Xu * SOFTWARE. 2268411521cc6055edc6274e03ab3210a5893533baHerbert Xu * 2368411521cc6055edc6274e03ab3210a5893533baHerbert Xu */ 2468411521cc6055edc6274e03ab3210a5893533baHerbert Xu 2568411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <linux/types.h> 2668411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <linux/module.h> 2768411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <linux/crc-t10dif.h> 2868411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <crypto/internal/hash.h> 2968411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <linux/init.h> 3068411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <linux/string.h> 3168411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <linux/kernel.h> 3268411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <asm/i387.h> 3368411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <asm/cpufeature.h> 3468411521cc6055edc6274e03ab3210a5893533baHerbert Xu#include <asm/cpu_device_id.h> 3568411521cc6055edc6274e03ab3210a5893533baHerbert Xu 3668411521cc6055edc6274e03ab3210a5893533baHerbert Xuasmlinkage __u16 crc_t10dif_pcl(__u16 crc, const unsigned char *buf, 3768411521cc6055edc6274e03ab3210a5893533baHerbert Xu size_t len); 3868411521cc6055edc6274e03ab3210a5893533baHerbert Xu 3968411521cc6055edc6274e03ab3210a5893533baHerbert Xustruct chksum_desc_ctx { 4068411521cc6055edc6274e03ab3210a5893533baHerbert Xu __u16 crc; 4168411521cc6055edc6274e03ab3210a5893533baHerbert Xu}; 4268411521cc6055edc6274e03ab3210a5893533baHerbert Xu 4368411521cc6055edc6274e03ab3210a5893533baHerbert Xu/* 4468411521cc6055edc6274e03ab3210a5893533baHerbert Xu * Steps through buffer one byte at at time, calculates reflected 4568411521cc6055edc6274e03ab3210a5893533baHerbert Xu * crc using table. 4668411521cc6055edc6274e03ab3210a5893533baHerbert Xu */ 4768411521cc6055edc6274e03ab3210a5893533baHerbert Xu 4868411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic int chksum_init(struct shash_desc *desc) 4968411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 5068411521cc6055edc6274e03ab3210a5893533baHerbert Xu struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 5168411521cc6055edc6274e03ab3210a5893533baHerbert Xu 5268411521cc6055edc6274e03ab3210a5893533baHerbert Xu ctx->crc = 0; 5368411521cc6055edc6274e03ab3210a5893533baHerbert Xu 5468411521cc6055edc6274e03ab3210a5893533baHerbert Xu return 0; 5568411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 5668411521cc6055edc6274e03ab3210a5893533baHerbert Xu 5768411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic int chksum_update(struct shash_desc *desc, const u8 *data, 5868411521cc6055edc6274e03ab3210a5893533baHerbert Xu unsigned int length) 5968411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 6068411521cc6055edc6274e03ab3210a5893533baHerbert Xu struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 6168411521cc6055edc6274e03ab3210a5893533baHerbert Xu 6268411521cc6055edc6274e03ab3210a5893533baHerbert Xu if (irq_fpu_usable()) { 6368411521cc6055edc6274e03ab3210a5893533baHerbert Xu kernel_fpu_begin(); 6468411521cc6055edc6274e03ab3210a5893533baHerbert Xu ctx->crc = crc_t10dif_pcl(ctx->crc, data, length); 6568411521cc6055edc6274e03ab3210a5893533baHerbert Xu kernel_fpu_end(); 6668411521cc6055edc6274e03ab3210a5893533baHerbert Xu } else 6768411521cc6055edc6274e03ab3210a5893533baHerbert Xu ctx->crc = crc_t10dif_generic(ctx->crc, data, length); 6868411521cc6055edc6274e03ab3210a5893533baHerbert Xu return 0; 6968411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 7068411521cc6055edc6274e03ab3210a5893533baHerbert Xu 7168411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic int chksum_final(struct shash_desc *desc, u8 *out) 7268411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 7368411521cc6055edc6274e03ab3210a5893533baHerbert Xu struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 7468411521cc6055edc6274e03ab3210a5893533baHerbert Xu 7568411521cc6055edc6274e03ab3210a5893533baHerbert Xu *(__u16 *)out = ctx->crc; 7668411521cc6055edc6274e03ab3210a5893533baHerbert Xu return 0; 7768411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 7868411521cc6055edc6274e03ab3210a5893533baHerbert Xu 7968411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len, 8068411521cc6055edc6274e03ab3210a5893533baHerbert Xu u8 *out) 8168411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 8268411521cc6055edc6274e03ab3210a5893533baHerbert Xu if (irq_fpu_usable()) { 8368411521cc6055edc6274e03ab3210a5893533baHerbert Xu kernel_fpu_begin(); 8468411521cc6055edc6274e03ab3210a5893533baHerbert Xu *(__u16 *)out = crc_t10dif_pcl(*crcp, data, len); 8568411521cc6055edc6274e03ab3210a5893533baHerbert Xu kernel_fpu_end(); 8668411521cc6055edc6274e03ab3210a5893533baHerbert Xu } else 8768411521cc6055edc6274e03ab3210a5893533baHerbert Xu *(__u16 *)out = crc_t10dif_generic(*crcp, data, len); 8868411521cc6055edc6274e03ab3210a5893533baHerbert Xu return 0; 8968411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 9068411521cc6055edc6274e03ab3210a5893533baHerbert Xu 9168411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic int chksum_finup(struct shash_desc *desc, const u8 *data, 9268411521cc6055edc6274e03ab3210a5893533baHerbert Xu unsigned int len, u8 *out) 9368411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 9468411521cc6055edc6274e03ab3210a5893533baHerbert Xu struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 9568411521cc6055edc6274e03ab3210a5893533baHerbert Xu 9668411521cc6055edc6274e03ab3210a5893533baHerbert Xu return __chksum_finup(&ctx->crc, data, len, out); 9768411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 9868411521cc6055edc6274e03ab3210a5893533baHerbert Xu 9968411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic int chksum_digest(struct shash_desc *desc, const u8 *data, 10068411521cc6055edc6274e03ab3210a5893533baHerbert Xu unsigned int length, u8 *out) 10168411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 10268411521cc6055edc6274e03ab3210a5893533baHerbert Xu struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 10368411521cc6055edc6274e03ab3210a5893533baHerbert Xu 10468411521cc6055edc6274e03ab3210a5893533baHerbert Xu return __chksum_finup(&ctx->crc, data, length, out); 10568411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 10668411521cc6055edc6274e03ab3210a5893533baHerbert Xu 10768411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic struct shash_alg alg = { 10868411521cc6055edc6274e03ab3210a5893533baHerbert Xu .digestsize = CRC_T10DIF_DIGEST_SIZE, 10968411521cc6055edc6274e03ab3210a5893533baHerbert Xu .init = chksum_init, 11068411521cc6055edc6274e03ab3210a5893533baHerbert Xu .update = chksum_update, 11168411521cc6055edc6274e03ab3210a5893533baHerbert Xu .final = chksum_final, 11268411521cc6055edc6274e03ab3210a5893533baHerbert Xu .finup = chksum_finup, 11368411521cc6055edc6274e03ab3210a5893533baHerbert Xu .digest = chksum_digest, 11468411521cc6055edc6274e03ab3210a5893533baHerbert Xu .descsize = sizeof(struct chksum_desc_ctx), 11568411521cc6055edc6274e03ab3210a5893533baHerbert Xu .base = { 11668411521cc6055edc6274e03ab3210a5893533baHerbert Xu .cra_name = "crct10dif", 11768411521cc6055edc6274e03ab3210a5893533baHerbert Xu .cra_driver_name = "crct10dif-pclmul", 11868411521cc6055edc6274e03ab3210a5893533baHerbert Xu .cra_priority = 200, 11968411521cc6055edc6274e03ab3210a5893533baHerbert Xu .cra_blocksize = CRC_T10DIF_BLOCK_SIZE, 12068411521cc6055edc6274e03ab3210a5893533baHerbert Xu .cra_module = THIS_MODULE, 12168411521cc6055edc6274e03ab3210a5893533baHerbert Xu } 12268411521cc6055edc6274e03ab3210a5893533baHerbert Xu}; 12368411521cc6055edc6274e03ab3210a5893533baHerbert Xu 12468411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic const struct x86_cpu_id crct10dif_cpu_id[] = { 12568411521cc6055edc6274e03ab3210a5893533baHerbert Xu X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ), 12668411521cc6055edc6274e03ab3210a5893533baHerbert Xu {} 12768411521cc6055edc6274e03ab3210a5893533baHerbert Xu}; 12868411521cc6055edc6274e03ab3210a5893533baHerbert XuMODULE_DEVICE_TABLE(x86cpu, crct10dif_cpu_id); 12968411521cc6055edc6274e03ab3210a5893533baHerbert Xu 13068411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic int __init crct10dif_intel_mod_init(void) 13168411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 13268411521cc6055edc6274e03ab3210a5893533baHerbert Xu if (!x86_match_cpu(crct10dif_cpu_id)) 13368411521cc6055edc6274e03ab3210a5893533baHerbert Xu return -ENODEV; 13468411521cc6055edc6274e03ab3210a5893533baHerbert Xu 13568411521cc6055edc6274e03ab3210a5893533baHerbert Xu return crypto_register_shash(&alg); 13668411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 13768411521cc6055edc6274e03ab3210a5893533baHerbert Xu 13868411521cc6055edc6274e03ab3210a5893533baHerbert Xustatic void __exit crct10dif_intel_mod_fini(void) 13968411521cc6055edc6274e03ab3210a5893533baHerbert Xu{ 14068411521cc6055edc6274e03ab3210a5893533baHerbert Xu crypto_unregister_shash(&alg); 14168411521cc6055edc6274e03ab3210a5893533baHerbert Xu} 14268411521cc6055edc6274e03ab3210a5893533baHerbert Xu 14368411521cc6055edc6274e03ab3210a5893533baHerbert Xumodule_init(crct10dif_intel_mod_init); 14468411521cc6055edc6274e03ab3210a5893533baHerbert Xumodule_exit(crct10dif_intel_mod_fini); 14568411521cc6055edc6274e03ab3210a5893533baHerbert Xu 14668411521cc6055edc6274e03ab3210a5893533baHerbert XuMODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>"); 14768411521cc6055edc6274e03ab3210a5893533baHerbert XuMODULE_DESCRIPTION("T10 DIF CRC calculation accelerated with PCLMULQDQ."); 14868411521cc6055edc6274e03ab3210a5893533baHerbert XuMODULE_LICENSE("GPL"); 14968411521cc6055edc6274e03ab3210a5893533baHerbert Xu 15068411521cc6055edc6274e03ab3210a5893533baHerbert XuMODULE_ALIAS("crct10dif"); 15168411521cc6055edc6274e03ab3210a5893533baHerbert XuMODULE_ALIAS("crct10dif-pclmul"); 152