| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Support for Marvell's crypto engine which can be found on some Orion5X | 
 | 3 |  * boards. | 
 | 4 |  * | 
 | 5 |  * Author: Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > | 
 | 6 |  * License: GPLv2 | 
 | 7 |  * | 
 | 8 |  */ | 
 | 9 | #include <crypto/aes.h> | 
 | 10 | #include <crypto/algapi.h> | 
 | 11 | #include <linux/crypto.h> | 
 | 12 | #include <linux/interrupt.h> | 
 | 13 | #include <linux/io.h> | 
 | 14 | #include <linux/kthread.h> | 
 | 15 | #include <linux/platform_device.h> | 
 | 16 | #include <linux/scatterlist.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 17 | #include <linux/slab.h> | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 18 | #include <crypto/internal/hash.h> | 
 | 19 | #include <crypto/sha.h> | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 20 |  | 
 | 21 | #include "mv_cesa.h" | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 22 |  | 
 | 23 | #define MV_CESA	"MV-CESA:" | 
 | 24 | #define MAX_HW_HASH_SIZE	0xFFFF | 
 | 25 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 26 | /* | 
 | 27 |  * STM: | 
 | 28 |  *   /---------------------------------------\ | 
 | 29 |  *   |					     | request complete | 
 | 30 |  *  \./					     | | 
 | 31 |  * IDLE -> new request -> BUSY -> done -> DEQUEUE | 
 | 32 |  *                         /°\               | | 
 | 33 |  *			    |		     | more scatter entries | 
 | 34 |  *			    \________________/ | 
 | 35 |  */ | 
 | 36 | enum engine_status { | 
 | 37 | 	ENGINE_IDLE, | 
 | 38 | 	ENGINE_BUSY, | 
 | 39 | 	ENGINE_W_DEQUEUE, | 
 | 40 | }; | 
 | 41 |  | 
 | 42 | /** | 
 | 43 |  * struct req_progress - used for every crypt request | 
 | 44 |  * @src_sg_it:		sg iterator for src | 
 | 45 |  * @dst_sg_it:		sg iterator for dst | 
 | 46 |  * @sg_src_left:	bytes left in src to process (scatter list) | 
 | 47 |  * @src_start:		offset to add to src start position (scatter list) | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 48 |  * @crypt_len:		length of current hw crypt/hash process | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 49 |  * @hw_nbytes:		total bytes to process in hw for this request | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 50 |  * @copy_back:		whether to copy data back (crypt) or not (hash) | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 51 |  * @sg_dst_left:	bytes left dst to process in this scatter list | 
 | 52 |  * @dst_start:		offset to add to dst start position (scatter list) | 
| Uri Simchoni | 7a5f691 | 2010-04-08 19:29:16 +0300 | [diff] [blame] | 53 |  * @hw_processed_bytes:	number of bytes processed by hw (request). | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 54 |  * | 
 | 55 |  * sg helper are used to iterate over the scatterlist. Since the size of the | 
 | 56 |  * SRAM may be less than the scatter size, this struct struct is used to keep | 
 | 57 |  * track of progress within current scatterlist. | 
 | 58 |  */ | 
 | 59 | struct req_progress { | 
 | 60 | 	struct sg_mapping_iter src_sg_it; | 
 | 61 | 	struct sg_mapping_iter dst_sg_it; | 
| Uri Simchoni | a58094a | 2010-04-08 19:30:19 +0300 | [diff] [blame] | 62 | 	void (*complete) (void); | 
 | 63 | 	void (*process) (int is_first); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 64 |  | 
 | 65 | 	/* src mostly */ | 
 | 66 | 	int sg_src_left; | 
 | 67 | 	int src_start; | 
 | 68 | 	int crypt_len; | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 69 | 	int hw_nbytes; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 70 | 	/* dst mostly */ | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 71 | 	int copy_back; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 72 | 	int sg_dst_left; | 
 | 73 | 	int dst_start; | 
| Uri Simchoni | 7a5f691 | 2010-04-08 19:29:16 +0300 | [diff] [blame] | 74 | 	int hw_processed_bytes; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 75 | }; | 
 | 76 |  | 
 | 77 | struct crypto_priv { | 
 | 78 | 	void __iomem *reg; | 
 | 79 | 	void __iomem *sram; | 
 | 80 | 	int irq; | 
 | 81 | 	struct task_struct *queue_th; | 
 | 82 |  | 
 | 83 | 	/* the lock protects queue and eng_st */ | 
 | 84 | 	spinlock_t lock; | 
 | 85 | 	struct crypto_queue queue; | 
 | 86 | 	enum engine_status eng_st; | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 87 | 	struct crypto_async_request *cur_req; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 88 | 	struct req_progress p; | 
 | 89 | 	int max_req_size; | 
 | 90 | 	int sram_size; | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 91 | 	int has_sha1; | 
 | 92 | 	int has_hmac_sha1; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 93 | }; | 
 | 94 |  | 
 | 95 | static struct crypto_priv *cpg; | 
 | 96 |  | 
 | 97 | struct mv_ctx { | 
 | 98 | 	u8 aes_enc_key[AES_KEY_LEN]; | 
 | 99 | 	u32 aes_dec_key[8]; | 
 | 100 | 	int key_len; | 
 | 101 | 	u32 need_calc_aes_dkey; | 
 | 102 | }; | 
 | 103 |  | 
 | 104 | enum crypto_op { | 
 | 105 | 	COP_AES_ECB, | 
 | 106 | 	COP_AES_CBC, | 
 | 107 | }; | 
 | 108 |  | 
 | 109 | struct mv_req_ctx { | 
 | 110 | 	enum crypto_op op; | 
 | 111 | 	int decrypt; | 
 | 112 | }; | 
 | 113 |  | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 114 | enum hash_op { | 
 | 115 | 	COP_SHA1, | 
 | 116 | 	COP_HMAC_SHA1 | 
 | 117 | }; | 
 | 118 |  | 
 | 119 | struct mv_tfm_hash_ctx { | 
 | 120 | 	struct crypto_shash *fallback; | 
 | 121 | 	struct crypto_shash *base_hash; | 
 | 122 | 	u32 ivs[2 * SHA1_DIGEST_SIZE / 4]; | 
 | 123 | 	int count_add; | 
 | 124 | 	enum hash_op op; | 
 | 125 | }; | 
 | 126 |  | 
 | 127 | struct mv_req_hash_ctx { | 
 | 128 | 	u64 count; | 
 | 129 | 	u32 state[SHA1_DIGEST_SIZE / 4]; | 
 | 130 | 	u8 buffer[SHA1_BLOCK_SIZE]; | 
 | 131 | 	int first_hash;		/* marks that we don't have previous state */ | 
 | 132 | 	int last_chunk;		/* marks that this is the 'final' request */ | 
 | 133 | 	int extra_bytes;	/* unprocessed bytes in buffer */ | 
 | 134 | 	enum hash_op op; | 
 | 135 | 	int count_add; | 
 | 136 | 	struct scatterlist dummysg; | 
 | 137 | }; | 
 | 138 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 139 | static void compute_aes_dec_key(struct mv_ctx *ctx) | 
 | 140 | { | 
 | 141 | 	struct crypto_aes_ctx gen_aes_key; | 
 | 142 | 	int key_pos; | 
 | 143 |  | 
 | 144 | 	if (!ctx->need_calc_aes_dkey) | 
 | 145 | 		return; | 
 | 146 |  | 
 | 147 | 	crypto_aes_expand_key(&gen_aes_key, ctx->aes_enc_key, ctx->key_len); | 
 | 148 |  | 
 | 149 | 	key_pos = ctx->key_len + 24; | 
 | 150 | 	memcpy(ctx->aes_dec_key, &gen_aes_key.key_enc[key_pos], 4 * 4); | 
 | 151 | 	switch (ctx->key_len) { | 
 | 152 | 	case AES_KEYSIZE_256: | 
 | 153 | 		key_pos -= 2; | 
 | 154 | 		/* fall */ | 
 | 155 | 	case AES_KEYSIZE_192: | 
 | 156 | 		key_pos -= 2; | 
 | 157 | 		memcpy(&ctx->aes_dec_key[4], &gen_aes_key.key_enc[key_pos], | 
 | 158 | 				4 * 4); | 
 | 159 | 		break; | 
 | 160 | 	} | 
 | 161 | 	ctx->need_calc_aes_dkey = 0; | 
 | 162 | } | 
 | 163 |  | 
 | 164 | static int mv_setkey_aes(struct crypto_ablkcipher *cipher, const u8 *key, | 
 | 165 | 		unsigned int len) | 
 | 166 | { | 
 | 167 | 	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); | 
 | 168 | 	struct mv_ctx *ctx = crypto_tfm_ctx(tfm); | 
 | 169 |  | 
 | 170 | 	switch (len) { | 
 | 171 | 	case AES_KEYSIZE_128: | 
 | 172 | 	case AES_KEYSIZE_192: | 
 | 173 | 	case AES_KEYSIZE_256: | 
 | 174 | 		break; | 
 | 175 | 	default: | 
 | 176 | 		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); | 
 | 177 | 		return -EINVAL; | 
 | 178 | 	} | 
 | 179 | 	ctx->key_len = len; | 
 | 180 | 	ctx->need_calc_aes_dkey = 1; | 
 | 181 |  | 
 | 182 | 	memcpy(ctx->aes_enc_key, key, AES_KEY_LEN); | 
 | 183 | 	return 0; | 
 | 184 | } | 
 | 185 |  | 
