diff options
Diffstat (limited to 'drivers/crypto/dcp.c')
| -rw-r--r-- | drivers/crypto/dcp.c | 912 | 
1 files changed, 0 insertions, 912 deletions
diff --git a/drivers/crypto/dcp.c b/drivers/crypto/dcp.c deleted file mode 100644 index a8a7dd4b0d2..00000000000 --- a/drivers/crypto/dcp.c +++ /dev/null @@ -1,912 +0,0 @@ -/* - * Cryptographic API. - * - * Support for DCP cryptographic accelerator. - * - * Copyright (c) 2013 - * Author: Tobias Rauter <tobias.rauter@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * Based on tegra-aes.c, dcp.c (from freescale SDK) and sahara.c - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/mutex.h> -#include <linux/interrupt.h> -#include <linux/completion.h> -#include <linux/workqueue.h> -#include <linux/delay.h> -#include <linux/crypto.h> -#include <linux/miscdevice.h> - -#include <crypto/scatterwalk.h> -#include <crypto/aes.h> - - -/* IOCTL for DCP OTP Key AES - taken from Freescale's SDK*/ -#define DBS_IOCTL_BASE   'd' -#define DBS_ENC	_IOW(DBS_IOCTL_BASE, 0x00, uint8_t[16]) -#define DBS_DEC _IOW(DBS_IOCTL_BASE, 0x01, uint8_t[16]) - -/* DCP channel used for AES */ -#define USED_CHANNEL 1 -/* Ring Buffers' maximum size */ -#define DCP_MAX_PKG 20 - -/* Control Register */ -#define DCP_REG_CTRL 0x000 -#define DCP_CTRL_SFRST (1<<31) -#define DCP_CTRL_CLKGATE (1<<30) -#define DCP_CTRL_CRYPTO_PRESENT (1<<29) -#define DCP_CTRL_SHA_PRESENT (1<<28) -#define DCP_CTRL_GATHER_RES_WRITE (1<<23) -#define DCP_CTRL_ENABLE_CONTEXT_CACHE (1<<22) -#define DCP_CTRL_ENABLE_CONTEXT_SWITCH (1<<21) -#define DCP_CTRL_CH_IRQ_E_0 0x01 -#define DCP_CTRL_CH_IRQ_E_1 0x02 -#define DCP_CTRL_CH_IRQ_E_2 0x04 -#define DCP_CTRL_CH_IRQ_E_3 0x08 - -/* Status register */ -#define DCP_REG_STAT 0x010 -#define DCP_STAT_OTP_KEY_READY (1<<28) -#define DCP_STAT_CUR_CHANNEL(stat) ((stat>>24)&0x0F) -#define DCP_STAT_READY_CHANNEL(stat) ((stat>>16)&0x0F) -#define DCP_STAT_IRQ(stat) (stat&0x0F) -#define DCP_STAT_CHAN_0 (0x01) -#define DCP_STAT_CHAN_1 (0x02) -#define DCP_STAT_CHAN_2 (0x04) -#define DCP_STAT_CHAN_3 (0x08) - -/* Channel Control Register */ -#define DCP_REG_CHAN_CTRL 0x020 -#define DCP_CHAN_CTRL_CH0_IRQ_MERGED (1<<16) -#define DCP_CHAN_CTRL_HIGH_PRIO_0 (0x0100) -#define DCP_CHAN_CTRL_HIGH_PRIO_1 (0x0200) -#define DCP_CHAN_CTRL_HIGH_PRIO_2 (0x0400) -#define DCP_CHAN_CTRL_HIGH_PRIO_3 (0x0800) -#define DCP_CHAN_CTRL_ENABLE_0 (0x01) -#define DCP_CHAN_CTRL_ENABLE_1 (0x02) -#define DCP_CHAN_CTRL_ENABLE_2 (0x04) -#define DCP_CHAN_CTRL_ENABLE_3 (0x08) - -/* - * Channel Registers: - * The DCP has 4 channels. Each of this channels - * has 4 registers (command pointer, semaphore, status and options). - * The address of register REG of channel CHAN is obtained by - * dcp_chan_reg(REG, CHAN) - */ -#define DCP_REG_CHAN_PTR	0x00000100 -#define DCP_REG_CHAN_SEMA	0x00000110 -#define DCP_REG_CHAN_STAT	0x00000120 -#define DCP_REG_CHAN_OPT	0x00000130 - -#define DCP_CHAN_STAT_NEXT_CHAIN_IS_0	0x010000 -#define DCP_CHAN_STAT_NO_CHAIN		0x020000 -#define DCP_CHAN_STAT_CONTEXT_ERROR	0x030000 -#define DCP_CHAN_STAT_PAYLOAD_ERROR	0x040000 -#define DCP_CHAN_STAT_INVALID_MODE	0x050000 -#define DCP_CHAN_STAT_PAGEFAULT		0x40 -#define DCP_CHAN_STAT_DST		0x20 -#define DCP_CHAN_STAT_SRC		0x10 -#define DCP_CHAN_STAT_PACKET		0x08 -#define DCP_CHAN_STAT_SETUP		0x04 -#define DCP_CHAN_STAT_MISMATCH		0x02 - -/* hw packet control*/ - -#define DCP_PKT_PAYLOAD_KEY	(1<<11) -#define DCP_PKT_OTP_KEY		(1<<10) -#define DCP_PKT_CIPHER_INIT	(1<<9) -#define DCP_PKG_CIPHER_ENCRYPT	(1<<8) -#define DCP_PKT_CIPHER_ENABLE	(1<<5) -#define DCP_PKT_DECR_SEM	(1<<1) -#define DCP_PKT_CHAIN		(1<<2) -#define DCP_PKT_IRQ		1 - -#define DCP_PKT_MODE_CBC	(1<<4) -#define DCP_PKT_KEYSELECT_OTP	(0xFF<<8) - -/* cipher flags */ -#define DCP_ENC		0x0001 -#define DCP_DEC		0x0002 -#define DCP_ECB		0x0004 -#define DCP_CBC		0x0008 -#define DCP_CBC_INIT	0x0010 -#define DCP_NEW_KEY	0x0040 -#define DCP_OTP_KEY	0x0080 -#define DCP_AES		0x1000 - -/* DCP Flags */ -#define DCP_FLAG_BUSY	0x01 -#define DCP_FLAG_PRODUCING	0x02 - -/* clock defines */ -#define CLOCK_ON	1 -#define CLOCK_OFF	0 - -struct dcp_dev_req_ctx { -	int mode; -}; - -struct dcp_op { -	unsigned int		flags; -	u8			key[AES_KEYSIZE_128]; -	int			keylen; - -	struct ablkcipher_request	*req; -	struct crypto_ablkcipher	*fallback; - -	uint32_t stat; -	uint32_t pkt1; -	uint32_t pkt2; -	struct ablkcipher_walk walk; -}; - -struct dcp_dev { -	struct device *dev; -	void __iomem *dcp_regs_base; - -	int dcp_vmi_irq; -	int dcp_irq; - -	spinlock_t queue_lock; -	struct crypto_queue queue; - -	uint32_t pkt_produced; -	uint32_t pkt_consumed; - -	struct dcp_hw_packet *hw_pkg[DCP_MAX_PKG]; -	dma_addr_t hw_phys_pkg; - -	/* [KEY][IV] Both with 16 Bytes */ -	u8 *payload_base; -	dma_addr_t payload_base_dma; - - -	struct tasklet_struct	done_task; -	struct tasklet_struct	queue_task; -	struct timer_list	watchdog; - -	unsigned long		flags; - -	struct dcp_op *ctx; - -	struct miscdevice dcp_bootstream_misc; -}; - -struct dcp_hw_packet { -	uint32_t next; -	uint32_t pkt1; -	uint32_t pkt2; -	uint32_t src; -	uint32_t dst; -	uint32_t size; -	uint32_t payload; -	uint32_t stat; -}; - -static struct dcp_dev *global_dev; - -static inline u32 dcp_chan_reg(u32 reg, int chan) -{ -	return reg + (chan) * 0x40; -} - -static inline void dcp_write(struct dcp_dev *dev, u32 data, u32 reg) -{ -	writel(data, dev->dcp_regs_base + reg); -} - -static inline void dcp_set(struct dcp_dev *dev, u32 data, u32 reg) -{ -	writel(data, dev->dcp_regs_base + (reg | 0x04)); -} - -static inline void dcp_clear(struct dcp_dev *dev, u32 data, u32 reg) -{ -	writel(data, dev->dcp_regs_base + (reg | 0x08)); -} - -static inline void dcp_toggle(struct dcp_dev *dev, u32 data, u32 reg) -{ -	writel(data, dev->dcp_regs_base + (reg | 0x0C)); -} - -static inline unsigned int dcp_read(struct dcp_dev *dev, u32 reg) -{ -	return readl(dev->dcp_regs_base + reg); -} - -static void dcp_dma_unmap(struct dcp_dev *dev, struct dcp_hw_packet *pkt) -{ -	dma_unmap_page(dev->dev, pkt->src, pkt->size, DMA_TO_DEVICE); -	dma_unmap_page(dev->dev, pkt->dst, pkt->size, DMA_FROM_DEVICE); -	dev_dbg(dev->dev, "unmap packet %x", (unsigned int) pkt); -} - -static int dcp_dma_map(struct dcp_dev *dev, -	struct ablkcipher_walk *walk, struct dcp_hw_packet *pkt) -{ -	dev_dbg(dev->dev, "map packet %x", (unsigned int) pkt); -	/* align to length = 16 */ -	pkt->size = walk->nbytes - (walk->nbytes % 16); - -	pkt->src = dma_map_page(dev->dev, walk->src.page, walk->src.offset, -		pkt->size, DMA_TO_DEVICE); - -	if (pkt->src == 0) { -		dev_err(dev->dev, "Unable to map src"); -		return -ENOMEM; -	} - -	pkt->dst = dma_map_page(dev->dev, walk->dst.page, walk->dst.offset, -		pkt->size, DMA_FROM_DEVICE); - -	if (pkt->dst == 0) { -		dev_err(dev->dev, "Unable to map dst"); -		dma_unmap_page(dev->dev, pkt->src, pkt->size, DMA_TO_DEVICE); -		return -ENOMEM; -	} - -	return 0; -} - -static void dcp_op_one(struct dcp_dev *dev, struct dcp_hw_packet *pkt, -			uint8_t last) -{ -	struct dcp_op *ctx = dev->ctx; -	pkt->pkt1 = ctx->pkt1; -	pkt->pkt2 = ctx->pkt2; - -	pkt->payload = (u32) dev->payload_base_dma; -	pkt->stat = 0; - -	if (ctx->flags & DCP_CBC_INIT) { -		pkt->pkt1 |= DCP_PKT_CIPHER_INIT; -		ctx->flags &= ~DCP_CBC_INIT; -	} - -	mod_timer(&dev->watchdog, jiffies + msecs_to_jiffies(500)); -	pkt->pkt1 |= DCP_PKT_IRQ; -	if (!last) -		pkt->pkt1 |= DCP_PKT_CHAIN; - -	dev->pkt_produced++; - -	dcp_write(dev, 1, -		dcp_chan_reg(DCP_REG_CHAN_SEMA, USED_CHANNEL)); -} - -static void dcp_op_proceed(struct dcp_dev *dev) -{ -	struct dcp_op *ctx = dev->ctx; -	struct dcp_hw_packet *pkt; - -	while (ctx->walk.nbytes) { -		int err = 0; - -		pkt = dev->hw_pkg[dev->pkt_produced % DCP_MAX_PKG]; -		err = dcp_dma_map(dev, &ctx->walk, pkt); -		if (err) { -			dev->ctx->stat |= err; -			/* start timer to wait for already set up calls */ -			mod_timer(&dev->watchdog, -				jiffies + msecs_to_jiffies(500)); -			break; -		} - - -		err = ctx->walk.nbytes - pkt->size; -		ablkcipher_walk_done(dev->ctx->req, &dev->ctx->walk, err); - -		dcp_op_one(dev, pkt, ctx->walk.nbytes == 0); -		/* we have to wait if no space is left in buffer */ -		if (dev->pkt_produced - dev->pkt_consumed == DCP_MAX_PKG) -			break; -	} -	clear_bit(DCP_FLAG_PRODUCING, &dev->flags); -} - -static void dcp_op_start(struct dcp_dev *dev, uint8_t use_walk) -{ -	struct dcp_op *ctx = dev->ctx; - -	if (ctx->flags & DCP_NEW_KEY) { -		memcpy(dev->payload_base, ctx->key, ctx->keylen); -		ctx->flags &= ~DCP_NEW_KEY; -	} - -	ctx->pkt1 = 0; -	ctx->pkt1 |= DCP_PKT_CIPHER_ENABLE; -	ctx->pkt1 |= DCP_PKT_DECR_SEM; - -	if (ctx->flags & DCP_OTP_KEY) -		ctx->pkt1 |= DCP_PKT_OTP_KEY; -	else -		ctx->pkt1 |= DCP_PKT_PAYLOAD_KEY; - -	if (ctx->flags & DCP_ENC) -		ctx->pkt1 |= DCP_PKG_CIPHER_ENCRYPT; - -	ctx->pkt2 = 0; -	if (ctx->flags & DCP_CBC) -		ctx->pkt2 |= DCP_PKT_MODE_CBC; - -	dev->pkt_produced = 0; -	dev->pkt_consumed = 0; - -	ctx->stat = 0; -	dcp_clear(dev, -1, dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL)); -	dcp_write(dev, (u32) dev->hw_phys_pkg, -		dcp_chan_reg(DCP_REG_CHAN_PTR, USED_CHANNEL)); - -	set_bit(DCP_FLAG_PRODUCING, &dev->flags); - -	if (use_walk) { -		ablkcipher_walk_init(&ctx->walk, ctx->req->dst, -				ctx->req->src, ctx->req->nbytes); -		ablkcipher_walk_phys(ctx->req, &ctx->walk); -		dcp_op_proceed(dev); -	} else { -		dcp_op_one(dev, dev->hw_pkg[0], 1); -		clear_bit(DCP_FLAG_PRODUCING, &dev->flags); -	} -} - -static void dcp_done_task(unsigned long data) -{ -	struct dcp_dev *dev = (struct dcp_dev *)data; -	struct dcp_hw_packet *last_packet; -	int fin; -	fin = 0; - -	for (last_packet = dev->hw_pkg[(dev->pkt_consumed) % DCP_MAX_PKG]; -		last_packet->stat == 1; -		last_packet = -			dev->hw_pkg[++(dev->pkt_consumed) % DCP_MAX_PKG]) { - -		dcp_dma_unmap(dev, last_packet); -		last_packet->stat = 0; -		fin++; -	} -	/* the last call of this function already consumed this IRQ's packet */ -	if (fin == 0) -		return; - -	dev_dbg(dev->dev, -		"Packet(s) done with status %x; finished: %d, produced:%d, complete consumed: %d", -		dev->ctx->stat, fin, dev->pkt_produced, dev->pkt_consumed); - -	last_packet = dev->hw_pkg[(dev->pkt_consumed - 1) % DCP_MAX_PKG]; -	if (!dev->ctx->stat && last_packet->pkt1 & DCP_PKT_CHAIN) { -		if (!test_and_set_bit(DCP_FLAG_PRODUCING, &dev->flags)) -			dcp_op_proceed(dev); -		return; -	} - -	while (unlikely(dev->pkt_consumed < dev->pkt_produced)) { -		dcp_dma_unmap(dev, -			dev->hw_pkg[dev->pkt_consumed++ % DCP_MAX_PKG]); -	} - -	if (dev->ctx->flags & DCP_OTP_KEY) { -		/* we used the miscdevice, no walk to finish */ -		clear_bit(DCP_FLAG_BUSY, &dev->flags); -		return; -	} - -	ablkcipher_walk_complete(&dev->ctx->walk); -	dev->ctx->req->base.complete(&dev->ctx->req->base, -			dev->ctx->stat); -	dev->ctx->req = NULL; -	/* in case there are other requests in the queue */ -	tasklet_schedule(&dev->queue_task); -} - -static void dcp_watchdog(unsigned long data) -{ -	struct dcp_dev *dev = (struct dcp_dev *)data; -	dev->ctx->stat |= dcp_read(dev, -			dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL)); - -	dev_err(dev->dev, "Timeout, Channel status: %x", dev->ctx->stat); - -	if (!dev->ctx->stat) -		dev->ctx->stat = -ETIMEDOUT; - -	dcp_done_task(data); -} - - -static irqreturn_t dcp_common_irq(int irq, void *context) -{ -	u32 msk; -	struct dcp_dev *dev = (struct dcp_dev *) context; - -	del_timer(&dev->watchdog); - -	msk = DCP_STAT_IRQ(dcp_read(dev, DCP_REG_STAT)); -	dcp_clear(dev, msk, DCP_REG_STAT); -	if (msk == 0) -		return IRQ_NONE; - -	dev->ctx->stat |= dcp_read(dev, -			dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL)); - -	if (msk & DCP_STAT_CHAN_1) -		tasklet_schedule(&dev->done_task); - -	return IRQ_HANDLED; -} - -static irqreturn_t dcp_vmi_irq(int irq, void *context) -{ -	return dcp_common_irq(irq, context); -} - -static irqreturn_t dcp_irq(int irq, void *context) -{ -	return dcp_common_irq(irq, context); -} - -static void dcp_crypt(struct dcp_dev *dev, struct dcp_op *ctx) -{ -	dev->ctx = ctx; - -	if ((ctx->flags & DCP_CBC) && ctx->req->info) { -		ctx->flags |= DCP_CBC_INIT; -		memcpy(dev->payload_base + AES_KEYSIZE_128, -			ctx->req->info, AES_KEYSIZE_128); -	} - -	dcp_op_start(dev, 1); -} - -static void dcp_queue_task(unsigned long data) -{ -	struct dcp_dev *dev = (struct dcp_dev *) data; -	struct crypto_async_request *async_req, *backlog; -	struct crypto_ablkcipher *tfm; -	struct dcp_op *ctx; -	struct dcp_dev_req_ctx *rctx; -	struct ablkcipher_request *req; -	unsigned long flags; - -	spin_lock_irqsave(&dev->queue_lock, flags); - -	backlog = crypto_get_backlog(&dev->queue); -	async_req = crypto_dequeue_request(&dev->queue); - -	spin_unlock_irqrestore(&dev->queue_lock, flags); - -	if (!async_req) -		goto ret_nothing_done; - -	if (backlog) -		backlog->complete(backlog, -EINPROGRESS); - -	req = ablkcipher_request_cast(async_req); -	tfm = crypto_ablkcipher_reqtfm(req); -	rctx = ablkcipher_request_ctx(req); -	ctx = crypto_ablkcipher_ctx(tfm); - -	if (!req->src || !req->dst) -		goto ret_nothing_done; - -	ctx->flags |= rctx->mode; -	ctx->req = req; - -	dcp_crypt(dev, ctx); - -	return; - -ret_nothing_done: -	clear_bit(DCP_FLAG_BUSY, &dev->flags); -} - - -static int dcp_cra_init(struct crypto_tfm *tfm) -{ -	const char *name = tfm->__crt_alg->cra_name; -	struct dcp_op *ctx = crypto_tfm_ctx(tfm); - -	tfm->crt_ablkcipher.reqsize = sizeof(struct dcp_dev_req_ctx); - -	ctx->fallback = crypto_alloc_ablkcipher(name, 0, -				CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); - -	if (IS_ERR(ctx->fallback)) { -		dev_err(global_dev->dev, "Error allocating fallback algo %s\n", -			name); -		return PTR_ERR(ctx->fallback); -	} - -	return 0; -} - -static void dcp_cra_exit(struct crypto_tfm *tfm) -{ -	struct dcp_op *ctx = crypto_tfm_ctx(tfm); - -	if (ctx->fallback) -		crypto_free_ablkcipher(ctx->fallback); - -	ctx->fallback = NULL; -} - -/* async interface */ -static int dcp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, -		unsigned int len) -{ -	struct dcp_op *ctx = crypto_ablkcipher_ctx(tfm); -	unsigned int ret = 0; -	ctx->keylen = len; -	ctx->flags = 0; -	if (len == AES_KEYSIZE_128) { -		if (memcmp(ctx->key, key, AES_KEYSIZE_128)) { -			memcpy(ctx->key, key, len); -			ctx->flags |= DCP_NEW_KEY; -		} -		return 0; -	} - -	ctx->fallback->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; -	ctx->fallback->base.crt_flags |= -		(tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); - -	ret = crypto_ablkcipher_setkey(ctx->fallback, key, len); -	if (ret) { -		struct crypto_tfm *tfm_aux = crypto_ablkcipher_tfm(tfm); - -		tfm_aux->crt_flags &= ~CRYPTO_TFM_RES_MASK; -		tfm_aux->crt_flags |= -			(ctx->fallback->base.crt_flags & CRYPTO_TFM_RES_MASK); -	} -	return ret; -} - -static int dcp_aes_cbc_crypt(struct ablkcipher_request *req, int mode) -{ -	struct dcp_dev_req_ctx *rctx = ablkcipher_request_ctx(req); -	struct dcp_dev *dev = global_dev; -	unsigned long flags; -	int err = 0; - -	if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) -		return -EINVAL; - -	rctx->mode = mode; - -	spin_lock_irqsave(&dev->queue_lock, flags); -	err = ablkcipher_enqueue_request(&dev->queue, req); -	spin_unlock_irqrestore(&dev->queue_lock, flags); - -	flags = test_and_set_bit(DCP_FLAG_BUSY, &dev->flags); - -	if (!(flags & DCP_FLAG_BUSY)) -		tasklet_schedule(&dev->queue_task); - -	return err; -} - -static int dcp_aes_cbc_encrypt(struct ablkcipher_request *req) -{ -	struct crypto_tfm *tfm = -		crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req)); -	struct dcp_op *ctx = crypto_ablkcipher_ctx( -		crypto_ablkcipher_reqtfm(req)); - -	if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { -		int err = 0; -		ablkcipher_request_set_tfm(req, ctx->fallback); -		err = crypto_ablkcipher_encrypt(req); -		ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm)); -		return err; -	} - -	return dcp_aes_cbc_crypt(req, DCP_AES | DCP_ENC | DCP_CBC); -} - -static int dcp_aes_cbc_decrypt(struct ablkcipher_request *req) -{ -	struct crypto_tfm *tfm = -		crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req)); -	struct dcp_op *ctx = crypto_ablkcipher_ctx( -		crypto_ablkcipher_reqtfm(req)); - -	if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { -		int err = 0; -		ablkcipher_request_set_tfm(req, ctx->fallback); -		err = crypto_ablkcipher_decrypt(req); -		ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm)); -		return err; -	} -	return dcp_aes_cbc_crypt(req, DCP_AES | DCP_DEC | DCP_CBC); -} - -static struct crypto_alg algs[] = { -	{ -		.cra_name = "cbc(aes)", -		.cra_driver_name = "dcp-cbc-aes", -		.cra_alignmask = 3, -		.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC | -			  CRYPTO_ALG_NEED_FALLBACK, -		.cra_blocksize = AES_KEYSIZE_128, -		.cra_type = &crypto_ablkcipher_type, -		.cra_priority = 300, -		.cra_u.ablkcipher = { -			.min_keysize =	AES_KEYSIZE_128, -			.max_keysize = AES_KEYSIZE_128, -			.setkey = dcp_aes_setkey, -			.encrypt = dcp_aes_cbc_encrypt, -			.decrypt = dcp_aes_cbc_decrypt, -			.ivsize = AES_KEYSIZE_128, -		} - -	}, -}; - -/* DCP bootstream verification interface: uses OTP key for crypto */ -static int dcp_bootstream_open(struct inode *inode, struct file *file) -{ -	file->private_data = container_of((file->private_data), -			struct dcp_dev, dcp_bootstream_misc); -	return 0; -} - -static long dcp_bootstream_ioctl(struct file *file, -					 unsigned int cmd, unsigned long arg) -{ -	struct dcp_dev *dev = (struct dcp_dev *) file->private_data; -	void __user *argp = (void __user *)arg; -	int ret; - -	if (dev == NULL) -		return -EBADF; - -	if (cmd != DBS_ENC && cmd != DBS_DEC) -		return -EINVAL; - -	if (copy_from_user(dev->payload_base, argp, 16)) -		return -EFAULT; - -	if (test_and_set_bit(DCP_FLAG_BUSY, &dev->flags)) -		return -EAGAIN; - -	dev->ctx = kzalloc(sizeof(struct dcp_op), GFP_KERNEL); -	if (!dev->ctx) { -		dev_err(dev->dev, -			"cannot allocate context for OTP crypto"); -		clear_bit(DCP_FLAG_BUSY, &dev->flags); -		return -ENOMEM; -	} - -	dev->ctx->flags = DCP_AES | DCP_ECB | DCP_OTP_KEY | DCP_CBC_INIT; -	dev->ctx->flags |= (cmd == DBS_ENC) ? DCP_ENC : DCP_DEC; -	dev->hw_pkg[0]->src = dev->payload_base_dma; -	dev->hw_pkg[0]->dst = dev->payload_base_dma; -	dev->hw_pkg[0]->size = 16; - -	dcp_op_start(dev, 0); - -	while (test_bit(DCP_FLAG_BUSY, &dev->flags)) -		cpu_relax(); - -	ret = dev->ctx->stat; -	if (!ret && copy_to_user(argp, dev->payload_base, 16)) -		ret =  -EFAULT; - -	kfree(dev->ctx); - -	return ret; -} - -static const struct file_operations dcp_bootstream_fops = { -	.owner =		THIS_MODULE, -	.unlocked_ioctl =	dcp_bootstream_ioctl, -	.open =			dcp_bootstream_open, -}; - -static int dcp_probe(struct platform_device *pdev) -{ -	struct dcp_dev *dev = NULL; -	struct resource *r; -	int i, ret, j; - -	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); -	if (!dev) -		return -ENOMEM; - -	global_dev = dev; -	dev->dev = &pdev->dev; - -	platform_set_drvdata(pdev, dev); - -	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!r) { -		dev_err(&pdev->dev, "failed to get IORESOURCE_MEM\n"); -		return -ENXIO; -	} -	dev->dcp_regs_base = devm_ioremap(&pdev->dev, r->start, -					  resource_size(r)); - -	dcp_set(dev, DCP_CTRL_SFRST, DCP_REG_CTRL); -	udelay(10); -	dcp_clear(dev, DCP_CTRL_SFRST | DCP_CTRL_CLKGATE, DCP_REG_CTRL); - -	dcp_write(dev, DCP_CTRL_GATHER_RES_WRITE | -		DCP_CTRL_ENABLE_CONTEXT_CACHE | DCP_CTRL_CH_IRQ_E_1, -		DCP_REG_CTRL); - -	dcp_write(dev, DCP_CHAN_CTRL_ENABLE_1, DCP_REG_CHAN_CTRL); - -	for (i = 0; i < 4; i++) -		dcp_clear(dev, -1, dcp_chan_reg(DCP_REG_CHAN_STAT, i)); - -	dcp_clear(dev, -1, DCP_REG_STAT); - - -	r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if (!r) { -		dev_err(&pdev->dev, "can't get IRQ resource (0)\n"); -		return -EIO; -	} -	dev->dcp_vmi_irq = r->start; -	ret = request_irq(dev->dcp_vmi_irq, dcp_vmi_irq, 0, "dcp", dev); -	if (ret != 0) { -		dev_err(&pdev->dev, "can't request_irq (0)\n"); -		return -EIO; -	} - -	r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); -	if (!r) { -		dev_err(&pdev->dev, "can't get IRQ resource (1)\n"); -		ret = -EIO; -		goto err_free_irq0; -	} -	dev->dcp_irq = r->start; -	ret = request_irq(dev->dcp_irq, dcp_irq, 0, "dcp", dev); -	if (ret != 0) { -		dev_err(&pdev->dev, "can't request_irq (1)\n"); -		ret = -EIO; -		goto err_free_irq0; -	} - -	dev->hw_pkg[0] = dma_alloc_coherent(&pdev->dev, -			DCP_MAX_PKG * sizeof(struct dcp_hw_packet), -			&dev->hw_phys_pkg, -			GFP_KERNEL); -	if (!dev->hw_pkg[0]) { -		dev_err(&pdev->dev, "Could not allocate hw descriptors\n"); -		ret = -ENOMEM; -		goto err_free_irq1; -	} - -	for (i = 1; i < DCP_MAX_PKG; i++) { -		dev->hw_pkg[i - 1]->next = dev->hw_phys_pkg -				+ i * sizeof(struct dcp_hw_packet); -		dev->hw_pkg[i] = dev->hw_pkg[i - 1] + 1; -	} -	dev->hw_pkg[i - 1]->next = dev->hw_phys_pkg; - - -	dev->payload_base = dma_alloc_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, -			&dev->payload_base_dma, GFP_KERNEL); -	if (!dev->payload_base) { -		dev_err(&pdev->dev, "Could not allocate memory for key\n"); -		ret = -ENOMEM; -		goto err_free_hw_packet; -	} -	tasklet_init(&dev->queue_task, dcp_queue_task, -		(unsigned long) dev); -	tasklet_init(&dev->done_task, dcp_done_task, -		(unsigned long) dev); -	spin_lock_init(&dev->queue_lock); - -	crypto_init_queue(&dev->queue, 10); - -	init_timer(&dev->watchdog); -	dev->watchdog.function = &dcp_watchdog; -	dev->watchdog.data = (unsigned long)dev; - -	dev->dcp_bootstream_misc.minor = MISC_DYNAMIC_MINOR, -	dev->dcp_bootstream_misc.name = "dcpboot", -	dev->dcp_bootstream_misc.fops = &dcp_bootstream_fops, -	ret = misc_register(&dev->dcp_bootstream_misc); -	if (ret != 0) { -		dev_err(dev->dev, "Unable to register misc device\n"); -		goto err_free_key_iv; -	} - -	for (i = 0; i < ARRAY_SIZE(algs); i++) { -		algs[i].cra_priority = 300; -		algs[i].cra_ctxsize = sizeof(struct dcp_op); -		algs[i].cra_module = THIS_MODULE; -		algs[i].cra_init = dcp_cra_init; -		algs[i].cra_exit = dcp_cra_exit; -		if (crypto_register_alg(&algs[i])) { -			dev_err(&pdev->dev, "register algorithm failed\n"); -			ret = -ENOMEM; -			goto err_unregister; -		} -	} -	dev_notice(&pdev->dev, "DCP crypto enabled.!\n"); - -	return 0; - -err_unregister: -	for (j = 0; j < i; j++) -		crypto_unregister_alg(&algs[j]); -err_free_key_iv: -	dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base, -			dev->payload_base_dma); -err_free_hw_packet: -	dma_free_coherent(&pdev->dev, DCP_MAX_PKG * -		sizeof(struct dcp_hw_packet), dev->hw_pkg[0], -		dev->hw_phys_pkg); -err_free_irq1: -	free_irq(dev->dcp_irq, dev); -err_free_irq0: -	free_irq(dev->dcp_vmi_irq, dev); - -	return ret; -} - -static int dcp_remove(struct platform_device *pdev) -{ -	struct dcp_dev *dev; -	int j; -	dev = platform_get_drvdata(pdev); - -	dma_free_coherent(&pdev->dev, -			DCP_MAX_PKG * sizeof(struct dcp_hw_packet), -			dev->hw_pkg[0],	dev->hw_phys_pkg); - -	dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base, -			dev->payload_base_dma); - -	free_irq(dev->dcp_irq, dev); -	free_irq(dev->dcp_vmi_irq, dev); - -	tasklet_kill(&dev->done_task); -	tasklet_kill(&dev->queue_task); - -	for (j = 0; j < ARRAY_SIZE(algs); j++) -		crypto_unregister_alg(&algs[j]); - -	misc_deregister(&dev->dcp_bootstream_misc); - -	return 0; -} - -static struct of_device_id fs_dcp_of_match[] = { -	{	.compatible = "fsl-dcp"}, -	{}, -}; - -static struct platform_driver fs_dcp_driver = { -	.probe = dcp_probe, -	.remove = dcp_remove, -	.driver = { -		.name = "fsl-dcp", -		.owner = THIS_MODULE, -		.of_match_table = fs_dcp_of_match -	} -}; - -module_platform_driver(fs_dcp_driver); - - -MODULE_AUTHOR("Tobias Rauter <tobias.rauter@gmail.com>"); -MODULE_DESCRIPTION("Freescale DCP Crypto Driver"); -MODULE_LICENSE("GPL");  | 
