• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/crypto/
1/*
2 * Cryptographic API.
3 *
4 * Support for OMAP SHA1/MD5 HW acceleration.
5 *
6 * Copyright (c) 2010 Nokia Corporation
7 * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as published
11 * by the Free Software Foundation.
12 *
13 * Some ideas are from old omap-sha1-md5.c driver.
14 */
15
16#define pr_fmt(fmt) "%s: " fmt, __func__
17
18#include <linux/err.h>
19#include <linux/device.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/errno.h>
23#include <linux/interrupt.h>
24#include <linux/kernel.h>
25#include <linux/clk.h>
26#include <linux/irq.h>
27#include <linux/io.h>
28#include <linux/platform_device.h>
29#include <linux/scatterlist.h>
30#include <linux/dma-mapping.h>
31#include <linux/delay.h>
32#include <linux/crypto.h>
33#include <linux/cryptohash.h>
34#include <crypto/scatterwalk.h>
35#include <crypto/algapi.h>
36#include <crypto/sha.h>
37#include <crypto/hash.h>
38#include <crypto/internal/hash.h>
39
40#include <plat/cpu.h>
41#include <plat/dma.h>
42#include <mach/irqs.h>
43
44#define SHA_REG_DIGEST(x)		(0x00 + ((x) * 0x04))
45#define SHA_REG_DIN(x)			(0x1C + ((x) * 0x04))
46
47#define SHA1_MD5_BLOCK_SIZE		SHA1_BLOCK_SIZE
48#define MD5_DIGEST_SIZE			16
49
50#define SHA_REG_DIGCNT			0x14
51
52#define SHA_REG_CTRL			0x18
53#define SHA_REG_CTRL_LENGTH		(0xFFFFFFFF << 5)
54#define SHA_REG_CTRL_CLOSE_HASH		(1 << 4)
55#define SHA_REG_CTRL_ALGO_CONST		(1 << 3)
56#define SHA_REG_CTRL_ALGO		(1 << 2)
57#define SHA_REG_CTRL_INPUT_READY	(1 << 1)
58#define SHA_REG_CTRL_OUTPUT_READY	(1 << 0)
59
60#define SHA_REG_REV			0x5C
61#define SHA_REG_REV_MAJOR		0xF0
62#define SHA_REG_REV_MINOR		0x0F
63
64#define SHA_REG_MASK			0x60
65#define SHA_REG_MASK_DMA_EN		(1 << 3)
66#define SHA_REG_MASK_IT_EN		(1 << 2)
67#define SHA_REG_MASK_SOFTRESET		(1 << 1)
68#define SHA_REG_AUTOIDLE		(1 << 0)
69
70#define SHA_REG_SYSSTATUS		0x64
71#define SHA_REG_SYSSTATUS_RESETDONE	(1 << 0)
72
73#define DEFAULT_TIMEOUT_INTERVAL	HZ
74
75#define FLAGS_FIRST		0x0001
76#define FLAGS_FINUP		0x0002
77#define FLAGS_FINAL		0x0004
78#define FLAGS_FAST		0x0008
79#define FLAGS_SHA1		0x0010
80#define FLAGS_DMA_ACTIVE	0x0020
81#define FLAGS_OUTPUT_READY	0x0040
82#define FLAGS_CLEAN		0x0080
83#define FLAGS_INIT		0x0100
84#define FLAGS_CPU		0x0200
85#define FLAGS_HMAC		0x0400
86
87/* 3rd byte */
88#define FLAGS_BUSY		16
89
90#define OP_UPDATE	1
91#define OP_FINAL	2
92
93struct omap_sham_dev;
94
95struct omap_sham_reqctx {
96	struct omap_sham_dev	*dd;
97	unsigned long		flags;
98	unsigned long		op;
99
100	size_t			digcnt;
101	u8			*buffer;
102	size_t			bufcnt;
103	size_t			buflen;
104	dma_addr_t		dma_addr;
105
106	/* walk state */
107	struct scatterlist	*sg;
108	unsigned int		offset;	/* offset in current sg */
109	unsigned int		total;	/* total request */
110};
111
112struct omap_sham_hmac_ctx {
113	struct crypto_shash	*shash;
114	u8			ipad[SHA1_MD5_BLOCK_SIZE];
115	u8			opad[SHA1_MD5_BLOCK_SIZE];
116};
117
118struct omap_sham_ctx {
119	struct omap_sham_dev	*dd;
120
121	unsigned long		flags;
122
123	/* fallback stuff */
124	struct crypto_shash	*fallback;
125
126	struct omap_sham_hmac_ctx base[0];
127};
128
129#define OMAP_SHAM_QUEUE_LENGTH	1
130
131struct omap_sham_dev {
132	struct list_head	list;
133	unsigned long		phys_base;
134	struct device		*dev;
135	void __iomem		*io_base;
136	int			irq;
137	struct clk		*iclk;
138	spinlock_t		lock;
139	int			dma;
140	int			dma_lch;
141	struct tasklet_struct	done_task;
142	struct tasklet_struct	queue_task;
143
144	unsigned long		flags;
145	struct crypto_queue	queue;
146	struct ahash_request	*req;
147};
148
149struct omap_sham_drv {
150	struct list_head	dev_list;
151	spinlock_t		lock;
152	unsigned long		flags;
153};
154
155static struct omap_sham_drv sham = {
156	.dev_list = LIST_HEAD_INIT(sham.dev_list),
157	.lock = __SPIN_LOCK_UNLOCKED(sham.lock),
158};
159
160static inline u32 omap_sham_read(struct omap_sham_dev *dd, u32 offset)
161{
162	return __raw_readl(dd->io_base + offset);
163}
164
165static inline void omap_sham_write(struct omap_sham_dev *dd,
166					u32 offset, u32 value)
167{
168	__raw_writel(value, dd->io_base + offset);
169}
170
171static inline void omap_sham_write_mask(struct omap_sham_dev *dd, u32 address,
172					u32 value, u32 mask)
173{
174	u32 val;
175
176	val = omap_sham_read(dd, address);
177	val &= ~mask;
178	val |= value;
179	omap_sham_write(dd, address, val);
180}
181
182static inline int omap_sham_wait(struct omap_sham_dev *dd, u32 offset, u32 bit)
183{
184	unsigned long timeout = jiffies + DEFAULT_TIMEOUT_INTERVAL;
185
186	while (!(omap_sham_read(dd, offset) & bit)) {
187		if (time_is_before_jiffies(timeout))
188			return -ETIMEDOUT;
189	}
190
191	return 0;
192}
193
194static void omap_sham_copy_hash(struct ahash_request *req, int out)
195{
196	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
197	u32 *hash = (u32 *)req->result;
198	int i;
199
200	if (likely(ctx->flags & FLAGS_SHA1)) {
201		/* SHA1 results are in big endian */
202		for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
203			if (out)
204				hash[i] = be32_to_cpu(omap_sham_read(ctx->dd,
205							SHA_REG_DIGEST(i)));
206			else
207				omap_sham_write(ctx->dd, SHA_REG_DIGEST(i),
208							cpu_to_be32(hash[i]));
209	} else {
210		/* MD5 results are in little endian */
211		for (i = 0; i < MD5_DIGEST_SIZE / sizeof(u32); i++)
212			if (out)
213				hash[i] = le32_to_cpu(omap_sham_read(ctx->dd,
214							SHA_REG_DIGEST(i)));
215			else
216				omap_sham_write(ctx->dd, SHA_REG_DIGEST(i),
217							cpu_to_le32(hash[i]));
218	}
219}
220
221static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
222				 int final, int dma)
223{
224	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
225	u32 val = length << 5, mask;
226
227	if (unlikely(!ctx->digcnt)) {
228
229		clk_enable(dd->iclk);
230
231		if (!(dd->flags & FLAGS_INIT)) {
232			omap_sham_write_mask(dd, SHA_REG_MASK,
233				SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET);
234
235			if (omap_sham_wait(dd, SHA_REG_SYSSTATUS,
236						SHA_REG_SYSSTATUS_RESETDONE))
237				return -ETIMEDOUT;
238
239			dd->flags |= FLAGS_INIT;
240		}
241	} else {
242		omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt);
243	}
244
245	omap_sham_write_mask(dd, SHA_REG_MASK,
246		SHA_REG_MASK_IT_EN | (dma ? SHA_REG_MASK_DMA_EN : 0),
247		SHA_REG_MASK_IT_EN | SHA_REG_MASK_DMA_EN);
248	/*
249	 * Setting ALGO_CONST only for the first iteration
250	 * and CLOSE_HASH only for the last one.
251	 */
252	if (ctx->flags & FLAGS_SHA1)
253		val |= SHA_REG_CTRL_ALGO;
254	if (!ctx->digcnt)
255		val |= SHA_REG_CTRL_ALGO_CONST;
256	if (final)
257		val |= SHA_REG_CTRL_CLOSE_HASH;
258
259	mask = SHA_REG_CTRL_ALGO_CONST | SHA_REG_CTRL_CLOSE_HASH |
260			SHA_REG_CTRL_ALGO | SHA_REG_CTRL_LENGTH;
261
262	omap_sham_write_mask(dd, SHA_REG_CTRL, val, mask);
263
264	return 0;
265}
266
267static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
268			      size_t length, int final)
269{
270	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
271	int err, count, len32;
272	const u32 *buffer = (const u32 *)buf;
273
274	dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
275						ctx->digcnt, length, final);
276
277	err = omap_sham_write_ctrl(dd, length, final, 0);
278	if (err)
279		return err;
280
281	if (omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY))
282		return -ETIMEDOUT;
283
284	ctx->digcnt += length;
285
286	if (final)
287		ctx->flags |= FLAGS_FINAL; /* catch last interrupt */
288
289	len32 = DIV_ROUND_UP(length, sizeof(u32));
290
291	for (count = 0; count < len32; count++)
292		omap_sham_write(dd, SHA_REG_DIN(count), buffer[count]);
293
294	return -EINPROGRESS;
295}
296
297static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
298			      size_t length, int final)
299{
300	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
301	int err, len32;
302
303	dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n",
304						ctx->digcnt, length, final);
305
306	/* flush cache entries related to our page */
307	if (dma_addr == ctx->dma_addr)
308		dma_sync_single_for_device(dd->dev, dma_addr, length,
309					   DMA_TO_DEVICE);
310
311	len32 = DIV_ROUND_UP(length, sizeof(u32));
312
313	omap_set_dma_transfer_params(dd->dma_lch, OMAP_DMA_DATA_TYPE_S32, len32,
314			1, OMAP_DMA_SYNC_PACKET, dd->dma, OMAP_DMA_DST_SYNC);
315
316	omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC,
317				dma_addr, 0, 0);
318
319	err = omap_sham_write_ctrl(dd, length, final, 1);
320	if (err)
321		return err;
322
323	ctx->digcnt += length;
324
325	if (final)
326		ctx->flags |= FLAGS_FINAL; /* catch last interrupt */
327
328	dd->flags |= FLAGS_DMA_ACTIVE;
329
330	omap_start_dma(dd->dma_lch);
331
332	return -EINPROGRESS;
333}
334
335static size_t omap_sham_append_buffer(struct omap_sham_reqctx *ctx,
336				const u8 *data, size_t length)
337{
338	size_t count = min(length, ctx->buflen - ctx->bufcnt);
339
340	count = min(count, ctx->total);
341	if (count <= 0)
342		return 0;
343	memcpy(ctx->buffer + ctx->bufcnt, data, count);
344	ctx->bufcnt += count;
345
346	return count;
347}
348
349static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx)
350{
351	size_t count;
352
353	while (ctx->sg) {
354		count = omap_sham_append_buffer(ctx,
355				sg_virt(ctx->sg) + ctx->offset,
356				ctx->sg->length - ctx->offset);
357		if (!count)
358			break;
359		ctx->offset += count;
360		ctx->total -= count;
361		if (ctx->offset == ctx->sg->length) {
362			ctx->sg = sg_next(ctx->sg);
363			if (ctx->sg)
364				ctx->offset = 0;
365			else
366				ctx->total = 0;
367		}
368	}
369
370	return 0;
371}
372
373static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
374{
375	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
376	unsigned int final;
377	size_t count;
378
379	if (!ctx->total)
380		return 0;
381
382	omap_sham_append_sg(ctx);
383
384	final = (ctx->flags & FLAGS_FINUP) && !ctx->total;
385
386	dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
387					 ctx->bufcnt, ctx->digcnt, final);
388
389	if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
390		count = ctx->bufcnt;
391		ctx->bufcnt = 0;
392		return omap_sham_xmit_dma(dd, ctx->dma_addr, count, final);
393	}
394
395	return 0;
396}
397
398static int omap_sham_update_dma_fast(struct omap_sham_dev *dd)
399{
400	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
401	unsigned int length;
402
403	ctx->flags |= FLAGS_FAST;
404
405	length = min(ctx->total, sg_dma_len(ctx->sg));
406	ctx->total = length;
407
408	if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
409		dev_err(dd->dev, "dma_map_sg  error\n");
410		return -EINVAL;
411	}
412
413	ctx->total -= length;
414
415	return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1);
416}
417
418static int omap_sham_update_cpu(struct omap_sham_dev *dd)
419{
420	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
421	int bufcnt;
422
423	omap_sham_append_sg(ctx);
424	bufcnt = ctx->bufcnt;
425	ctx->bufcnt = 0;
426
427	return omap_sham_xmit_cpu(dd, ctx->buffer, bufcnt, 1);
428}
429
430static int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
431{
432	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
433
434	omap_stop_dma(dd->dma_lch);
435	if (ctx->flags & FLAGS_FAST)
436		dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
437
438	return 0;
439}
440
441static void omap_sham_cleanup(struct ahash_request *req)
442{
443	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
444	struct omap_sham_dev *dd = ctx->dd;
445	unsigned long flags;
446
447	spin_lock_irqsave(&dd->lock, flags);
448	if (ctx->flags & FLAGS_CLEAN) {
449		spin_unlock_irqrestore(&dd->lock, flags);
450		return;
451	}
452	ctx->flags |= FLAGS_CLEAN;
453	spin_unlock_irqrestore(&dd->lock, flags);
454
455	if (ctx->digcnt)
456		clk_disable(dd->iclk);
457
458	if (ctx->dma_addr)
459		dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
460				 DMA_TO_DEVICE);
461
462	if (ctx->buffer)
463		free_page((unsigned long)ctx->buffer);
464
465	dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt);
466}
467
468static int omap_sham_init(struct ahash_request *req)
469{
470	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
471	struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
472	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
473	struct omap_sham_dev *dd = NULL, *tmp;
474
475	spin_lock_bh(&sham.lock);
476	if (!tctx->dd) {
477		list_for_each_entry(tmp, &sham.dev_list, list) {
478			dd = tmp;
479			break;
480		}
481		tctx->dd = dd;
482	} else {
483		dd = tctx->dd;
484	}
485	spin_unlock_bh(&sham.lock);
486
487	ctx->dd = dd;
488
489	ctx->flags = 0;
490
491	ctx->flags |= FLAGS_FIRST;
492
493	dev_dbg(dd->dev, "init: digest size: %d\n",
494		crypto_ahash_digestsize(tfm));
495
496	if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
497		ctx->flags |= FLAGS_SHA1;
498
499	ctx->bufcnt = 0;
500	ctx->digcnt = 0;
501
502	ctx->buflen = PAGE_SIZE;
503	ctx->buffer = (void *)__get_free_page(
504				(req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
505				GFP_KERNEL : GFP_ATOMIC);
506	if (!ctx->buffer)
507		return -ENOMEM;
508
509	ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen,
510					DMA_TO_DEVICE);
511	if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
512		dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen);
513		free_page((unsigned long)ctx->buffer);
514		return -EINVAL;
515	}
516
517	if (tctx->flags & FLAGS_HMAC) {
518		struct omap_sham_hmac_ctx *bctx = tctx->base;
519
520		memcpy(ctx->buffer, bctx->ipad, SHA1_MD5_BLOCK_SIZE);
521		ctx->bufcnt = SHA1_MD5_BLOCK_SIZE;
522		ctx->flags |= FLAGS_HMAC;
523	}
524
525	return 0;
526
527}
528
529static int omap_sham_update_req(struct omap_sham_dev *dd)
530{
531	struct ahash_request *req = dd->req;
532	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
533	int err;
534
535	dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
536		 ctx->total, ctx->digcnt, (ctx->flags & FLAGS_FINUP) != 0);
537
538	if (ctx->flags & FLAGS_CPU)
539		err = omap_sham_update_cpu(dd);
540	else if (ctx->flags & FLAGS_FAST)
541		err = omap_sham_update_dma_fast(dd);
542	else
543		err = omap_sham_update_dma_slow(dd);
544
545	/* wait for dma completion before can take more data */
546	dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n", err, ctx->digcnt);
547
548	return err;
549}
550
551static int omap_sham_final_req(struct omap_sham_dev *dd)
552{
553	struct ahash_request *req = dd->req;
554	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
555	int err = 0, use_dma = 1;
556
557	if (ctx->bufcnt <= 64)
558		/* faster to handle last block with cpu */
559		use_dma = 0;
560
561	if (use_dma)
562		err = omap_sham_xmit_dma(dd, ctx->dma_addr, ctx->bufcnt, 1);
563	else
564		err = omap_sham_xmit_cpu(dd, ctx->buffer, ctx->bufcnt, 1);
565
566	ctx->bufcnt = 0;
567
568	if (err != -EINPROGRESS)
569		omap_sham_cleanup(req);
570
571	dev_dbg(dd->dev, "final_req: err: %d\n", err);
572
573	return err;
574}
575
576static int omap_sham_finish_req_hmac(struct ahash_request *req)
577{
578	struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
579	struct omap_sham_hmac_ctx *bctx = tctx->base;
580	int bs = crypto_shash_blocksize(bctx->shash);
581	int ds = crypto_shash_digestsize(bctx->shash);
582	struct {
583		struct shash_desc shash;
584		char ctx[crypto_shash_descsize(bctx->shash)];
585	} desc;
586
587	desc.shash.tfm = bctx->shash;
588	desc.shash.flags = 0; /* not CRYPTO_TFM_REQ_MAY_SLEEP */
589
590	return crypto_shash_init(&desc.shash) ?:
591	       crypto_shash_update(&desc.shash, bctx->opad, bs) ?:
592	       crypto_shash_finup(&desc.shash, req->result, ds, req->result);
593}
594
595static void omap_sham_finish_req(struct ahash_request *req, int err)
596{
597	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
598
599	if (!err) {
600		omap_sham_copy_hash(ctx->dd->req, 1);
601		if (ctx->flags & FLAGS_HMAC)
602			err = omap_sham_finish_req_hmac(req);
603	}
604
605	if (ctx->flags & FLAGS_FINAL)
606		omap_sham_cleanup(req);
607
608	clear_bit(FLAGS_BUSY, &ctx->dd->flags);
609
610	if (req->base.complete)
611		req->base.complete(&req->base, err);
612}
613
614static int omap_sham_handle_queue(struct omap_sham_dev *dd)
615{
616	struct crypto_async_request *async_req, *backlog;
617	struct omap_sham_reqctx *ctx;
618	struct ahash_request *req, *prev_req;
619	unsigned long flags;
620	int err = 0;
621
622	if (test_and_set_bit(FLAGS_BUSY, &dd->flags))
623		return 0;
624
625	spin_lock_irqsave(&dd->lock, flags);
626	backlog = crypto_get_backlog(&dd->queue);
627	async_req = crypto_dequeue_request(&dd->queue);
628	if (!async_req)
629		clear_bit(FLAGS_BUSY, &dd->flags);
630	spin_unlock_irqrestore(&dd->lock, flags);
631
632	if (!async_req)
633		return 0;
634
635	if (backlog)
636		backlog->complete(backlog, -EINPROGRESS);
637
638	req = ahash_request_cast(async_req);
639
640	prev_req = dd->req;
641	dd->req = req;
642
643	ctx = ahash_request_ctx(req);
644
645	dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
646						ctx->op, req->nbytes);
647
648	if (req != prev_req && ctx->digcnt)
649		/* request has changed - restore hash */
650		omap_sham_copy_hash(req, 0);
651
652	if (ctx->op == OP_UPDATE) {
653		err = omap_sham_update_req(dd);
654		if (err != -EINPROGRESS && (ctx->flags & FLAGS_FINUP))
655			/* no final() after finup() */
656			err = omap_sham_final_req(dd);
657	} else if (ctx->op == OP_FINAL) {
658		err = omap_sham_final_req(dd);
659	}
660
661	if (err != -EINPROGRESS) {
662		/* done_task will not finish it, so do it here */
663		omap_sham_finish_req(req, err);
664		tasklet_schedule(&dd->queue_task);
665	}
666
667	dev_dbg(dd->dev, "exit, err: %d\n", err);
668
669	return err;
670}
671
672static int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
673{
674	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
675	struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
676	struct omap_sham_dev *dd = tctx->dd;
677	unsigned long flags;
678	int err;
679
680	ctx->op = op;
681
682	spin_lock_irqsave(&dd->lock, flags);
683	err = ahash_enqueue_request(&dd->queue, req);
684	spin_unlock_irqrestore(&dd->lock, flags);
685
686	omap_sham_handle_queue(dd);
687
688	return err;
689}
690
691static int omap_sham_update(struct ahash_request *req)
692{
693	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
694
695	if (!req->nbytes)
696		return 0;
697
698	ctx->total = req->nbytes;
699	ctx->sg = req->src;
700	ctx->offset = 0;
701
702	if (ctx->flags & FLAGS_FINUP) {
703		if ((ctx->digcnt + ctx->bufcnt + ctx->total) < 9) {
704			/*
705			* OMAP HW accel works only with buffers >= 9
706			* will switch to bypass in final()
707			* final has the same request and data
708			*/
709			omap_sham_append_sg(ctx);
710			return 0;
711		} else if (ctx->bufcnt + ctx->total <= 64) {
712			ctx->flags |= FLAGS_CPU;
713		} else if (!ctx->bufcnt && sg_is_last(ctx->sg)) {
714			/* may be can use faster functions */
715			int aligned = IS_ALIGNED((u32)ctx->sg->offset,
716								sizeof(u32));
717
718			if (aligned && (ctx->flags & FLAGS_FIRST))
719				/* digest: first and final */
720				ctx->flags |= FLAGS_FAST;
721
722			ctx->flags &= ~FLAGS_FIRST;
723		}
724	} else if (ctx->bufcnt + ctx->total <= ctx->buflen) {
725		/* if not finaup -> not fast */
726		omap_sham_append_sg(ctx);
727		return 0;
728	}
729
730	return omap_sham_enqueue(req, OP_UPDATE);
731}
732
733static int omap_sham_shash_digest(struct crypto_shash *shash, u32 flags,
734				  const u8 *data, unsigned int len, u8 *out)
735{
736	struct {
737		struct shash_desc shash;
738		char ctx[crypto_shash_descsize(shash)];
739	} desc;
740
741	desc.shash.tfm = shash;
742	desc.shash.flags = flags & CRYPTO_TFM_REQ_MAY_SLEEP;
743
744	return crypto_shash_digest(&desc.shash, data, len, out);
745}
746
747static int omap_sham_final_shash(struct ahash_request *req)
748{
749	struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
750	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
751
752	return omap_sham_shash_digest(tctx->fallback, req->base.flags,
753				      ctx->buffer, ctx->bufcnt, req->result);
754}
755
756static int omap_sham_final(struct ahash_request *req)
757{
758	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
759	int err = 0;
760
761	ctx->flags |= FLAGS_FINUP;
762
763	/* OMAP HW accel works only with buffers >= 9 */
764	/* HMAC is always >= 9 because of ipad */
765	if ((ctx->digcnt + ctx->bufcnt) < 9)
766		err = omap_sham_final_shash(req);
767	else if (ctx->bufcnt)
768		return omap_sham_enqueue(req, OP_FINAL);
769
770	omap_sham_cleanup(req);
771
772	return err;
773}
774
775static int omap_sham_finup(struct ahash_request *req)
776{
777	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
778	int err1, err2;
779
780	ctx->flags |= FLAGS_FINUP;
781
782	err1 = omap_sham_update(req);
783	if (err1 == -EINPROGRESS)
784		return err1;
785	/*
786	 * final() has to be always called to cleanup resources
787	 * even if udpate() failed, except EINPROGRESS
788	 */
789	err2 = omap_sham_final(req);
790
791	return err1 ?: err2;
792}
793
794static int omap_sham_digest(struct ahash_request *req)
795{
796	return omap_sham_init(req) ?: omap_sham_finup(req);
797}
798
799static int omap_sham_setkey(struct crypto_ahash *tfm, const u8 *key,
800		      unsigned int keylen)
801{
802	struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
803	struct omap_sham_hmac_ctx *bctx = tctx->base;
804	int bs = crypto_shash_blocksize(bctx->shash);
805	int ds = crypto_shash_digestsize(bctx->shash);
806	int err, i;
807	err = crypto_shash_setkey(tctx->fallback, key, keylen);
808	if (err)
809		return err;
810
811	if (keylen > bs) {
812		err = omap_sham_shash_digest(bctx->shash,
813				crypto_shash_get_flags(bctx->shash),
814				key, keylen, bctx->ipad);
815		if (err)
816			return err;
817		keylen = ds;
818	} else {
819		memcpy(bctx->ipad, key, keylen);
820	}
821
822	memset(bctx->ipad + keylen, 0, bs - keylen);
823	memcpy(bctx->opad, bctx->ipad, bs);
824
825	for (i = 0; i < bs; i++) {
826		bctx->ipad[i] ^= 0x36;
827		bctx->opad[i] ^= 0x5c;
828	}
829
830	return err;
831}
832
833static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
834{
835	struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
836	const char *alg_name = crypto_tfm_alg_name(tfm);
837
838	/* Allocate a fallback and abort if it failed. */
839	tctx->fallback = crypto_alloc_shash(alg_name, 0,
840					    CRYPTO_ALG_NEED_FALLBACK);
841	if (IS_ERR(tctx->fallback)) {
842		pr_err("omap-sham: fallback driver '%s' "
843				"could not be loaded.\n", alg_name);
844		return PTR_ERR(tctx->fallback);
845	}
846
847	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
848				 sizeof(struct omap_sham_reqctx));
849
850	if (alg_base) {
851		struct omap_sham_hmac_ctx *bctx = tctx->base;
852		tctx->flags |= FLAGS_HMAC;
853		bctx->shash = crypto_alloc_shash(alg_base, 0,
854						CRYPTO_ALG_NEED_FALLBACK);
855		if (IS_ERR(bctx->shash)) {
856			pr_err("omap-sham: base driver '%s' "
857					"could not be loaded.\n", alg_base);
858			crypto_free_shash(tctx->fallback);
859			return PTR_ERR(bctx->shash);
860		}
861
862	}
863
864	return 0;
865}
866
867static int omap_sham_cra_init(struct crypto_tfm *tfm)
868{
869	return omap_sham_cra_init_alg(tfm, NULL);
870}
871
872static int omap_sham_cra_sha1_init(struct crypto_tfm *tfm)
873{
874	return omap_sham_cra_init_alg(tfm, "sha1");
875}
876
877static int omap_sham_cra_md5_init(struct crypto_tfm *tfm)
878{
879	return omap_sham_cra_init_alg(tfm, "md5");
880}
881
882static void omap_sham_cra_exit(struct crypto_tfm *tfm)
883{
884	struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
885
886	crypto_free_shash(tctx->fallback);
887	tctx->fallback = NULL;
888
889	if (tctx->flags & FLAGS_HMAC) {
890		struct omap_sham_hmac_ctx *bctx = tctx->base;
891		crypto_free_shash(bctx->shash);
892	}
893}
894
895static struct ahash_alg algs[] = {
896{
897	.init		= omap_sham_init,
898	.update		= omap_sham_update,
899	.final		= omap_sham_final,
900	.finup		= omap_sham_finup,
901	.digest		= omap_sham_digest,
902	.halg.digestsize	= SHA1_DIGEST_SIZE,
903	.halg.base	= {
904		.cra_name		= "sha1",
905		.cra_driver_name	= "omap-sha1",
906		.cra_priority		= 100,
907		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
908						CRYPTO_ALG_ASYNC |
909						CRYPTO_ALG_NEED_FALLBACK,
910		.cra_blocksize		= SHA1_BLOCK_SIZE,
911		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
912		.cra_alignmask		= 0,
913		.cra_module		= THIS_MODULE,
914		.cra_init		= omap_sham_cra_init,
915		.cra_exit		= omap_sham_cra_exit,
916	}
917},
918{
919	.init		= omap_sham_init,
920	.update		= omap_sham_update,
921	.final		= omap_sham_final,
922	.finup		= omap_sham_finup,
923	.digest		= omap_sham_digest,
924	.halg.digestsize	= MD5_DIGEST_SIZE,
925	.halg.base	= {
926		.cra_name		= "md5",
927		.cra_driver_name	= "omap-md5",
928		.cra_priority		= 100,
929		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
930						CRYPTO_ALG_ASYNC |
931						CRYPTO_ALG_NEED_FALLBACK,
932		.cra_blocksize		= SHA1_BLOCK_SIZE,
933		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
934		.cra_alignmask		= 0,
935		.cra_module		= THIS_MODULE,
936		.cra_init		= omap_sham_cra_init,
937		.cra_exit		= omap_sham_cra_exit,
938	}
939},
940{
941	.init		= omap_sham_init,
942	.update		= omap_sham_update,
943	.final		= omap_sham_final,
944	.finup		= omap_sham_finup,
945	.digest		= omap_sham_digest,
946	.setkey		= omap_sham_setkey,
947	.halg.digestsize	= SHA1_DIGEST_SIZE,
948	.halg.base	= {
949		.cra_name		= "hmac(sha1)",
950		.cra_driver_name	= "omap-hmac-sha1",
951		.cra_priority		= 100,
952		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
953						CRYPTO_ALG_ASYNC |
954						CRYPTO_ALG_NEED_FALLBACK,
955		.cra_blocksize		= SHA1_BLOCK_SIZE,
956		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
957					sizeof(struct omap_sham_hmac_ctx),
958		.cra_alignmask		= 0,
959		.cra_module		= THIS_MODULE,
960		.cra_init		= omap_sham_cra_sha1_init,
961		.cra_exit		= omap_sham_cra_exit,
962	}
963},
964{
965	.init		= omap_sham_init,
966	.update		= omap_sham_update,
967	.final		= omap_sham_final,
968	.finup		= omap_sham_finup,
969	.digest		= omap_sham_digest,
970	.setkey		= omap_sham_setkey,
971	.halg.digestsize	= MD5_DIGEST_SIZE,
972	.halg.base	= {
973		.cra_name		= "hmac(md5)",
974		.cra_driver_name	= "omap-hmac-md5",
975		.cra_priority		= 100,
976		.cra_flags		= CRYPTO_ALG_TYPE_AHASH |
977						CRYPTO_ALG_ASYNC |
978						CRYPTO_ALG_NEED_FALLBACK,
979		.cra_blocksize		= SHA1_BLOCK_SIZE,
980		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
981					sizeof(struct omap_sham_hmac_ctx),
982		.cra_alignmask		= 0,
983		.cra_module		= THIS_MODULE,
984		.cra_init		= omap_sham_cra_md5_init,
985		.cra_exit		= omap_sham_cra_exit,
986	}
987}
988};
989
990static void omap_sham_done_task(unsigned long data)
991{
992	struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
993	struct ahash_request *req = dd->req;
994	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
995	int ready = 1;
996
997	if (ctx->flags & FLAGS_OUTPUT_READY) {
998		ctx->flags &= ~FLAGS_OUTPUT_READY;
999		ready = 1;
1000	}
1001
1002	if (dd->flags & FLAGS_DMA_ACTIVE) {
1003		dd->flags &= ~FLAGS_DMA_ACTIVE;
1004		omap_sham_update_dma_stop(dd);
1005		omap_sham_update_dma_slow(dd);
1006	}
1007
1008	if (ready && !(dd->flags & FLAGS_DMA_ACTIVE)) {
1009		dev_dbg(dd->dev, "update done\n");
1010		/* finish curent request */
1011		omap_sham_finish_req(req, 0);
1012		/* start new request */
1013		omap_sham_handle_queue(dd);
1014	}
1015}
1016
1017static void omap_sham_queue_task(unsigned long data)
1018{
1019	struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
1020
1021	omap_sham_handle_queue(dd);
1022}
1023
1024static irqreturn_t omap_sham_irq(int irq, void *dev_id)
1025{
1026	struct omap_sham_dev *dd = dev_id;
1027	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
1028
1029	if (!ctx) {
1030		dev_err(dd->dev, "unknown interrupt.\n");
1031		return IRQ_HANDLED;
1032	}
1033
1034	if (unlikely(ctx->flags & FLAGS_FINAL))
1035		/* final -> allow device to go to power-saving mode */
1036		omap_sham_write_mask(dd, SHA_REG_CTRL, 0, SHA_REG_CTRL_LENGTH);
1037
1038	omap_sham_write_mask(dd, SHA_REG_CTRL, SHA_REG_CTRL_OUTPUT_READY,
1039				 SHA_REG_CTRL_OUTPUT_READY);
1040	omap_sham_read(dd, SHA_REG_CTRL);
1041
1042	ctx->flags |= FLAGS_OUTPUT_READY;
1043	tasklet_schedule(&dd->done_task);
1044
1045	return IRQ_HANDLED;
1046}
1047
1048static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
1049{
1050	struct omap_sham_dev *dd = data;
1051
1052	if (likely(lch == dd->dma_lch))
1053		tasklet_schedule(&dd->done_task);
1054}
1055
1056static int omap_sham_dma_init(struct omap_sham_dev *dd)
1057{
1058	int err;
1059
1060	dd->dma_lch = -1;
1061
1062	err = omap_request_dma(dd->dma, dev_name(dd->dev),
1063			omap_sham_dma_callback, dd, &dd->dma_lch);
1064	if (err) {
1065		dev_err(dd->dev, "Unable to request DMA channel\n");
1066		return err;
1067	}
1068	omap_set_dma_dest_params(dd->dma_lch, 0,
1069			OMAP_DMA_AMODE_CONSTANT,
1070			dd->phys_base + SHA_REG_DIN(0), 0, 16);
1071
1072	omap_set_dma_dest_burst_mode(dd->dma_lch,
1073			OMAP_DMA_DATA_BURST_16);
1074
1075	return 0;
1076}
1077
1078static void omap_sham_dma_cleanup(struct omap_sham_dev *dd)
1079{
1080	if (dd->dma_lch >= 0) {
1081		omap_free_dma(dd->dma_lch);
1082		dd->dma_lch = -1;
1083	}
1084}
1085
1086static int __devinit omap_sham_probe(struct platform_device *pdev)
1087{
1088	struct omap_sham_dev *dd;
1089	struct device *dev = &pdev->dev;
1090	struct resource *res;
1091	int err, i, j;
1092
1093	dd = kzalloc(sizeof(struct omap_sham_dev), GFP_KERNEL);
1094	if (dd == NULL) {
1095		dev_err(dev, "unable to alloc data struct.\n");
1096		err = -ENOMEM;
1097		goto data_err;
1098	}
1099	dd->dev = dev;
1100	platform_set_drvdata(pdev, dd);
1101
1102	INIT_LIST_HEAD(&dd->list);
1103	spin_lock_init(&dd->lock);
1104	tasklet_init(&dd->done_task, omap_sham_done_task, (unsigned long)dd);
1105	tasklet_init(&dd->queue_task, omap_sham_queue_task, (unsigned long)dd);
1106	crypto_init_queue(&dd->queue, OMAP_SHAM_QUEUE_LENGTH);
1107
1108	dd->irq = -1;
1109
1110	/* Get the base address */
1111	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1112	if (!res) {
1113		dev_err(dev, "no MEM resource info\n");
1114		err = -ENODEV;
1115		goto res_err;
1116	}
1117	dd->phys_base = res->start;
1118
1119	/* Get the DMA */
1120	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
1121	if (!res) {
1122		dev_err(dev, "no DMA resource info\n");
1123		err = -ENODEV;
1124		goto res_err;
1125	}
1126	dd->dma = res->start;
1127
1128	/* Get the IRQ */
1129	dd->irq = platform_get_irq(pdev,  0);
1130	if (dd->irq < 0) {
1131		dev_err(dev, "no IRQ resource info\n");
1132		err = dd->irq;
1133		goto res_err;
1134	}
1135
1136	err = request_irq(dd->irq, omap_sham_irq,
1137			IRQF_TRIGGER_LOW, dev_name(dev), dd);
1138	if (err) {
1139		dev_err(dev, "unable to request irq.\n");
1140		goto res_err;
1141	}
1142
1143	err = omap_sham_dma_init(dd);
1144	if (err)
1145		goto dma_err;
1146
1147	/* Initializing the clock */
1148	dd->iclk = clk_get(dev, "ick");
1149	if (!dd->iclk) {
1150		dev_err(dev, "clock intialization failed.\n");
1151		err = -ENODEV;
1152		goto clk_err;
1153	}
1154
1155	dd->io_base = ioremap(dd->phys_base, SZ_4K);
1156	if (!dd->io_base) {
1157		dev_err(dev, "can't ioremap\n");
1158		err = -ENOMEM;
1159		goto io_err;
1160	}
1161
1162	clk_enable(dd->iclk);
1163	dev_info(dev, "hw accel on OMAP rev %u.%u\n",
1164		(omap_sham_read(dd, SHA_REG_REV) & SHA_REG_REV_MAJOR) >> 4,
1165		omap_sham_read(dd, SHA_REG_REV) & SHA_REG_REV_MINOR);
1166	clk_disable(dd->iclk);
1167
1168	spin_lock(&sham.lock);
1169	list_add_tail(&dd->list, &sham.dev_list);
1170	spin_unlock(&sham.lock);
1171
1172	for (i = 0; i < ARRAY_SIZE(algs); i++) {
1173		err = crypto_register_ahash(&algs[i]);
1174		if (err)
1175			goto err_algs;
1176	}
1177
1178	return 0;
1179
1180err_algs:
1181	for (j = 0; j < i; j++)
1182		crypto_unregister_ahash(&algs[j]);
1183	iounmap(dd->io_base);
1184io_err:
1185	clk_put(dd->iclk);
1186clk_err:
1187	omap_sham_dma_cleanup(dd);
1188dma_err:
1189	if (dd->irq >= 0)
1190		free_irq(dd->irq, dd);
1191res_err:
1192	kfree(dd);
1193	dd = NULL;
1194data_err:
1195	dev_err(dev, "initialization failed.\n");
1196
1197	return err;
1198}
1199
1200static int __devexit omap_sham_remove(struct platform_device *pdev)
1201{
1202	static struct omap_sham_dev *dd;
1203	int i;
1204
1205	dd = platform_get_drvdata(pdev);
1206	if (!dd)
1207		return -ENODEV;
1208	spin_lock(&sham.lock);
1209	list_del(&dd->list);
1210	spin_unlock(&sham.lock);
1211	for (i = 0; i < ARRAY_SIZE(algs); i++)
1212		crypto_unregister_ahash(&algs[i]);
1213	tasklet_kill(&dd->done_task);
1214	tasklet_kill(&dd->queue_task);
1215	iounmap(dd->io_base);
1216	clk_put(dd->iclk);
1217	omap_sham_dma_cleanup(dd);
1218	if (dd->irq >= 0)
1219		free_irq(dd->irq, dd);
1220	kfree(dd);
1221	dd = NULL;
1222
1223	return 0;
1224}
1225
1226static struct platform_driver omap_sham_driver = {
1227	.probe	= omap_sham_probe,
1228	.remove	= omap_sham_remove,
1229	.driver	= {
1230		.name	= "omap-sham",
1231		.owner	= THIS_MODULE,
1232	},
1233};
1234
1235static int __init omap_sham_mod_init(void)
1236{
1237	pr_info("loading %s driver\n", "omap-sham");
1238
1239	if (!cpu_class_is_omap2() ||
1240		omap_type() != OMAP2_DEVICE_TYPE_SEC) {
1241		pr_err("Unsupported cpu\n");
1242		return -ENODEV;
1243	}
1244
1245	return platform_driver_register(&omap_sham_driver);
1246}
1247
1248static void __exit omap_sham_mod_exit(void)
1249{
1250	platform_driver_unregister(&omap_sham_driver);
1251}
1252
1253module_init(omap_sham_mod_init);
1254module_exit(omap_sham_mod_exit);
1255
1256MODULE_DESCRIPTION("OMAP SHA1/MD5 hw acceleration support.");
1257MODULE_LICENSE("GPL v2");
1258MODULE_AUTHOR("Dmitry Kasatkin");
1259