| Uri Simchoni | 15d4dd3 | 2010-04-08 19:27:02 +0300 | [diff] [blame] | 186 | static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len) | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 187 | { | 
 | 188 | 	int ret; | 
| Uri Simchoni | 15d4dd3 | 2010-04-08 19:27:02 +0300 | [diff] [blame] | 189 | 	void *sbuf; | 
 | 190 | 	int copied = 0; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 191 |  | 
| Uri Simchoni | 15d4dd3 | 2010-04-08 19:27:02 +0300 | [diff] [blame] | 192 | 	while (1) { | 
 | 193 | 		if (!p->sg_src_left) { | 
 | 194 | 			ret = sg_miter_next(&p->src_sg_it); | 
 | 195 | 			BUG_ON(!ret); | 
 | 196 | 			p->sg_src_left = p->src_sg_it.length; | 
 | 197 | 			p->src_start = 0; | 
 | 198 | 		} | 
 | 199 |  | 
 | 200 | 		sbuf = p->src_sg_it.addr + p->src_start; | 
 | 201 |  | 
 | 202 | 		if (p->sg_src_left <= len - copied) { | 
 | 203 | 			memcpy(dbuf + copied, sbuf, p->sg_src_left); | 
 | 204 | 			copied += p->sg_src_left; | 
 | 205 | 			p->sg_src_left = 0; | 
 | 206 | 			if (copied >= len) | 
 | 207 | 				break; | 
 | 208 | 		} else { | 
 | 209 | 			int copy_len = len - copied; | 
 | 210 | 			memcpy(dbuf + copied, sbuf, copy_len); | 
 | 211 | 			p->src_start += copy_len; | 
 | 212 | 			p->sg_src_left -= copy_len; | 
 | 213 | 			break; | 
 | 214 | 		} | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 215 | 	} | 
| Uri Simchoni | 15d4dd3 | 2010-04-08 19:27:02 +0300 | [diff] [blame] | 216 | } | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 217 |  | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 218 | static void setup_data_in(void) | 
| Uri Simchoni | 15d4dd3 | 2010-04-08 19:27:02 +0300 | [diff] [blame] | 219 | { | 
 | 220 | 	struct req_progress *p = &cpg->p; | 
| Uri Simchoni | 0c5c6c4 | 2010-04-08 19:33:26 +0300 | [diff] [blame] | 221 | 	int data_in_sram = | 
| Uri Simchoni | 7a5f691 | 2010-04-08 19:29:16 +0300 | [diff] [blame] | 222 | 	    min(p->hw_nbytes - p->hw_processed_bytes, cpg->max_req_size); | 
| Uri Simchoni | 0c5c6c4 | 2010-04-08 19:33:26 +0300 | [diff] [blame] | 223 | 	copy_src_to_buf(p, cpg->sram + SRAM_DATA_IN_START + p->crypt_len, | 
 | 224 | 			data_in_sram - p->crypt_len); | 
 | 225 | 	p->crypt_len = data_in_sram; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 226 | } | 
 | 227 |  | 
 | 228 | static void mv_process_current_q(int first_block) | 
 | 229 | { | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 230 | 	struct ablkcipher_request *req = ablkcipher_request_cast(cpg->cur_req); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 231 | 	struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | 
 | 232 | 	struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | 
 | 233 | 	struct sec_accel_config op; | 
 | 234 |  | 
 | 235 | 	switch (req_ctx->op) { | 
 | 236 | 	case COP_AES_ECB: | 
 | 237 | 		op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_ECB; | 
 | 238 | 		break; | 
 | 239 | 	case COP_AES_CBC: | 
| Uri Simchoni | 6bc6fcd | 2010-04-08 19:25:56 +0300 | [diff] [blame] | 240 | 	default: | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 241 | 		op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_CBC; | 
 | 242 | 		op.enc_iv = ENC_IV_POINT(SRAM_DATA_IV) | | 
 | 243 | 			ENC_IV_BUF_POINT(SRAM_DATA_IV_BUF); | 
 | 244 | 		if (first_block) | 
 | 245 | 			memcpy(cpg->sram + SRAM_DATA_IV, req->info, 16); | 
 | 246 | 		break; | 
 | 247 | 	} | 
 | 248 | 	if (req_ctx->decrypt) { | 
 | 249 | 		op.config |= CFG_DIR_DEC; | 
 | 250 | 		memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_dec_key, | 
 | 251 | 				AES_KEY_LEN); | 
 | 252 | 	} else { | 
 | 253 | 		op.config |= CFG_DIR_ENC; | 
 | 254 | 		memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_enc_key, | 
 | 255 | 				AES_KEY_LEN); | 
 | 256 | 	} | 
 | 257 |  | 
 | 258 | 	switch (ctx->key_len) { | 
 | 259 | 	case AES_KEYSIZE_128: | 
 | 260 | 		op.config |= CFG_AES_LEN_128; | 
 | 261 | 		break; | 
 | 262 | 	case AES_KEYSIZE_192: | 
 | 263 | 		op.config |= CFG_AES_LEN_192; | 
 | 264 | 		break; | 
 | 265 | 	case AES_KEYSIZE_256: | 
 | 266 | 		op.config |= CFG_AES_LEN_256; | 
 | 267 | 		break; | 
 | 268 | 	} | 
 | 269 | 	op.enc_p = ENC_P_SRC(SRAM_DATA_IN_START) | | 
 | 270 | 		ENC_P_DST(SRAM_DATA_OUT_START); | 
 | 271 | 	op.enc_key_p = SRAM_DATA_KEY_P; | 
 | 272 |  | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 273 | 	setup_data_in(); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 274 | 	op.enc_len = cpg->p.crypt_len; | 
 | 275 | 	memcpy(cpg->sram + SRAM_CONFIG, &op, | 
 | 276 | 			sizeof(struct sec_accel_config)); | 
 | 277 |  | 
 | 278 | 	writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); | 
 | 279 | 	/* GO */ | 
 | 280 | 	writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); | 
 | 281 |  | 
 | 282 | 	/* | 
 | 283 | 	 * XXX: add timer if the interrupt does not occur for some mystery | 
 | 284 | 	 * reason | 
 | 285 | 	 */ | 
 | 286 | } | 
 | 287 |  | 
 | 288 | static void mv_crypto_algo_completion(void) | 
 | 289 | { | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 290 | 	struct ablkcipher_request *req = ablkcipher_request_cast(cpg->cur_req); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 291 | 	struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | 
 | 292 |  | 
| Uri Simchoni | a58094a | 2010-04-08 19:30:19 +0300 | [diff] [blame] | 293 | 	sg_miter_stop(&cpg->p.src_sg_it); | 
 | 294 | 	sg_miter_stop(&cpg->p.dst_sg_it); | 
 | 295 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 296 | 	if (req_ctx->op != COP_AES_CBC) | 
 | 297 | 		return ; | 
 | 298 |  | 
 | 299 | 	memcpy(req->info, cpg->sram + SRAM_DATA_IV_BUF, 16); | 
 | 300 | } | 
 | 301 |  | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 302 | static void mv_process_hash_current(int first_block) | 
 | 303 | { | 
 | 304 | 	struct ahash_request *req = ahash_request_cast(cpg->cur_req); | 
 | 305 | 	struct mv_req_hash_ctx *req_ctx = ahash_request_ctx(req); | 
 | 306 | 	struct req_progress *p = &cpg->p; | 
 | 307 | 	struct sec_accel_config op = { 0 }; | 
 | 308 | 	int is_last; | 
 | 309 |  | 
 | 310 | 	switch (req_ctx->op) { | 
 | 311 | 	case COP_SHA1: | 
 | 312 | 	default: | 
 | 313 | 		op.config = CFG_OP_MAC_ONLY | CFG_MACM_SHA1; | 
 | 314 | 		break; | 
 | 315 | 	case COP_HMAC_SHA1: | 
 | 316 | 		op.config = CFG_OP_MAC_ONLY | CFG_MACM_HMAC_SHA1; | 
 | 317 | 		break; | 
 | 318 | 	} | 
 | 319 |  | 
 | 320 | 	op.mac_src_p = | 
 | 321 | 		MAC_SRC_DATA_P(SRAM_DATA_IN_START) | MAC_SRC_TOTAL_LEN((u32) | 
 | 322 | 		req_ctx-> | 
 | 323 | 		count); | 
 | 324 |  | 
 | 325 | 	setup_data_in(); | 
 | 326 |  | 
 | 327 | 	op.mac_digest = | 
 | 328 | 		MAC_DIGEST_P(SRAM_DIGEST_BUF) | MAC_FRAG_LEN(p->crypt_len); | 
 | 329 | 	op.mac_iv = | 
 | 330 | 		MAC_INNER_IV_P(SRAM_HMAC_IV_IN) | | 
 | 331 | 		MAC_OUTER_IV_P(SRAM_HMAC_IV_OUT); | 
 | 332 |  | 
 | 333 | 	is_last = req_ctx->last_chunk | 
 | 334 | 		&& (p->hw_processed_bytes + p->crypt_len >= p->hw_nbytes) | 
 | 335 | 		&& (req_ctx->count <= MAX_HW_HASH_SIZE); | 
 | 336 | 	if (req_ctx->first_hash) { | 
 | 337 | 		if (is_last) | 
 | 338 | 			op.config |= CFG_NOT_FRAG; | 
 | 339 | 		else | 
 | 340 | 			op.config |= CFG_FIRST_FRAG; | 
 | 341 |  | 
 | 342 | 		req_ctx->first_hash = 0; | 
 | 343 | 	} else { | 
 | 344 | 		if (is_last) | 
 | 345 | 			op.config |= CFG_LAST_FRAG; | 
 | 346 | 		else | 
 | 347 | 			op.config |= CFG_MID_FRAG; | 
 | 348 | 	} | 
 | 349 |  | 
 | 350 | 	memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); | 
 | 351 |  | 
 | 352 | 	writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); | 
 | 353 | 	/* GO */ | 
 | 354 | 	writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); | 
 | 355 |  | 
 | 356 | 	/* | 
 | 357 | 	* XXX: add timer if the interrupt does not occur for some mystery | 
 | 358 | 	* reason | 
 | 359 | 	*/ | 
 | 360 | } | 
 | 361 |  | 
 | 362 | static inline int mv_hash_import_sha1_ctx(const struct mv_req_hash_ctx *ctx, | 
 | 363 | 					  struct shash_desc *desc) | 
 | 364 | { | 
 | 365 | 	int i; | 
 | 366 | 	struct sha1_state shash_state; | 
 | 367 |  | 
 | 368 | 	shash_state.count = ctx->count + ctx->count_add; | 
 | 369 | 	for (i = 0; i < 5; i++) | 
 | 370 | 		shash_state.state[i] = ctx->state[i]; | 
 | 371 | 	memcpy(shash_state.buffer, ctx->buffer, sizeof(shash_state.buffer)); | 
 | 372 | 	return crypto_shash_import(desc, &shash_state); | 
 | 373 | } | 
 | 374 |  | 
 | 375 | static int mv_hash_final_fallback(struct ahash_request *req) | 
 | 376 | { | 
 | 377 | 	const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); | 
 | 378 | 	struct mv_req_hash_ctx *req_ctx = ahash_request_ctx(req); | 
 | 379 | 	struct { | 
 | 380 | 		struct shash_desc shash; | 
 | 381 | 		char ctx[crypto_shash_descsize(tfm_ctx->fallback)]; | 
 | 382 | 	} desc; | 
 | 383 | 	int rc; | 
 | 384 |  | 
 | 385 | 	desc.shash.tfm = tfm_ctx->fallback; | 
 | 386 | 	desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 
 | 387 | 	if (unlikely(req_ctx->first_hash)) { | 
 | 388 | 		crypto_shash_init(&desc.shash); | 
 | 389 | 		crypto_shash_update(&desc.shash, req_ctx->buffer, | 
 | 390 | 				    req_ctx->extra_bytes); | 
 | 391 | 	} else { | 
 | 392 | 		/* only SHA1 for now.... | 
 | 393 | 		 */ | 
 | 394 | 		rc = mv_hash_import_sha1_ctx(req_ctx, &desc.shash); | 
 | 395 | 		if (rc) | 
 | 396 | 			goto out; | 
 | 397 | 	} | 
 | 398 | 	rc = crypto_shash_final(&desc.shash, req->result); | 
 | 399 | out: | 
 | 400 | 	return rc; | 
 | 401 | } | 
 | 402 |  | 
 | 403 | static void mv_hash_algo_completion(void) | 
 | 404 | { | 
 | 405 | 	struct ahash_request *req = ahash_request_cast(cpg->cur_req); | 
 | 406 | 	struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); | 
 | 407 |  | 
 | 408 | 	if (ctx->extra_bytes) | 
 | 409 | 		copy_src_to_buf(&cpg->p, ctx->buffer, ctx->extra_bytes); | 
 | 410 | 	sg_miter_stop(&cpg->p.src_sg_it); | 
 | 411 |  | 
 | 412 | 	ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A); | 
 | 413 | 	ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B); | 
 | 414 | 	ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C); | 
 | 415 | 	ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D); | 
 | 416 | 	ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E); | 
 | 417 |  | 
 | 418 | 	if (likely(ctx->last_chunk)) { | 
 | 419 | 		if (likely(ctx->count <= MAX_HW_HASH_SIZE)) { | 
 | 420 | 			memcpy(req->result, cpg->sram + SRAM_DIGEST_BUF, | 
 | 421 | 			       crypto_ahash_digestsize(crypto_ahash_reqtfm | 
 | 422 | 						       (req))); | 
 | 423 | 		} else | 
 | 424 | 			mv_hash_final_fallback(req); | 
 | 425 | 	} | 
 | 426 | } | 
 | 427 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 428 | static void dequeue_complete_req(void) | 
 | 429 | { | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 430 | 	struct crypto_async_request *req = cpg->cur_req; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 431 | 	void *buf; | 
 | 432 | 	int ret; | 
| Uri Simchoni | 7a5f691 | 2010-04-08 19:29:16 +0300 | [diff] [blame] | 433 | 	cpg->p.hw_processed_bytes += cpg->p.crypt_len; | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 434 | 	if (cpg->p.copy_back) { | 
 | 435 | 		int need_copy_len = cpg->p.crypt_len; | 
 | 436 | 		int sram_offset = 0; | 
 | 437 | 		do { | 
 | 438 | 			int dst_copy; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 439 |  | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 440 | 			if (!cpg->p.sg_dst_left) { | 
 | 441 | 				ret = sg_miter_next(&cpg->p.dst_sg_it); | 
 | 442 | 				BUG_ON(!ret); | 
 | 443 | 				cpg->p.sg_dst_left = cpg->p.dst_sg_it.length; | 
 | 444 | 				cpg->p.dst_start = 0; | 
 | 445 | 			} | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 446 |  | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 447 | 			buf = cpg->p.dst_sg_it.addr; | 
 | 448 | 			buf += cpg->p.dst_start; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 449 |  | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 450 | 			dst_copy = min(need_copy_len, cpg->p.sg_dst_left); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 451 |  | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 452 | 			memcpy(buf, | 
 | 453 | 			       cpg->sram + SRAM_DATA_OUT_START + sram_offset, | 
 | 454 | 			       dst_copy); | 
 | 455 | 			sram_offset += dst_copy; | 
 | 456 | 			cpg->p.sg_dst_left -= dst_copy; | 
 | 457 | 			need_copy_len -= dst_copy; | 
 | 458 | 			cpg->p.dst_start += dst_copy; | 
 | 459 | 		} while (need_copy_len > 0); | 
 | 460 | 	} | 
 | 461 |  | 
| Uri Simchoni | 0c5c6c4 | 2010-04-08 19:33:26 +0300 | [diff] [blame] | 462 | 	cpg->p.crypt_len = 0; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 463 |  | 
 | 464 | 	BUG_ON(cpg->eng_st != ENGINE_W_DEQUEUE); | 
| Uri Simchoni | 7a5f691 | 2010-04-08 19:29:16 +0300 | [diff] [blame] | 465 | 	if (cpg->p.hw_processed_bytes < cpg->p.hw_nbytes) { | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 466 | 		/* process next scatter list entry */ | 
 | 467 | 		cpg->eng_st = ENGINE_BUSY; | 
| Uri Simchoni | a58094a | 2010-04-08 19:30:19 +0300 | [diff] [blame] | 468 | 		cpg->p.process(0); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 469 | 	} else { | 
| Uri Simchoni | a58094a | 2010-04-08 19:30:19 +0300 | [diff] [blame] | 470 | 		cpg->p.complete(); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 471 | 		cpg->eng_st = ENGINE_IDLE; | 
| Uri Simchoni | 0328ac2 | 2010-04-08 19:25:37 +0300 | [diff] [blame] | 472 | 		local_bh_disable(); | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 473 | 		req->complete(req, 0); | 
| Uri Simchoni | 0328ac2 | 2010-04-08 19:25:37 +0300 | [diff] [blame] | 474 | 		local_bh_enable(); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 475 | 	} | 
 | 476 | } | 
 | 477 |  | 
 | 478 | static int count_sgs(struct scatterlist *sl, unsigned int total_bytes) | 
 | 479 | { | 
 | 480 | 	int i = 0; | 
| Uri Simchoni | 15d4dd3 | 2010-04-08 19:27:02 +0300 | [diff] [blame] | 481 | 	size_t cur_len; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 482 |  | 
| Uri Simchoni | 15d4dd3 | 2010-04-08 19:27:02 +0300 | [diff] [blame] | 483 | 	while (1) { | 
 | 484 | 		cur_len = sl[i].length; | 
 | 485 | 		++i; | 
 | 486 | 		if (total_bytes > cur_len) | 
 | 487 | 			total_bytes -= cur_len; | 
 | 488 | 		else | 
 | 489 | 			break; | 
 | 490 | 	} | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 491 |  | 
 | 492 | 	return i; | 
 | 493 | } | 
 | 494 |  | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 495 | static void mv_start_new_crypt_req(struct ablkcipher_request *req) | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 496 | { | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 497 | 	struct req_progress *p = &cpg->p; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 498 | 	int num_sgs; | 
 | 499 |  | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 500 | 	cpg->cur_req = &req->base; | 
 | 501 | 	memset(p, 0, sizeof(struct req_progress)); | 
 | 502 | 	p->hw_nbytes = req->nbytes; | 
| Uri Simchoni | a58094a | 2010-04-08 19:30:19 +0300 | [diff] [blame] | 503 | 	p->complete = mv_crypto_algo_completion; | 
 | 504 | 	p->process = mv_process_current_q; | 
| Uri Simchoni | f0d03de | 2010-04-08 19:31:48 +0300 | [diff] [blame] | 505 | 	p->copy_back = 1; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 506 |  | 
 | 507 | 	num_sgs = count_sgs(req->src, req->nbytes); | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 508 | 	sg_miter_start(&p->src_sg_it, req->src, num_sgs, SG_MITER_FROM_SG); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 509 |  | 
 | 510 | 	num_sgs = count_sgs(req->dst, req->nbytes); | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 511 | 	sg_miter_start(&p->dst_sg_it, req->dst, num_sgs, SG_MITER_TO_SG); | 
 | 512 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 513 | 	mv_process_current_q(1); | 
 | 514 | } | 
 | 515 |  | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 516 | static void mv_start_new_hash_req(struct ahash_request *req) | 
 | 517 | { | 
 | 518 | 	struct req_progress *p = &cpg->p; | 
 | 519 | 	struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); | 
 | 520 | 	const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); | 
 | 521 | 	int num_sgs, hw_bytes, old_extra_bytes, rc; | 
 | 522 | 	cpg->cur_req = &req->base; | 
 | 523 | 	memset(p, 0, sizeof(struct req_progress)); | 
 | 524 | 	hw_bytes = req->nbytes + ctx->extra_bytes; | 
 | 525 | 	old_extra_bytes = ctx->extra_bytes; | 
 | 526 |  | 
 | 527 | 	if (unlikely(ctx->extra_bytes)) { | 
 | 528 | 		memcpy(cpg->sram + SRAM_DATA_IN_START, ctx->buffer, | 
 | 529 | 		       ctx->extra_bytes); | 
 | 530 | 		p->crypt_len = ctx->extra_bytes; | 
 | 531 | 	} | 
 | 532 |  | 
 | 533 | 	memcpy(cpg->sram + SRAM_HMAC_IV_IN, tfm_ctx->ivs, sizeof(tfm_ctx->ivs)); | 
 | 534 |  | 
 | 535 | 	if (unlikely(!ctx->first_hash)) { | 
 | 536 | 		writel(ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); | 
 | 537 | 		writel(ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); | 
 | 538 | 		writel(ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); | 
 | 539 | 		writel(ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); | 
 | 540 | 		writel(ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); | 
 | 541 | 	} | 
 | 542 |  | 
 | 543 | 	ctx->extra_bytes = hw_bytes % SHA1_BLOCK_SIZE; | 
 | 544 | 	if (ctx->extra_bytes != 0 | 
 | 545 | 	    && (!ctx->last_chunk || ctx->count > MAX_HW_HASH_SIZE)) | 
 | 546 | 		hw_bytes -= ctx->extra_bytes; | 
 | 547 | 	else | 
 | 548 | 		ctx->extra_bytes = 0; | 
 | 549 |  | 
 | 550 | 	num_sgs = count_sgs(req->src, req->nbytes); | 
 | 551 | 	sg_miter_start(&p->src_sg_it, req->src, num_sgs, SG_MITER_FROM_SG); | 
 | 552 |  | 
 | 553 | 	if (hw_bytes) { | 
 | 554 | 		p->hw_nbytes = hw_bytes; | 
 | 555 | 		p->complete = mv_hash_algo_completion; | 
 | 556 | 		p->process = mv_process_hash_current; | 
 | 557 |  | 
 | 558 | 		mv_process_hash_current(1); | 
 | 559 | 	} else { | 
 | 560 | 		copy_src_to_buf(p, ctx->buffer + old_extra_bytes, | 
 | 561 | 				ctx->extra_bytes - old_extra_bytes); | 
 | 562 | 		sg_miter_stop(&p->src_sg_it); | 
 | 563 | 		if (ctx->last_chunk) | 
 | 564 | 			rc = mv_hash_final_fallback(req); | 
 | 565 | 		else | 
 | 566 | 			rc = 0; | 
 | 567 | 		cpg->eng_st = ENGINE_IDLE; | 
 | 568 | 		local_bh_disable(); | 
 | 569 | 		req->base.complete(&req->base, rc); | 
 | 570 | 		local_bh_enable(); | 
 | 571 | 	} | 
 | 572 | } | 
 | 573 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 574 | static int queue_manag(void *data) | 
 | 575 | { | 
 | 576 | 	cpg->eng_st = ENGINE_IDLE; | 
 | 577 | 	do { | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 578 | 		struct crypto_async_request *async_req = NULL; | 
 | 579 | 		struct crypto_async_request *backlog; | 
 | 580 |  | 
 | 581 | 		__set_current_state(TASK_INTERRUPTIBLE); | 
 | 582 |  | 
 | 583 | 		if (cpg->eng_st == ENGINE_W_DEQUEUE) | 
 | 584 | 			dequeue_complete_req(); | 
 | 585 |  | 
 | 586 | 		spin_lock_irq(&cpg->lock); | 
 | 587 | 		if (cpg->eng_st == ENGINE_IDLE) { | 
 | 588 | 			backlog = crypto_get_backlog(&cpg->queue); | 
 | 589 | 			async_req = crypto_dequeue_request(&cpg->queue); | 
 | 590 | 			if (async_req) { | 
 | 591 | 				BUG_ON(cpg->eng_st != ENGINE_IDLE); | 
 | 592 | 				cpg->eng_st = ENGINE_BUSY; | 
 | 593 | 			} | 
 | 594 | 		} | 
 | 595 | 		spin_unlock_irq(&cpg->lock); | 
 | 596 |  | 
 | 597 | 		if (backlog) { | 
 | 598 | 			backlog->complete(backlog, -EINPROGRESS); | 
 | 599 | 			backlog = NULL; | 
 | 600 | 		} | 
 | 601 |  | 
 | 602 | 		if (async_req) { | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 603 | 			if (async_req->tfm->__crt_alg->cra_type != | 
 | 604 | 			    &crypto_ahash_type) { | 
 | 605 | 				struct ablkcipher_request *req = | 
 | 606 | 				    container_of(async_req, | 
 | 607 | 						 struct ablkcipher_request, | 
 | 608 | 						 base); | 
 | 609 | 				mv_start_new_crypt_req(req); | 
 | 610 | 			} else { | 
 | 611 | 				struct ahash_request *req = | 
 | 612 | 				    ahash_request_cast(async_req); | 
 | 613 | 				mv_start_new_hash_req(req); | 
 | 614 | 			} | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 615 | 			async_req = NULL; | 
 | 616 | 		} | 
 | 617 |  | 
 | 618 | 		schedule(); | 
 | 619 |  | 
 | 620 | 	} while (!kthread_should_stop()); | 
 | 621 | 	return 0; | 
 | 622 | } | 
 | 623 |  | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 624 | static int mv_handle_req(struct crypto_async_request *req) | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 625 | { | 
 | 626 | 	unsigned long flags; | 
 | 627 | 	int ret; | 
 | 628 |  | 
 | 629 | 	spin_lock_irqsave(&cpg->lock, flags); | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 630 | 	ret = crypto_enqueue_request(&cpg->queue, req); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 631 | 	spin_unlock_irqrestore(&cpg->lock, flags); | 
 | 632 | 	wake_up_process(cpg->queue_th); | 
 | 633 | 	return ret; | 
 | 634 | } | 
 | 635 |  | 
 | 636 | static int mv_enc_aes_ecb(struct ablkcipher_request *req) | 
 | 637 | { | 
 | 638 | 	struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | 
 | 639 |  | 
 | 640 | 	req_ctx->op = COP_AES_ECB; | 
 | 641 | 	req_ctx->decrypt = 0; | 
 | 642 |  | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 643 | 	return mv_handle_req(&req->base); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 644 | } | 
 | 645 |  | 
 | 646 | static int mv_dec_aes_ecb(struct ablkcipher_request *req) | 
 | 647 | { | 
 | 648 | 	struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | 
 | 649 | 	struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | 
 | 650 |  | 
 | 651 | 	req_ctx->op = COP_AES_ECB; | 
 | 652 | 	req_ctx->decrypt = 1; | 
 | 653 |  | 
 | 654 | 	compute_aes_dec_key(ctx); | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 655 | 	return mv_handle_req(&req->base); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 656 | } | 
 | 657 |  | 
 | 658 | static int mv_enc_aes_cbc(struct ablkcipher_request *req) | 
 | 659 | { | 
 | 660 | 	struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | 
 | 661 |  | 
 | 662 | 	req_ctx->op = COP_AES_CBC; | 
 | 663 | 	req_ctx->decrypt = 0; | 
 | 664 |  | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 665 | 	return mv_handle_req(&req->base); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 666 | } | 
 | 667 |  | 
 | 668 | static int mv_dec_aes_cbc(struct ablkcipher_request *req) | 
 | 669 | { | 
 | 670 | 	struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | 
 | 671 | 	struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | 
 | 672 |  | 
 | 673 | 	req_ctx->op = COP_AES_CBC; | 
 | 674 | 	req_ctx->decrypt = 1; | 
 | 675 |  | 
 | 676 | 	compute_aes_dec_key(ctx); | 
| Uri Simchoni | 3b61a90 | 2010-04-08 19:27:33 +0300 | [diff] [blame] | 677 | 	return mv_handle_req(&req->base); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 678 | } | 
 | 679 |  | 
 | 680 | static int mv_cra_init(struct crypto_tfm *tfm) | 
 | 681 | { | 
 | 682 | 	tfm->crt_ablkcipher.reqsize = sizeof(struct mv_req_ctx); | 
 | 683 | 	return 0; | 
 | 684 | } | 
 | 685 |  | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 686 | static void mv_init_hash_req_ctx(struct mv_req_hash_ctx *ctx, int op, | 
 | 687 | 				 int is_last, unsigned int req_len, | 
 | 688 | 				 int count_add) | 
 | 689 | { | 
 | 690 | 	memset(ctx, 0, sizeof(*ctx)); | 
 | 691 | 	ctx->op = op; | 
 | 692 | 	ctx->count = req_len; | 
 | 693 | 	ctx->first_hash = 1; | 
 | 694 | 	ctx->last_chunk = is_last; | 
 | 695 | 	ctx->count_add = count_add; | 
 | 696 | } | 
 | 697 |  | 
 | 698 | static void mv_update_hash_req_ctx(struct mv_req_hash_ctx *ctx, int is_last, | 
 | 699 | 				   unsigned req_len) | 
 | 700 | { | 
 | 701 | 	ctx->last_chunk = is_last; | 
 | 702 | 	ctx->count += req_len; | 
 | 703 | } | 
 | 704 |  | 
 | 705 | static int mv_hash_init(struct ahash_request *req) | 
 | 706 | { | 
 | 707 | 	const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); | 
 | 708 | 	mv_init_hash_req_ctx(ahash_request_ctx(req), tfm_ctx->op, 0, 0, | 
 | 709 | 			     tfm_ctx->count_add); | 
 | 710 | 	return 0; | 
 | 711 | } | 
 | 712 |  | 
 | 713 | static int mv_hash_update(struct ahash_request *req) | 
 | 714 | { | 
 | 715 | 	if (!req->nbytes) | 
 | 716 | 		return 0; | 
 | 717 |  | 
 | 718 | 	mv_update_hash_req_ctx(ahash_request_ctx(req), 0, req->nbytes); | 
 | 719 | 	return mv_handle_req(&req->base); | 
 | 720 | } | 
 | 721 |  | 
 | 722 | static int mv_hash_final(struct ahash_request *req) | 
 | 723 | { | 
 | 724 | 	struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); | 
 | 725 | 	/* dummy buffer of 4 bytes */ | 
 | 726 | 	sg_init_one(&ctx->dummysg, ctx->buffer, 4); | 
 | 727 | 	/* I think I'm allowed to do that... */ | 
 | 728 | 	ahash_request_set_crypt(req, &ctx->dummysg, req->result, 0); | 
 | 729 | 	mv_update_hash_req_ctx(ctx, 1, 0); | 
 | 730 | 	return mv_handle_req(&req->base); | 
 | 731 | } | 
 | 732 |  | 
 | 733 | static int mv_hash_finup(struct ahash_request *req) | 
 | 734 | { | 
 | 735 | 	if (!req->nbytes) | 
 | 736 | 		return mv_hash_final(req); | 
 | 737 |  | 
 | 738 | 	mv_update_hash_req_ctx(ahash_request_ctx(req), 1, req->nbytes); | 
 | 739 | 	return mv_handle_req(&req->base); | 
 | 740 | } | 
 | 741 |  | 
 | 742 | static int mv_hash_digest(struct ahash_request *req) | 
 | 743 | { | 
 | 744 | 	const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); | 
 | 745 | 	mv_init_hash_req_ctx(ahash_request_ctx(req), tfm_ctx->op, 1, | 
 | 746 | 			     req->nbytes, tfm_ctx->count_add); | 
 | 747 | 	return mv_handle_req(&req->base); | 
 | 748 | } | 
 | 749 |  | 
 | 750 | static void mv_hash_init_ivs(struct mv_tfm_hash_ctx *ctx, const void *istate, | 
 | 751 | 			     const void *ostate) | 
 | 752 | { | 
 | 753 | 	const struct sha1_state *isha1_state = istate, *osha1_state = ostate; | 
 | 754 | 	int i; | 
 | 755 | 	for (i = 0; i < 5; i++) { | 
 | 756 | 		ctx->ivs[i] = cpu_to_be32(isha1_state->state[i]); | 
 | 757 | 		ctx->ivs[i + 5] = cpu_to_be32(osha1_state->state[i]); | 
 | 758 | 	} | 
 | 759 | } | 
 | 760 |  | 
 | 761 | static int mv_hash_setkey(struct crypto_ahash *tfm, const u8 * key, | 
 | 762 | 			  unsigned int keylen) | 
 | 763 | { | 
 | 764 | 	int rc; | 
 | 765 | 	struct mv_tfm_hash_ctx *ctx = crypto_tfm_ctx(&tfm->base); | 
 | 766 | 	int bs, ds, ss; | 
 | 767 |  | 
 | 768 | 	if (!ctx->base_hash) | 
 | 769 | 		return 0; | 
 | 770 |  | 
 | 771 | 	rc = crypto_shash_setkey(ctx->fallback, key, keylen); | 
 | 772 | 	if (rc) | 
 | 773 | 		return rc; | 
 | 774 |  | 
 | 775 | 	/* Can't see a way to extract the ipad/opad from the fallback tfm | 
 | 776 | 	   so I'm basically copying code from the hmac module */ | 
 | 777 | 	bs = crypto_shash_blocksize(ctx->base_hash); | 
 | 778 | 	ds = crypto_shash_digestsize(ctx->base_hash); | 
 | 779 | 	ss = crypto_shash_statesize(ctx->base_hash); | 
 | 780 |  | 
 | 781 | 	{ | 
 | 782 | 		struct { | 
 | 783 | 			struct shash_desc shash; | 
 | 784 | 			char ctx[crypto_shash_descsize(ctx->base_hash)]; | 
 | 785 | 		} desc; | 
 | 786 | 		unsigned int i; | 
 | 787 | 		char ipad[ss]; | 
 | 788 | 		char opad[ss]; | 
 | 789 |  | 
 | 790 | 		desc.shash.tfm = ctx->base_hash; | 
 | 791 | 		desc.shash.flags = crypto_shash_get_flags(ctx->base_hash) & | 
 | 792 | 		    CRYPTO_TFM_REQ_MAY_SLEEP; | 
 | 793 |  | 
 | 794 | 		if (keylen > bs) { | 
 | 795 | 			int err; | 
 | 796 |  | 
 | 797 | 			err = | 
 | 798 | 			    crypto_shash_digest(&desc.shash, key, keylen, ipad); | 
 | 799 | 			if (err) | 
 | 800 | 				return err; | 
 | 801 |  | 
 | 802 | 			keylen = ds; | 
 | 803 | 		} else | 
 | 804 | 			memcpy(ipad, key, keylen); | 
 | 805 |  | 
 | 806 | 		memset(ipad + keylen, 0, bs - keylen); | 
 | 807 | 		memcpy(opad, ipad, bs); | 
 | 808 |  | 
 | 809 | 		for (i = 0; i < bs; i++) { | 
 | 810 | 			ipad[i] ^= 0x36; | 
 | 811 | 			opad[i] ^= 0x5c; | 
 | 812 | 		} | 
 | 813 |  | 
 | 814 | 		rc = crypto_shash_init(&desc.shash) ? : | 
 | 815 | 		    crypto_shash_update(&desc.shash, ipad, bs) ? : | 
 | 816 | 		    crypto_shash_export(&desc.shash, ipad) ? : | 
 | 817 | 		    crypto_shash_init(&desc.shash) ? : | 
 | 818 | 		    crypto_shash_update(&desc.shash, opad, bs) ? : | 
 | 819 | 		    crypto_shash_export(&desc.shash, opad); | 
 | 820 |  | 
 | 821 | 		if (rc == 0) | 
 | 822 | 			mv_hash_init_ivs(ctx, ipad, opad); | 
 | 823 |  | 
 | 824 | 		return rc; | 
 | 825 | 	} | 
 | 826 | } | 
 | 827 |  | 
 | 828 | static int mv_cra_hash_init(struct crypto_tfm *tfm, const char *base_hash_name, | 
 | 829 | 			    enum hash_op op, int count_add) | 
 | 830 | { | 
 | 831 | 	const char *fallback_driver_name = tfm->__crt_alg->cra_name; | 
 | 832 | 	struct mv_tfm_hash_ctx *ctx = crypto_tfm_ctx(tfm); | 
 | 833 | 	struct crypto_shash *fallback_tfm = NULL; | 
 | 834 | 	struct crypto_shash *base_hash = NULL; | 
 | 835 | 	int err = -ENOMEM; | 
 | 836 |  | 
 | 837 | 	ctx->op = op; | 
 | 838 | 	ctx->count_add = count_add; | 
 | 839 |  | 
 | 840 | 	/* Allocate a fallback and abort if it failed. */ | 
 | 841 | 	fallback_tfm = crypto_alloc_shash(fallback_driver_name, 0, | 
 | 842 | 					  CRYPTO_ALG_NEED_FALLBACK); | 
 | 843 | 	if (IS_ERR(fallback_tfm)) { | 
 | 844 | 		printk(KERN_WARNING MV_CESA | 
 | 845 | 		       "Fallback driver '%s' could not be loaded!\n", | 
 | 846 | 		       fallback_driver_name); | 
 | 847 | 		err = PTR_ERR(fallback_tfm); | 
 | 848 | 		goto out; | 
 | 849 | 	} | 
 | 850 | 	ctx->fallback = fallback_tfm; | 
 | 851 |  | 
 | 852 | 	if (base_hash_name) { | 
 | 853 | 		/* Allocate a hash to compute the ipad/opad of hmac. */ | 
 | 854 | 		base_hash = crypto_alloc_shash(base_hash_name, 0, | 
 | 855 | 					       CRYPTO_ALG_NEED_FALLBACK); | 
 | 856 | 		if (IS_ERR(base_hash)) { | 
 | 857 | 			printk(KERN_WARNING MV_CESA | 
 | 858 | 			       "Base driver '%s' could not be loaded!\n", | 
 | 859 | 			       base_hash_name); | 
| Roel Kluin | 41f2977 | 2011-01-04 15:37:16 +1100 | [diff] [blame] | 860 | 			err = PTR_ERR(base_hash); | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 861 | 			goto err_bad_base; | 
 | 862 | 		} | 
 | 863 | 	} | 
 | 864 | 	ctx->base_hash = base_hash; | 
 | 865 |  | 
 | 866 | 	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), | 
 | 867 | 				 sizeof(struct mv_req_hash_ctx) + | 
 | 868 | 				 crypto_shash_descsize(ctx->fallback)); | 
 | 869 | 	return 0; | 
 | 870 | err_bad_base: | 
 | 871 | 	crypto_free_shash(fallback_tfm); | 
 | 872 | out: | 
 | 873 | 	return err; | 
 | 874 | } | 
 | 875 |  | 
 | 876 | static void mv_cra_hash_exit(struct crypto_tfm *tfm) | 
 | 877 | { | 
 | 878 | 	struct mv_tfm_hash_ctx *ctx = crypto_tfm_ctx(tfm); | 
 | 879 |  | 
 | 880 | 	crypto_free_shash(ctx->fallback); | 
 | 881 | 	if (ctx->base_hash) | 
 | 882 | 		crypto_free_shash(ctx->base_hash); | 
 | 883 | } | 
 | 884 |  | 
 | 885 | static int mv_cra_hash_sha1_init(struct crypto_tfm *tfm) | 
 | 886 | { | 
 | 887 | 	return mv_cra_hash_init(tfm, NULL, COP_SHA1, 0); | 
 | 888 | } | 
 | 889 |  | 
 | 890 | static int mv_cra_hash_hmac_sha1_init(struct crypto_tfm *tfm) | 
 | 891 | { | 
 | 892 | 	return mv_cra_hash_init(tfm, "sha1", COP_HMAC_SHA1, SHA1_BLOCK_SIZE); | 
 | 893 | } | 
 | 894 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 895 | irqreturn_t crypto_int(int irq, void *priv) | 
 | 896 | { | 
 | 897 | 	u32 val; | 
 | 898 |  | 
 | 899 | 	val = readl(cpg->reg + SEC_ACCEL_INT_STATUS); | 
 | 900 | 	if (!(val & SEC_INT_ACCEL0_DONE)) | 
 | 901 | 		return IRQ_NONE; | 
 | 902 |  | 
 | 903 | 	val &= ~SEC_INT_ACCEL0_DONE; | 
 | 904 | 	writel(val, cpg->reg + FPGA_INT_STATUS); | 
 | 905 | 	writel(val, cpg->reg + SEC_ACCEL_INT_STATUS); | 
 | 906 | 	BUG_ON(cpg->eng_st != ENGINE_BUSY); | 
 | 907 | 	cpg->eng_st = ENGINE_W_DEQUEUE; | 
 | 908 | 	wake_up_process(cpg->queue_th); | 
 | 909 | 	return IRQ_HANDLED; | 
 | 910 | } | 
 | 911 |  | 
 | 912 | struct crypto_alg mv_aes_alg_ecb = { | 
 | 913 | 	.cra_name		= "ecb(aes)", | 
 | 914 | 	.cra_driver_name	= "mv-ecb-aes", | 
 | 915 | 	.cra_priority	= 300, | 
 | 916 | 	.cra_flags	= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, | 
 | 917 | 	.cra_blocksize	= 16, | 
 | 918 | 	.cra_ctxsize	= sizeof(struct mv_ctx), | 
 | 919 | 	.cra_alignmask	= 0, | 
 | 920 | 	.cra_type	= &crypto_ablkcipher_type, | 
 | 921 | 	.cra_module	= THIS_MODULE, | 
 | 922 | 	.cra_init	= mv_cra_init, | 
 | 923 | 	.cra_u		= { | 
 | 924 | 		.ablkcipher = { | 
 | 925 | 			.min_keysize	=	AES_MIN_KEY_SIZE, | 
 | 926 | 			.max_keysize	=	AES_MAX_KEY_SIZE, | 
 | 927 | 			.setkey		=	mv_setkey_aes, | 
 | 928 | 			.encrypt	=	mv_enc_aes_ecb, | 
 | 929 | 			.decrypt	=	mv_dec_aes_ecb, | 
 | 930 | 		}, | 
 | 931 | 	}, | 
 | 932 | }; | 
 | 933 |  | 
 | 934 | struct crypto_alg mv_aes_alg_cbc = { | 
 | 935 | 	.cra_name		= "cbc(aes)", | 
 | 936 | 	.cra_driver_name	= "mv-cbc-aes", | 
 | 937 | 	.cra_priority	= 300, | 
 | 938 | 	.cra_flags	= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, | 
 | 939 | 	.cra_blocksize	= AES_BLOCK_SIZE, | 
 | 940 | 	.cra_ctxsize	= sizeof(struct mv_ctx), | 
 | 941 | 	.cra_alignmask	= 0, | 
 | 942 | 	.cra_type	= &crypto_ablkcipher_type, | 
 | 943 | 	.cra_module	= THIS_MODULE, | 
 | 944 | 	.cra_init	= mv_cra_init, | 
 | 945 | 	.cra_u		= { | 
 | 946 | 		.ablkcipher = { | 
 | 947 | 			.ivsize		=	AES_BLOCK_SIZE, | 
 | 948 | 			.min_keysize	=	AES_MIN_KEY_SIZE, | 
 | 949 | 			.max_keysize	=	AES_MAX_KEY_SIZE, | 
 | 950 | 			.setkey		=	mv_setkey_aes, | 
 | 951 | 			.encrypt	=	mv_enc_aes_cbc, | 
 | 952 | 			.decrypt	=	mv_dec_aes_cbc, | 
 | 953 | 		}, | 
 | 954 | 	}, | 
 | 955 | }; | 
 | 956 |  | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 957 | struct ahash_alg mv_sha1_alg = { | 
 | 958 | 	.init = mv_hash_init, | 
 | 959 | 	.update = mv_hash_update, | 
 | 960 | 	.final = mv_hash_final, | 
 | 961 | 	.finup = mv_hash_finup, | 
 | 962 | 	.digest = mv_hash_digest, | 
 | 963 | 	.halg = { | 
 | 964 | 		 .digestsize = SHA1_DIGEST_SIZE, | 
 | 965 | 		 .base = { | 
 | 966 | 			  .cra_name = "sha1", | 
 | 967 | 			  .cra_driver_name = "mv-sha1", | 
 | 968 | 			  .cra_priority = 300, | 
 | 969 | 			  .cra_flags = | 
 | 970 | 			  CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, | 
 | 971 | 			  .cra_blocksize = SHA1_BLOCK_SIZE, | 
 | 972 | 			  .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx), | 
 | 973 | 			  .cra_init = mv_cra_hash_sha1_init, | 
 | 974 | 			  .cra_exit = mv_cra_hash_exit, | 
 | 975 | 			  .cra_module = THIS_MODULE, | 
 | 976 | 			  } | 
 | 977 | 		 } | 
 | 978 | }; | 
 | 979 |  | 
 | 980 | struct ahash_alg mv_hmac_sha1_alg = { | 
 | 981 | 	.init = mv_hash_init, | 
 | 982 | 	.update = mv_hash_update, | 
 | 983 | 	.final = mv_hash_final, | 
 | 984 | 	.finup = mv_hash_finup, | 
 | 985 | 	.digest = mv_hash_digest, | 
 | 986 | 	.setkey = mv_hash_setkey, | 
 | 987 | 	.halg = { | 
 | 988 | 		 .digestsize = SHA1_DIGEST_SIZE, | 
 | 989 | 		 .base = { | 
 | 990 | 			  .cra_name = "hmac(sha1)", | 
 | 991 | 			  .cra_driver_name = "mv-hmac-sha1", | 
 | 992 | 			  .cra_priority = 300, | 
 | 993 | 			  .cra_flags = | 
 | 994 | 			  CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, | 
 | 995 | 			  .cra_blocksize = SHA1_BLOCK_SIZE, | 
 | 996 | 			  .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx), | 
 | 997 | 			  .cra_init = mv_cra_hash_hmac_sha1_init, | 
 | 998 | 			  .cra_exit = mv_cra_hash_exit, | 
 | 999 | 			  .cra_module = THIS_MODULE, | 
 | 1000 | 			  } | 
 | 1001 | 		 } | 
 | 1002 | }; | 
 | 1003 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1004 | static int mv_probe(struct platform_device *pdev) | 
 | 1005 | { | 
 | 1006 | 	struct crypto_priv *cp; | 
 | 1007 | 	struct resource *res; | 
 | 1008 | 	int irq; | 
 | 1009 | 	int ret; | 
 | 1010 |  | 
 | 1011 | 	if (cpg) { | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 1012 | 		printk(KERN_ERR MV_CESA "Second crypto dev?\n"); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1013 | 		return -EEXIST; | 
 | 1014 | 	} | 
 | 1015 |  | 
 | 1016 | 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | 
 | 1017 | 	if (!res) | 
 | 1018 | 		return -ENXIO; | 
 | 1019 |  | 
 | 1020 | 	cp = kzalloc(sizeof(*cp), GFP_KERNEL); | 
 | 1021 | 	if (!cp) | 
 | 1022 | 		return -ENOMEM; | 
 | 1023 |  | 
 | 1024 | 	spin_lock_init(&cp->lock); | 
 | 1025 | 	crypto_init_queue(&cp->queue, 50); | 
| Tobias Klauser | 5bdd5de | 2010-05-14 14:58:05 +1000 | [diff] [blame] | 1026 | 	cp->reg = ioremap(res->start, resource_size(res)); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1027 | 	if (!cp->reg) { | 
 | 1028 | 		ret = -ENOMEM; | 
 | 1029 | 		goto err; | 
 | 1030 | 	} | 
 | 1031 |  | 
 | 1032 | 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); | 
 | 1033 | 	if (!res) { | 
 | 1034 | 		ret = -ENXIO; | 
 | 1035 | 		goto err_unmap_reg; | 
 | 1036 | 	} | 
