1537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin/*
2537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin * Cryptographic API.
3537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin *
4537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin * Support for OMAP AES HW acceleration.
5537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin *
6537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin * Copyright (c) 2010 Nokia Corporation
7537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
8537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin *
9537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin * This program is free software; you can redistribute it and/or modify
10537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin * it under the terms of the GNU General Public License version 2 as published
11537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin * by the Free Software Foundation.
12537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin *
13537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin */
14537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
15537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define pr_fmt(fmt) "%s: " fmt, __func__
16537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
17537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/err.h>
18537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/module.h>
19537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/init.h>
20537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/errno.h>
21537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/kernel.h>
22537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/clk.h>
23537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/platform_device.h>
24537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/scatterlist.h>
25537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/dma-mapping.h>
26537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/io.h>
27537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/crypto.h>
28537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <linux/interrupt.h>
29537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <crypto/scatterwalk.h>
30537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <crypto/aes.h>
31537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
32537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <plat/cpu.h>
33537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#include <plat/dma.h>
34537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
35537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin/* OMAP TRM gives bitfields as start:end, where start is the higher bit
36537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin   number. For example 7:0 */
37537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define FLD_MASK(start, end)	(((1 << ((start) - (end) + 1)) - 1) << (end))
38537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
39537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
40537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_KEY(x)			(0x1C - ((x ^ 0x01) * 0x04))
41537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_IV(x)			(0x20 + ((x) * 0x04))
42537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
43537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL			0x30
44537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL_CTR_WIDTH		(1 << 7)
45537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL_CTR		(1 << 6)
46537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL_CBC		(1 << 5)
47537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL_KEY_SIZE		(3 << 3)
48537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL_DIRECTION		(1 << 2)
49537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL_INPUT_READY	(1 << 1)
50537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_CTRL_OUTPUT_READY	(1 << 0)
51537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
52537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_DATA			0x34
53537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_DATA_N(x)		(0x34 + ((x) * 0x04))
54537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
55537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_REV			0x44
56537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_REV_MAJOR		0xF0
57537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_REV_MINOR		0x0F
58537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
59537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_MASK			0x48
60537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_MASK_SIDLE		(1 << 6)
61537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_MASK_START		(1 << 5)
62537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_MASK_DMA_OUT_EN		(1 << 3)
63537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_MASK_DMA_IN_EN		(1 << 2)
64537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_MASK_SOFTRESET		(1 << 1)
65537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_AUTOIDLE		(1 << 0)
66537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
67537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_SYSSTATUS		0x4C
68537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define AES_REG_SYSSTATUS_RESETDONE	(1 << 0)
69537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
70537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define DEFAULT_TIMEOUT		(5*HZ)
71537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
72537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define FLAGS_MODE_MASK		0x000f
73537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define FLAGS_ENCRYPT		BIT(0)
74537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define FLAGS_CBC		BIT(1)
75537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define FLAGS_GIV		BIT(2)
76537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
7767a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin#define FLAGS_INIT		BIT(4)
7867a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin#define FLAGS_FAST		BIT(5)
7967a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin#define FLAGS_BUSY		BIT(6)
80537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
81537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstruct omap_aes_ctx {
82537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd;
83537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
84537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int		keylen;
85537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	u32		key[AES_KEYSIZE_256 / sizeof(u32)];
86537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned long	flags;
87537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin};
88537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
89537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstruct omap_aes_reqctx {
90537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned long mode;
91537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin};
92537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
93537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define OMAP_AES_QUEUE_LENGTH	1
94537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin#define OMAP_AES_CACHE_SIZE	0
95537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
96537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstruct omap_aes_dev {
97537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct list_head	list;
98537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned long		phys_base;
99efce41b65f66251d60484781df305e8a85c9507bDmitry Kasatkin	void __iomem		*io_base;
100537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct clk		*iclk;
101537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_ctx	*ctx;
102537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct device		*dev;
103537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned long		flags;
10421fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	int			err;
105537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
10621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	spinlock_t		lock;
10721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	struct crypto_queue	queue;
108537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
10921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	struct tasklet_struct	done_task;
11021fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	struct tasklet_struct	queue_task;
111537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
112537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct ablkcipher_request	*req;
113537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	size_t				total;
114537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct scatterlist		*in_sg;
115537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	size_t				in_offset;
116537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct scatterlist		*out_sg;
117537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	size_t				out_offset;
118537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
119537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	size_t			buflen;
120537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	void			*buf_in;
121537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	size_t			dma_size;
122537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int			dma_in;
123537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int			dma_lch_in;
124537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dma_addr_t		dma_addr_in;
125537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	void			*buf_out;
126537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int			dma_out;
127537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int			dma_lch_out;
128537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dma_addr_t		dma_addr_out;
129537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin};
130537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
131537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin/* keep registered devices data here */
132537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic LIST_HEAD(dev_list);
133537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic DEFINE_SPINLOCK(list_lock);
134537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
135537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic inline u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset)
136537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
137537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return __raw_readl(dd->io_base + offset);
138537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
139537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
140537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic inline void omap_aes_write(struct omap_aes_dev *dd, u32 offset,
141537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				  u32 value)
142537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
143537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	__raw_writel(value, dd->io_base + offset);
144537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
145537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
146537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic inline void omap_aes_write_mask(struct omap_aes_dev *dd, u32 offset,
147537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					u32 value, u32 mask)
148537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
149537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	u32 val;
150537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
151537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	val = omap_aes_read(dd, offset);
152537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	val &= ~mask;
153537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	val |= value;
154537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_aes_write(dd, offset, val);
155537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
156537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
157537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset,
158537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					u32 *value, int count)
159537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
160537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	for (; count--; value++, offset += 4)
161537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		omap_aes_write(dd, offset, *value);
162537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
163537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
164537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit)
165537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
166537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned long timeout = jiffies + DEFAULT_TIMEOUT;
167537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
168537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	while (!(omap_aes_read(dd, offset) & bit)) {
169537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		if (time_is_before_jiffies(timeout)) {
170537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			dev_err(dd->dev, "omap-aes timeout\n");
171537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			return -ETIMEDOUT;
172537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		}
173537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
174537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return 0;
175537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
176537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
177537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_hw_init(struct omap_aes_dev *dd)
178537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
17983ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	/*
18083ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	 * clocks are enabled when request starts and disabled when finished.
18183ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	 * It may be long delays between requests.
18283ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	 * Device might go to off mode to save power.
18383ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	 */
184537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	clk_enable(dd->iclk);
185eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin
186537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!(dd->flags & FLAGS_INIT)) {
187537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		/* is it necessary to reset before every operation? */
188537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET,
189537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					AES_REG_MASK_SOFTRESET);
190537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		/*
191537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		 * prevent OCP bus error (SRESP) in case an access to the module
192537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		 * is performed while the module is coming out of soft reset
193537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		 */
194537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		__asm__ __volatile__("nop");
195537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		__asm__ __volatile__("nop");
196537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
197eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin		if (omap_aes_wait(dd, AES_REG_SYSSTATUS,
19883ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin				AES_REG_SYSSTATUS_RESETDONE))
199eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin			return -ETIMEDOUT;
20083ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin
201eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin		dd->flags |= FLAGS_INIT;
20221fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		dd->err = 0;
203537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
204537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
205eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin	return 0;
206537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
207537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
20821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkinstatic int omap_aes_write_ctrl(struct omap_aes_dev *dd)
209537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
210537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned int key32;
21167a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	int i, err;
212537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	u32 val, mask;
213537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
21421fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	err = omap_aes_hw_init(dd);
21521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	if (err)
21621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		return err;
21721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
218537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	val = 0;
219537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (dd->dma_lch_out >= 0)
220537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		val |= AES_REG_MASK_DMA_OUT_EN;
221537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (dd->dma_lch_in >= 0)
222537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		val |= AES_REG_MASK_DMA_IN_EN;
223537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
224537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	mask = AES_REG_MASK_DMA_IN_EN | AES_REG_MASK_DMA_OUT_EN;
225537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
226537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_aes_write_mask(dd, AES_REG_MASK, val, mask);
227537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
228537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	key32 = dd->ctx->keylen / sizeof(u32);
22967a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin
23067a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	/* it seems a key should always be set even if it has not changed */
231537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	for (i = 0; i < key32; i++) {
232537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		omap_aes_write(dd, AES_REG_KEY(i),
233537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			__le32_to_cpu(dd->ctx->key[i]));
234537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
235537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
23667a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	if ((dd->flags & FLAGS_CBC) && dd->req->info)
23767a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin		omap_aes_write_n(dd, AES_REG_IV(0), dd->req->info, 4);
23867a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin
23967a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
24067a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	if (dd->flags & FLAGS_CBC)
24167a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin		val |= AES_REG_CTRL_CBC;
24267a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	if (dd->flags & FLAGS_ENCRYPT)
24367a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin		val |= AES_REG_CTRL_DIRECTION;
244537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
245537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION |
246537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			AES_REG_CTRL_KEY_SIZE;
247537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
24867a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	omap_aes_write_mask(dd, AES_REG_CTRL, val, mask);
249537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
25083ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	/* IN */
25183ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT,
25283ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin				 dd->phys_base + AES_REG_DATA, 0, 4);
25383ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin
25483ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
25583ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
25683ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin
25783ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	/* OUT */
25883ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT,
25983ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin				dd->phys_base + AES_REG_DATA, 0, 4);
26083ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin
26183ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
26283ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
26321fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
26421fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	return 0;
265537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
266537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
267537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx)
268537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
269537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd = NULL, *tmp;
270537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
271537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_lock_bh(&list_lock);
272537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!ctx->dd) {
273537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		list_for_each_entry(tmp, &dev_list, list) {
274537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			/* FIXME: take fist available aes core */
275537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			dd = tmp;
276537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			break;
277537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		}
278537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		ctx->dd = dd;
279537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	} else {
280537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		/* already found before */
281537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dd = ctx->dd;
282537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
283537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_unlock_bh(&list_lock);
284537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
285537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return dd;
286537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
287537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
288537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic void omap_aes_dma_callback(int lch, u16 ch_status, void *data)
289537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
290537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd = data;
291537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
29221fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	if (ch_status != OMAP_DMA_BLOCK_IRQ) {
29321fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		pr_err("omap-aes DMA error status: 0x%hx\n", ch_status);
29421fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		dd->err = -EIO;
29521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		dd->flags &= ~FLAGS_INIT; /* request to re-initialize */
29621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	} else if (lch == dd->dma_lch_in) {
29721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		return;
29821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	}
29921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
30021fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	/* dma_lch_out - completed */
30121fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	tasklet_schedule(&dd->done_task);
302537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
303537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
304537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_dma_init(struct omap_aes_dev *dd)
305537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
306537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int err = -ENOMEM;
307537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
308537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->dma_lch_out = -1;
309537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->dma_lch_in = -1;
310537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
311537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
312537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
313537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->buflen = PAGE_SIZE << OMAP_AES_CACHE_SIZE;
314537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->buflen &= ~(AES_BLOCK_SIZE - 1);
315537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
316537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!dd->buf_in || !dd->buf_out) {
317537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dd->dev, "unable to alloc pages.\n");
318537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_alloc;
319537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
320537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
321537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* MAP here */
322537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen,
323537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					 DMA_TO_DEVICE);
324537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
325537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
326537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		err = -EINVAL;
327537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_map_in;
328537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
329537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
330537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen,
331537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					  DMA_FROM_DEVICE);
332537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
333537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
334537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		err = -EINVAL;
335537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_map_out;
336537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
337537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
338537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	err = omap_request_dma(dd->dma_in, "omap-aes-rx",
339537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			       omap_aes_dma_callback, dd, &dd->dma_lch_in);
340537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (err) {
341537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dd->dev, "Unable to request DMA channel\n");
342537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_dma_in;
343537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
344537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	err = omap_request_dma(dd->dma_out, "omap-aes-tx",
345537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			       omap_aes_dma_callback, dd, &dd->dma_lch_out);
346537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (err) {
347537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dd->dev, "Unable to request DMA channel\n");
348537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_dma_out;
349537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
350537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
351537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return 0;
352537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
353537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_dma_out:
354537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_free_dma(dd->dma_lch_in);
355537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_dma_in:
356537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
357537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			 DMA_FROM_DEVICE);
358537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_map_out:
359537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
360537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_map_in:
361537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
362537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
363537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_alloc:
364537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (err)
365537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		pr_err("error: %d\n", err);
366537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return err;
367537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
368537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
369537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic void omap_aes_dma_cleanup(struct omap_aes_dev *dd)
370537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
371537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_free_dma(dd->dma_lch_out);
372537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_free_dma(dd->dma_lch_in);
373537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
374537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			 DMA_FROM_DEVICE);
375537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
376537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
377537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
378537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
379537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
380537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic void sg_copy_buf(void *buf, struct scatterlist *sg,
381537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			      unsigned int start, unsigned int nbytes, int out)
382537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
383537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct scatter_walk walk;
384537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
385537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!nbytes)
386537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		return;
387537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
388537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	scatterwalk_start(&walk, sg);
389537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	scatterwalk_advance(&walk, start);
390537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	scatterwalk_copychunks(buf, &walk, nbytes, out);
391537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	scatterwalk_done(&walk, out, 0);
392537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
393537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
394537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int sg_copy(struct scatterlist **sg, size_t *offset, void *buf,
395537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		   size_t buflen, size_t total, int out)
396537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
397537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned int count, off = 0;
398537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
399537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	while (buflen && total) {
400537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		count = min((*sg)->length - *offset, total);
401537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		count = min(count, buflen);
402537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
403537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		if (!count)
404537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			return off;
405537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
40621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		/*
40721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		 * buflen and total are AES_BLOCK_SIZE size aligned,
40821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		 * so count should be also aligned
40921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		 */
41021fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
411537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		sg_copy_buf(buf + off, *sg, *offset, count, out);
412537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
413537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		off += count;
414537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		buflen -= count;
415537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		*offset += count;
416537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		total -= count;
417537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
418537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		if (*offset == (*sg)->length) {
419537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			*sg = sg_next(*sg);
420537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			if (*sg)
421537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				*offset = 0;
422537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			else
423537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				total = 0;
424537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		}
425537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
426537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
427537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return off;
428537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
429537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
430537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
431537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			       dma_addr_t dma_addr_out, int length)
432537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
433537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
434537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd = ctx->dd;
435537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int len32;
436537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
437537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("len: %d\n", length);
438537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
439537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->dma_size = length;
440537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
441537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!(dd->flags & FLAGS_FAST))
442537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dma_sync_single_for_device(dd->dev, dma_addr_in, length,
443537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					   DMA_TO_DEVICE);
444537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
445537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	len32 = DIV_ROUND_UP(length, sizeof(u32));
446537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
447537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* IN */
448537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_set_dma_transfer_params(dd->dma_lch_in, OMAP_DMA_DATA_TYPE_S32,
449537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				     len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_in,
450537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					OMAP_DMA_DST_SYNC);
451537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
452537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_set_dma_src_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_POST_INC,
453537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				dma_addr_in, 0, 0);
454537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
455537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* OUT */
456537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_set_dma_transfer_params(dd->dma_lch_out, OMAP_DMA_DATA_TYPE_S32,
457537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				     len32, 1, OMAP_DMA_SYNC_PACKET,
458537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					dd->dma_out, OMAP_DMA_SRC_SYNC);
459537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
460537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_set_dma_dest_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_POST_INC,
461537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				 dma_addr_out, 0, 0);
462537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
463537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_start_dma(dd->dma_lch_in);
464537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_start_dma(dd->dma_lch_out);
465537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
46683ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	/* start DMA or disable idle mode */
46783ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START,
46883ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin			    AES_REG_MASK_START);
46983ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin
470537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return 0;
471537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
472537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
473537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
474537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
475537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
476537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					crypto_ablkcipher_reqtfm(dd->req));
477537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int err, fast = 0, in, out;
478537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	size_t count;
479537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dma_addr_t addr_in, addr_out;
480537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
481537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("total: %d\n", dd->total);
482537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
483537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
484537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		/* check for alignment */
485537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
486537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
487537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
488537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		fast = in && out;
489537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
490537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
491537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (fast)  {
492537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		count = min(dd->total, sg_dma_len(dd->in_sg));
493537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		count = min(count, sg_dma_len(dd->out_sg));
494537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
49521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		if (count != dd->total) {
49621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin			pr_err("request length != buffer length\n");
497537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			return -EINVAL;
49821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		}
499537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
500537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		pr_debug("fast\n");
501537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
502537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
503537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		if (!err) {
504537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			dev_err(dd->dev, "dma_map_sg() error\n");
505537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			return -EINVAL;
506537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		}
507537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
508537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
509537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		if (!err) {
510537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			dev_err(dd->dev, "dma_map_sg() error\n");
511537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
512537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			return -EINVAL;
513537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		}
514537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
515537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		addr_in = sg_dma_address(dd->in_sg);
516537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		addr_out = sg_dma_address(dd->out_sg);
517537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
518537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dd->flags |= FLAGS_FAST;
519537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
520537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	} else {
521537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		/* use cache buffers */
522537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in,
523537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				 dd->buflen, dd->total, 0);
524537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
525537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		addr_in = dd->dma_addr_in;
526537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		addr_out = dd->dma_addr_out;
527537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
528537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dd->flags &= ~FLAGS_FAST;
529537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
530537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
531537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
532537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->total -= count;
533537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
534537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count);
53521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	if (err) {
53621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
53721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
53821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	}
539537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
540537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return err;
541537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
542537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
543537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
544537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
54521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	struct ablkcipher_request *req = dd->req;
546537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
547537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("err: %d\n", err);
548537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
54983ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	clk_disable(dd->iclk);
550eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin	dd->flags &= ~FLAGS_BUSY;
551eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin
55267a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	req->base.complete(&req->base, err);
553537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
554537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
555537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
556537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
557537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int err = 0;
558537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	size_t count;
559537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
560537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("total: %d\n", dd->total);
561537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
562537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START);
563537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
564537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_stop_dma(dd->dma_lch_in);
565537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_stop_dma(dd->dma_lch_out);
566537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
567537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (dd->flags & FLAGS_FAST) {
568537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
569537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
570537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	} else {
571537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
572537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin					   dd->dma_size, DMA_FROM_DEVICE);
573537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
574537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		/* copy data */
575537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		count = sg_copy(&dd->out_sg, &dd->out_offset, dd->buf_out,
576537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin				 dd->buflen, dd->dma_size, 1);
577537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		if (count != dd->dma_size) {
578537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			err = -EINVAL;
579537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			pr_err("not all data converted: %u\n", count);
580537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		}
581537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
582537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
583537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return err;
584537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
585537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
58621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkinstatic int omap_aes_handle_queue(struct omap_aes_dev *dd,
587eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin			       struct ablkcipher_request *req)
588537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
589537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct crypto_async_request *async_req, *backlog;
590537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_ctx *ctx;
591537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_reqctx *rctx;
592537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	unsigned long flags;
59321fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	int err, ret = 0;
594537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
595537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_lock_irqsave(&dd->lock, flags);
596eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin	if (req)
59721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		ret = ablkcipher_enqueue_request(&dd->queue, req);
598eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin	if (dd->flags & FLAGS_BUSY) {
599eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin		spin_unlock_irqrestore(&dd->lock, flags);
60021fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		return ret;
601eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin	}
602537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	backlog = crypto_get_backlog(&dd->queue);
603537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	async_req = crypto_dequeue_request(&dd->queue);
604eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin	if (async_req)
605eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin		dd->flags |= FLAGS_BUSY;
606537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_unlock_irqrestore(&dd->lock, flags);
607537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
608537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!async_req)
60921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		return ret;
610537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
611537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (backlog)
612537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		backlog->complete(backlog, -EINPROGRESS);
613537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
614537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	req = ablkcipher_request_cast(async_req);
615537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
616537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* assign new request to device */
617537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->req = req;
618537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->total = req->nbytes;
619537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->in_offset = 0;
620537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->in_sg = req->src;
621537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->out_offset = 0;
622537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->out_sg = req->dst;
623537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
624537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	rctx = ablkcipher_request_ctx(req);
625537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
626537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	rctx->mode &= FLAGS_MODE_MASK;
627537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
628537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
62967a730ce449561f6df838f0b38a2b72cbf4e3c4cDmitry Kasatkin	dd->ctx = ctx;
630537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	ctx->dd = dd;
631537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
63283ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	err = omap_aes_write_ctrl(dd);
63383ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin	if (!err)
63483ea7e0fe1471508ab8e8d7b317e743fe7a05a5fDmitry Kasatkin		err = omap_aes_crypt_dma_start(dd);
63521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	if (err) {
63621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		/* aes_task will not finish it, so do it here */
63721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		omap_aes_finish_req(dd, err);
63821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		tasklet_schedule(&dd->queue_task);
63921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	}
640eeb2b202c5b886b76c3bfa76f47e450fa69389fbDmitry Kasatkin
64121fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	return ret; /* return ret, which is enqueue return value */
642537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
643537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
64421fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkinstatic void omap_aes_done_task(unsigned long data)
645537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
646537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
64721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	int err;
648537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
649537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("enter\n");
650537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
65121fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	err = omap_aes_crypt_dma_stop(dd);
652537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
65321fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	err = dd->err ? : err;
65421fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
65521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	if (dd->total && !err) {
65621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		err = omap_aes_crypt_dma_start(dd);
65721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		if (!err)
65821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin			return; /* DMA started. Not fininishing. */
65921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	}
66021fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
66121fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	omap_aes_finish_req(dd, err);
66221fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	omap_aes_handle_queue(dd, NULL);
663537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
664537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("exit\n");
665537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
666537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
66721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkinstatic void omap_aes_queue_task(unsigned long data)
66821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin{
66921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
67021fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
67121fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	omap_aes_handle_queue(dd, NULL);
67221fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin}
67321fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
674537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
675537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
676537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
677537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			crypto_ablkcipher_reqtfm(req));
678537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
679537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd;
680537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
681537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes,
682537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		  !!(mode & FLAGS_ENCRYPT),
683537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		  !!(mode & FLAGS_CBC));
684537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
68521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
68621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		pr_err("request size is not exact amount of AES blocks\n");
68721fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin		return -EINVAL;
68821fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	}
68921fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin
690537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd = omap_aes_find_dev(ctx);
691537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!dd)
692537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		return -ENODEV;
693537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
694537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	rctx->mode = mode;
695537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
69621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	return omap_aes_handle_queue(dd, req);
697537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
698537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
699537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin/* ********************** ALG API ************************************ */
700537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
701537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
702537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			   unsigned int keylen)
703537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
704537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
705537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
706537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
707537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		   keylen != AES_KEYSIZE_256)
708537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		return -EINVAL;
709537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
710537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("enter, keylen: %d\n", keylen);
711537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
712537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	memcpy(ctx->key, key, keylen);
713537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	ctx->keylen = keylen;
714537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
715537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return 0;
716537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
717537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
718537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_ecb_encrypt(struct ablkcipher_request *req)
719537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
720537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return omap_aes_crypt(req, FLAGS_ENCRYPT);
721537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
722537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
723537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_ecb_decrypt(struct ablkcipher_request *req)
724537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
725537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return omap_aes_crypt(req, 0);
726537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
727537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
728537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_cbc_encrypt(struct ablkcipher_request *req)
729537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
730537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
731537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
732537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
733537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_cbc_decrypt(struct ablkcipher_request *req)
734537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
735537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return omap_aes_crypt(req, FLAGS_CBC);
736537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
737537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
738537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_cra_init(struct crypto_tfm *tfm)
739537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
740537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("enter\n");
741537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
742537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx);
743537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
744537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return 0;
745537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
746537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
747537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic void omap_aes_cra_exit(struct crypto_tfm *tfm)
748537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
749537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_debug("enter\n");
750537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
751537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
752537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin/* ********************** ALGS ************************************ */
753537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
754537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic struct crypto_alg algs[] = {
755537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
756537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_name		= "ecb(aes)",
757537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_driver_name	= "ecb-aes-omap",
758537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_priority		= 100,
759d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
760d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos				  CRYPTO_ALG_KERN_DRIVER_ONLY |
761d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos				  CRYPTO_ALG_ASYNC,
762537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_blocksize		= AES_BLOCK_SIZE,
763537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_ctxsize		= sizeof(struct omap_aes_ctx),
764efce41b65f66251d60484781df305e8a85c9507bDmitry Kasatkin	.cra_alignmask		= 0,
765537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_type		= &crypto_ablkcipher_type,
766537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_module		= THIS_MODULE,
767537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_init		= omap_aes_cra_init,
768537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_exit		= omap_aes_cra_exit,
769537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_u.ablkcipher = {
770537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.min_keysize	= AES_MIN_KEY_SIZE,
771537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.max_keysize	= AES_MAX_KEY_SIZE,
772537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.setkey		= omap_aes_setkey,
773537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.encrypt	= omap_aes_ecb_encrypt,
774537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.decrypt	= omap_aes_ecb_decrypt,
775537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
776537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin},
777537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
778537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_name		= "cbc(aes)",
779537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_driver_name	= "cbc-aes-omap",
780537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_priority		= 100,
781d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
782d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos				  CRYPTO_ALG_KERN_DRIVER_ONLY |
783d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos				  CRYPTO_ALG_ASYNC,
784537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_blocksize		= AES_BLOCK_SIZE,
785537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_ctxsize		= sizeof(struct omap_aes_ctx),
786efce41b65f66251d60484781df305e8a85c9507bDmitry Kasatkin	.cra_alignmask		= 0,
787537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_type		= &crypto_ablkcipher_type,
788537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_module		= THIS_MODULE,
789537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_init		= omap_aes_cra_init,
790537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_exit		= omap_aes_cra_exit,
791537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.cra_u.ablkcipher = {
792537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.min_keysize	= AES_MIN_KEY_SIZE,
793537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.max_keysize	= AES_MAX_KEY_SIZE,
794537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.ivsize		= AES_BLOCK_SIZE,
795537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.setkey		= omap_aes_setkey,
796537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.encrypt	= omap_aes_cbc_encrypt,
797537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.decrypt	= omap_aes_cbc_decrypt,
798537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
799537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
800537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin};
801537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
802537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_probe(struct platform_device *pdev)
803537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
804537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct device *dev = &pdev->dev;
805537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd;
806537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct resource *res;
807537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int err = -ENOMEM, i, j;
808537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	u32 reg;
809537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
810537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd = kzalloc(sizeof(struct omap_aes_dev), GFP_KERNEL);
811537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (dd == NULL) {
812537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dev, "unable to alloc data struct.\n");
813537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_data;
814537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
815537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->dev = dev;
816537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	platform_set_drvdata(pdev, dd);
817537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
818537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_lock_init(&dd->lock);
819537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH);
820537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
821537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* Get the base address */
822537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
823537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!res) {
824537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dev, "invalid resource type\n");
825537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		err = -ENODEV;
826537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_res;
827537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
828537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->phys_base = res->start;
829537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
830537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* Get the DMA */
831537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
832537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!res)
833537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_info(dev, "no DMA info\n");
834537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	else
835537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dd->dma_out = res->start;
836537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
837537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* Get the DMA */
838537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
839537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!res)
840537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_info(dev, "no DMA info\n");
841537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	else
842537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dd->dma_in = res->start;
843537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
844537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	/* Initializing the clock */
845537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->iclk = clk_get(dev, "ick");
8463e50191d981082345572f1e80b463eb9c05989a0Jamie Iles	if (IS_ERR(dd->iclk)) {
847537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dev, "clock intialization failed.\n");
8483e50191d981082345572f1e80b463eb9c05989a0Jamie Iles		err = PTR_ERR(dd->iclk);
849537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_res;
850537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
851537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
852537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd->io_base = ioremap(dd->phys_base, SZ_4K);
853537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!dd->io_base) {
854537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		dev_err(dev, "can't ioremap\n");
855537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		err = -ENOMEM;
856537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_io;
857537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
858537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
859537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	clk_enable(dd->iclk);
860537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	reg = omap_aes_read(dd, AES_REG_REV);
861537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dev_info(dev, "OMAP AES hw accel rev: %u.%u\n",
862537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		 (reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR);
863537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	clk_disable(dd->iclk);
864537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
86521fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd);
86621fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd);
867537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
868537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	err = omap_aes_dma_init(dd);
869537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (err)
870537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		goto err_dma;
871537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
872537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	INIT_LIST_HEAD(&dd->list);
873537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_lock(&list_lock);
874537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	list_add_tail(&dd->list, &dev_list);
875537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_unlock(&list_lock);
876537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
877537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	for (i = 0; i < ARRAY_SIZE(algs); i++) {
878537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		pr_debug("i: %d\n", i);
879537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		INIT_LIST_HEAD(&algs[i].cra_list);
880537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		err = crypto_register_alg(&algs[i]);
881537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		if (err)
882537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin			goto err_algs;
883537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
884537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
885537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_info("probe() done\n");
886537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
887537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return 0;
888537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_algs:
889537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	for (j = 0; j < i; j++)
890537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		crypto_unregister_alg(&algs[j]);
891537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_aes_dma_cleanup(dd);
892537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_dma:
89321fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	tasklet_kill(&dd->done_task);
89421fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	tasklet_kill(&dd->queue_task);
895537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	iounmap(dd->io_base);
896537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_io:
897537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	clk_put(dd->iclk);
898537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_res:
899537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	kfree(dd);
900537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd = NULL;
901537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinerr_data:
902537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dev_err(dev, "initialization failed.\n");
903537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return err;
904537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
905537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
906537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int omap_aes_remove(struct platform_device *pdev)
907537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
908537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	struct omap_aes_dev *dd = platform_get_drvdata(pdev);
909537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	int i;
910537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
911537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!dd)
912537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		return -ENODEV;
913537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
914537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_lock(&list_lock);
915537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	list_del(&dd->list);
916537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	spin_unlock(&list_lock);
917537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
918537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	for (i = 0; i < ARRAY_SIZE(algs); i++)
919537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		crypto_unregister_alg(&algs[i]);
920537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
92121fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	tasklet_kill(&dd->done_task);
92221fe9767f3bd56fd9a271dc43b93cd4608d47f4aDmitry Kasatkin	tasklet_kill(&dd->queue_task);
923537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	omap_aes_dma_cleanup(dd);
924537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	iounmap(dd->io_base);
925537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	clk_put(dd->iclk);
926537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	kfree(dd);
927537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	dd = NULL;
928537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
929537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return 0;
930537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
931537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
932537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic struct platform_driver omap_aes_driver = {
933537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.probe	= omap_aes_probe,
934537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.remove	= omap_aes_remove,
935537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	.driver	= {
936537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.name	= "omap-aes",
937537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		.owner	= THIS_MODULE,
938537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	},
939537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin};
940537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
941537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic int __init omap_aes_mod_init(void)
942537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
943537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	pr_info("loading %s driver\n", "omap-aes");
944537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
945537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	if (!cpu_class_is_omap2() || omap_type() != OMAP2_DEVICE_TYPE_SEC) {
946537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		pr_err("Unsupported cpu\n");
947537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin		return -ENODEV;
948537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	}
949537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
950537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	return  platform_driver_register(&omap_aes_driver);
951537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
952537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
953537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinstatic void __exit omap_aes_mod_exit(void)
954537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin{
955537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin	platform_driver_unregister(&omap_aes_driver);
956537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin}
957537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
958537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinmodule_init(omap_aes_mod_init);
959537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkinmodule_exit(omap_aes_mod_exit);
960537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
961537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry KasatkinMODULE_DESCRIPTION("OMAP AES hw acceleration support.");
962537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry KasatkinMODULE_LICENSE("GPL v2");
963537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry KasatkinMODULE_AUTHOR("Dmitry Kasatkin");
964537559a5b3ef854772bd89fbb43aa77d0bbfb721Dmitry Kasatkin
965