1/* 2 * Cryptographic API for the 842 compression algorithm. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 * Copyright (C) IBM Corporation, 2011 19 * 20 * Authors: Robert Jennings <rcj@linux.vnet.ibm.com> 21 * Seth Jennings <sjenning@linux.vnet.ibm.com> 22 */ 23 24#include <linux/init.h> 25#include <linux/module.h> 26#include <linux/crypto.h> 27#include <linux/vmalloc.h> 28#include <linux/nx842.h> 29#include <linux/lzo.h> 30#include <linux/timer.h> 31 32static int nx842_uselzo; 33 34struct nx842_ctx { 35 void *nx842_wmem; /* working memory for 842/lzo */ 36}; 37 38enum nx842_crypto_type { 39 NX842_CRYPTO_TYPE_842, 40 NX842_CRYPTO_TYPE_LZO 41}; 42 43#define NX842_SENTINEL 0xdeadbeef 44 45struct nx842_crypto_header { 46 unsigned int sentinel; /* debug */ 47 enum nx842_crypto_type type; 48}; 49 50static int nx842_init(struct crypto_tfm *tfm) 51{ 52 struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); 53 int wmemsize; 54 55 wmemsize = max_t(int, nx842_get_workmem_size(), LZO1X_MEM_COMPRESS); 56 ctx->nx842_wmem = kmalloc(wmemsize, GFP_NOFS); 57 if (!ctx->nx842_wmem) 58 return -ENOMEM; 59 60 return 0; 61} 62 63static void nx842_exit(struct crypto_tfm *tfm) 64{ 65 struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); 66 67 kfree(ctx->nx842_wmem); 68} 69 70static void nx842_reset_uselzo(unsigned long data) 71{ 72 nx842_uselzo = 0; 73} 74 75static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0); 76 77static int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src, 78 unsigned int slen, u8 *dst, unsigned int *dlen) 79{ 80 struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); 81 struct nx842_crypto_header *hdr; 82 unsigned int tmp_len = *dlen; 83 size_t lzodlen; /* needed for lzo */ 84 int err; 85 86 *dlen = 0; 87 hdr = (struct nx842_crypto_header *)dst; 88 hdr->sentinel = NX842_SENTINEL; /* debug */ 89 dst += sizeof(struct nx842_crypto_header); 90 tmp_len -= sizeof(struct nx842_crypto_header); 91 lzodlen = tmp_len; 92 93 if (likely(!nx842_uselzo)) { 94 err = nx842_compress(src, slen, dst, &tmp_len, ctx->nx842_wmem); 95 96 if (likely(!err)) { 97 hdr->type = NX842_CRYPTO_TYPE_842; 98 *dlen = tmp_len + sizeof(struct nx842_crypto_header); 99 return 0; 100 } 101 102 /* hardware failed */ 103 nx842_uselzo = 1; 104 105 /* set timer to check for hardware again in 1 second */ 106 mod_timer(&failover_timer, jiffies + msecs_to_jiffies(1000)); 107 } 108 109 /* no hardware, use lzo */ 110 err = lzo1x_1_compress(src, slen, dst, &lzodlen, ctx->nx842_wmem); 111 if (err != LZO_E_OK) 112 return -EINVAL; 113 114 hdr->type = NX842_CRYPTO_TYPE_LZO; 115 *dlen = lzodlen + sizeof(struct nx842_crypto_header); 116 return 0; 117} 118 119static int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src, 120 unsigned int slen, u8 *dst, unsigned int *dlen) 121{ 122 struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); 123 struct nx842_crypto_header *hdr; 124 unsigned int tmp_len = *dlen; 125 size_t lzodlen; /* needed for lzo */ 126 int err; 127 128 *dlen = 0; 129 hdr = (struct nx842_crypto_header *)src; 130 131 if (unlikely(hdr->sentinel != NX842_SENTINEL)) 132 return -EINVAL; 133 134 src += sizeof(struct nx842_crypto_header); 135 slen -= sizeof(struct nx842_crypto_header); 136 137 if (likely(hdr->type == NX842_CRYPTO_TYPE_842)) { 138 err = nx842_decompress(src, slen, dst, &tmp_len, 139 ctx->nx842_wmem); 140 if (err) 141 return -EINVAL; 142 *dlen = tmp_len; 143 } else if (hdr->type == NX842_CRYPTO_TYPE_LZO) { 144 lzodlen = tmp_len; 145 err = lzo1x_decompress_safe(src, slen, dst, &lzodlen); 146 if (err != LZO_E_OK) 147 return -EINVAL; 148 *dlen = lzodlen; 149 } else 150 return -EINVAL; 151 152 return 0; 153} 154 155static struct crypto_alg alg = { 156 .cra_name = "842", 157 .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, 158 .cra_ctxsize = sizeof(struct nx842_ctx), 159 .cra_module = THIS_MODULE, 160 .cra_init = nx842_init, 161 .cra_exit = nx842_exit, 162 .cra_u = { .compress = { 163 .coa_compress = nx842_crypto_compress, 164 .coa_decompress = nx842_crypto_decompress } } 165}; 166 167static int __init nx842_mod_init(void) 168{ 169 del_timer(&failover_timer); 170 return crypto_register_alg(&alg); 171} 172 173static void __exit nx842_mod_exit(void) 174{ 175 crypto_unregister_alg(&alg); 176} 177 178module_init(nx842_mod_init); 179module_exit(nx842_mod_exit); 180 181MODULE_LICENSE("GPL"); 182MODULE_DESCRIPTION("842 Compression Algorithm"); 183MODULE_ALIAS_CRYPTO("842"); 184