| Tobias Klauser | 5bdd5de | 2010-05-14 14:58:05 +1000 | [diff] [blame] | 1037 | 	cp->sram_size = resource_size(res); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1038 | 	cp->max_req_size = cp->sram_size - SRAM_CFG_SPACE; | 
 | 1039 | 	cp->sram = ioremap(res->start, cp->sram_size); | 
 | 1040 | 	if (!cp->sram) { | 
 | 1041 | 		ret = -ENOMEM; | 
 | 1042 | 		goto err_unmap_reg; | 
 | 1043 | 	} | 
 | 1044 |  | 
 | 1045 | 	irq = platform_get_irq(pdev, 0); | 
 | 1046 | 	if (irq < 0 || irq == NO_IRQ) { | 
 | 1047 | 		ret = irq; | 
 | 1048 | 		goto err_unmap_sram; | 
 | 1049 | 	} | 
 | 1050 | 	cp->irq = irq; | 
 | 1051 |  | 
 | 1052 | 	platform_set_drvdata(pdev, cp); | 
 | 1053 | 	cpg = cp; | 
 | 1054 |  | 
 | 1055 | 	cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto"); | 
 | 1056 | 	if (IS_ERR(cp->queue_th)) { | 
 | 1057 | 		ret = PTR_ERR(cp->queue_th); | 
| Dan Carpenter | 7cc2835 | 2010-05-26 10:45:22 +1000 | [diff] [blame] | 1058 | 		goto err_unmap_sram; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1059 | 	} | 
 | 1060 |  | 
 | 1061 | 	ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev), | 
 | 1062 | 			cp); | 
 | 1063 | 	if (ret) | 
