On Sun, Dec 01, 2013 at 10:20:20PM +0100, Marek Vasut wrote:
> Remove the old DCP driver as it had multiple severe issues. The driver
> will be replaced by a more robust implementation. Here is a short list
> of problems with this driver:
> 
> 1) It only supports AES_CBC
> 2) The driver was apparently never ran behind anyone working with MXS. ie.:
>    -> Restarting the DCP block is not done via mxs_reset_block()
>    -> The DT name is not "fsl,dcp" or "fsl,mxs-dcp" as other MXS drivers
> 3) Introduces new ad-hoc IOCTLs
> 4) The IRQ handler can't use usual completion() in the driver because that'd
>    trigger "scheduling while atomic" oops, yes?
> 
> Signed-off-by: Marek Vasut <[email protected]>

Please drop "ARM: mxs: " from patch subject, since it's not a patch
touching arch/arm/mach-mxs anyhow.  It's there confusing people.

Shawn

> Cc: Herbert Xu <[email protected]>
> Cc: David S. Miller <[email protected]>
> Cc: Fabio Estevam <[email protected]>
> Cc: Shawn Guo <[email protected]>
> Cc: [email protected]
> ---
>  drivers/crypto/Kconfig  |  10 -
>  drivers/crypto/Makefile |   1 -
>  drivers/crypto/dcp.c    | 903 
> ------------------------------------------------
>  3 files changed, 914 deletions(-)
>  delete mode 100644 drivers/crypto/dcp.c
> 
> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> index f4fd837..776d308 100644
> --- a/drivers/crypto/Kconfig
> +++ b/drivers/crypto/Kconfig
> @@ -289,16 +289,6 @@ config CRYPTO_DEV_SAHARA
>         This option enables support for the SAHARA HW crypto accelerator
>         found in some Freescale i.MX chips.
>  
> -config CRYPTO_DEV_DCP
> -     tristate "Support for the DCP engine"
> -     depends on ARCH_MXS && OF
> -     select CRYPTO_BLKCIPHER
> -     select CRYPTO_AES
> -     select CRYPTO_CBC
> -     help
> -       This options enables support for the hardware crypto-acceleration
> -       capabilities of the DCP co-processor
> -
>  config CRYPTO_DEV_S5P
>       tristate "Support for Samsung S5PV210 crypto accelerator"
>       depends on ARCH_S5PV210
> diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
> index b4946dd..38ce13d 100644
> --- a/drivers/crypto/Makefile
> +++ b/drivers/crypto/Makefile
> @@ -13,7 +13,6 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
>  obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
>  obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
>  obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
> -obj-$(CONFIG_CRYPTO_DEV_DCP) += dcp.o
>  obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
>  obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
>  obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
> diff --git a/drivers/crypto/dcp.c b/drivers/crypto/dcp.c
> deleted file mode 100644
> index 247ab80..0000000
> --- a/drivers/crypto/dcp.c
> +++ /dev/null
> @@ -1,903 +0,0 @@
> -/*
> - * Cryptographic API.
> - *
> - * Support for DCP cryptographic accelerator.
> - *
> - * Copyright (c) 2013
> - * Author: Tobias Rauter <[email protected]>
> - *
> - * 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);
> -     dev->dcp_regs_base = devm_ioremap_resource(&pdev->dev, r);
> -     if (IS_ERR(dev->dcp_regs_base))
> -             return PTR_ERR(dev->dcp_regs_base);
> -
> -     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 = devm_request_irq(&pdev->dev, 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");
> -             return -EIO;
> -     }
> -     dev->dcp_irq = r->start;
> -     ret = devm_request_irq(&pdev->dev, dev->dcp_irq, dcp_irq, 0, "dcp",
> -                            dev);
> -     if (ret != 0) {
> -             dev_err(&pdev->dev, "can't request_irq (1)\n");
> -             return -EIO;
> -     }
> -
> -     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");
> -             return -ENOMEM;
> -     }
> -
> -     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:
> -     tasklet_kill(&dev->done_task);
> -     tasklet_kill(&dev->queue_task);
> -     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);
> -
> -     return ret;
> -}
> -
> -static int dcp_remove(struct platform_device *pdev)
> -{
> -     struct dcp_dev *dev;
> -     int j;
> -     dev = platform_get_drvdata(pdev);
> -
> -     misc_deregister(&dev->dcp_bootstream_misc);
> -
> -     for (j = 0; j < ARRAY_SIZE(algs); j++)
> -             crypto_unregister_alg(&algs[j]);
> -
> -     tasklet_kill(&dev->done_task);
> -     tasklet_kill(&dev->queue_task);
> -
> -     dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base,
> -                     dev->payload_base_dma);
> -
> -     dma_free_coherent(&pdev->dev,
> -                     DCP_MAX_PKG * sizeof(struct dcp_hw_packet),
> -                     dev->hw_pkg[0], dev->hw_phys_pkg);
> -
> -     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 <[email protected]>");
> -MODULE_DESCRIPTION("Freescale DCP Crypto Driver");
> -MODULE_LICENSE("GPL");
> -- 
> 1.8.4.2
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to