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 32 static int nx842_uselzo; 33 34 struct nx842_ctx { 35 void *nx842_wmem; /* working memory for 842/lzo */ 36 }; 37 38 enum nx842_crypto_type { 39 NX842_CRYPTO_TYPE_842, 40 NX842_CRYPTO_TYPE_LZO 41 }; 42 43 #define NX842_SENTINEL 0xdeadbeef 44 45 struct nx842_crypto_header { 46 unsigned int sentinel; /* debug */ 47 enum nx842_crypto_type type; 48 }; 49 50 static 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 63 static 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 70 static void nx842_reset_uselzo(unsigned long data) 71 { 72 nx842_uselzo = 0; 73 } 74 75 static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0); 76 77 static 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 119 static 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 155 static 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 167 static int __init nx842_mod_init(void) 168 { 169 del_timer(&failover_timer); 170 return crypto_register_alg(&alg); 171 } 172 173 static void __exit nx842_mod_exit(void) 174 { 175 crypto_unregister_alg(&alg); 176 } 177 178 module_init(nx842_mod_init); 179 module_exit(nx842_mod_exit); 180 181 MODULE_LICENSE("GPL"); 182 MODULE_DESCRIPTION("842 Compression Algorithm"); 183 MODULE_ALIAS_CRYPTO("842"); 184