| Dan Carpenter | 7cc2835 | 2010-05-26 10:45:22 +1000 | [diff] [blame] | 1064 | 		goto err_thread; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1065 |  | 
 | 1066 | 	writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); | 
 | 1067 | 	writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); | 
 | 1068 |  | 
 | 1069 | 	ret = crypto_register_alg(&mv_aes_alg_ecb); | 
 | 1070 | 	if (ret) | 
| Dan Carpenter | 7cc2835 | 2010-05-26 10:45:22 +1000 | [diff] [blame] | 1071 | 		goto err_irq; | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1072 |  | 
 | 1073 | 	ret = crypto_register_alg(&mv_aes_alg_cbc); | 
 | 1074 | 	if (ret) | 
 | 1075 | 		goto err_unreg_ecb; | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 1076 |  | 
 | 1077 | 	ret = crypto_register_ahash(&mv_sha1_alg); | 
 | 1078 | 	if (ret == 0) | 
 | 1079 | 		cpg->has_sha1 = 1; | 
 | 1080 | 	else | 
 | 1081 | 		printk(KERN_WARNING MV_CESA "Could not register sha1 driver\n"); | 
 | 1082 |  | 
 | 1083 | 	ret = crypto_register_ahash(&mv_hmac_sha1_alg); | 
 | 1084 | 	if (ret == 0) { | 
 | 1085 | 		cpg->has_hmac_sha1 = 1; | 
 | 1086 | 	} else { | 
 | 1087 | 		printk(KERN_WARNING MV_CESA | 
 | 1088 | 		       "Could not register hmac-sha1 driver\n"); | 
 | 1089 | 	} | 
 | 1090 |  | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1091 | 	return 0; | 
 | 1092 | err_unreg_ecb: | 
 | 1093 | 	crypto_unregister_alg(&mv_aes_alg_ecb); | 
| Dan Carpenter | 7cc2835 | 2010-05-26 10:45:22 +1000 | [diff] [blame] | 1094 | err_irq: | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1095 | 	free_irq(irq, cp); | 
| Dan Carpenter | 7cc2835 | 2010-05-26 10:45:22 +1000 | [diff] [blame] | 1096 | err_thread: | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1097 | 	kthread_stop(cp->queue_th); | 
 | 1098 | err_unmap_sram: | 
 | 1099 | 	iounmap(cp->sram); | 
 | 1100 | err_unmap_reg: | 
 | 1101 | 	iounmap(cp->reg); | 
 | 1102 | err: | 
 | 1103 | 	kfree(cp); | 
 | 1104 | 	cpg = NULL; | 
 | 1105 | 	platform_set_drvdata(pdev, NULL); | 
 | 1106 | 	return ret; | 
 | 1107 | } | 
 | 1108 |  | 
 | 1109 | static int mv_remove(struct platform_device *pdev) | 
 | 1110 | { | 
 | 1111 | 	struct crypto_priv *cp = platform_get_drvdata(pdev); | 
 | 1112 |  | 
 | 1113 | 	crypto_unregister_alg(&mv_aes_alg_ecb); | 
 | 1114 | 	crypto_unregister_alg(&mv_aes_alg_cbc); | 
| Uri Simchoni | 750052d | 2010-04-08 19:34:55 +0300 | [diff] [blame] | 1115 | 	if (cp->has_sha1) | 
 | 1116 | 		crypto_unregister_ahash(&mv_sha1_alg); | 
 | 1117 | 	if (cp->has_hmac_sha1) | 
 | 1118 | 		crypto_unregister_ahash(&mv_hmac_sha1_alg); | 
| Sebastian Andrzej Siewior | 85a7f0ac | 2009-08-10 12:50:03 +1000 | [diff] [blame] | 1119 | 	kthread_stop(cp->queue_th); | 
 | 1120 | 	free_irq(cp->irq, cp); | 
 | 1121 | 	memset(cp->sram, 0, cp->sram_size); | 
 | 1122 | 	iounmap(cp->sram); | 
 | 1123 | 	iounmap(cp->reg); | 
 | 1124 | 	kfree(cp); | 
 | 1125 | 	cpg = NULL; | 
 | 1126 | 	return 0; | 
 | 1127 | } | 
 | 1128 |  | 
 | 1129 | static struct platform_driver marvell_crypto = { | 
 | 1130 | 	.probe		= mv_probe, | 
 | 1131 | 	.remove		= mv_remove, | 
 | 1132 | 	.driver		= { | 
 | 1133 | 		.owner	= THIS_MODULE, | 
 | 1134 | 		.name	= "mv_crypto", | 
 | 1135 | 	}, | 
 | 1136 | }; | 
 | 1137 | MODULE_ALIAS("platform:mv_crypto"); | 
 | 1138 |  | 
 | 1139 | static int __init mv_crypto_init(void) | 
 | 1140 | { | 
 | 1141 | 	return platform_driver_register(&marvell_crypto); | 
 | 1142 | } | 
 | 1143 | module_init(mv_crypto_init); | 
 | 1144 |  | 
 | 1145 | static void __exit mv_crypto_exit(void) | 
 | 1146 | { | 
 | 1147 | 	platform_driver_unregister(&marvell_crypto); | 
 | 1148 | } | 
 | 1149 | module_exit(mv_crypto_exit); | 
 | 1150 |  | 
 | 1151 | MODULE_AUTHOR("Sebastian Andrzej Siewior <sebastian@breakpoint.cc>"); | 
 | 1152 | MODULE_DESCRIPTION("Support for Marvell's cryptographic engine"); | 
 | 1153 | MODULE_LICENSE("GPL"); |