diff options
author | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-05 10:12:53 +0000 |
---|---|---|
committer | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-05 10:12:53 +0000 |
commit | 5c105d9f3fd086aff195d3849dcf847d6b0bd927 (patch) | |
tree | 1229a11f725bfa58aa7c57a76898553bb5f6654a /target/linux/coldfire/patches/024-Add-SEC-1.1-support-for-MCF547x-and-MCF548x.patch | |
download | openwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.tar.gz openwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.zip |
branch Attitude Adjustment
git-svn-id: svn://svn.openwrt.org/openwrt/branches/attitude_adjustment@33625 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/coldfire/patches/024-Add-SEC-1.1-support-for-MCF547x-and-MCF548x.patch')
-rw-r--r-- | target/linux/coldfire/patches/024-Add-SEC-1.1-support-for-MCF547x-and-MCF548x.patch | 2093 |
1 files changed, 2093 insertions, 0 deletions
diff --git a/target/linux/coldfire/patches/024-Add-SEC-1.1-support-for-MCF547x-and-MCF548x.patch b/target/linux/coldfire/patches/024-Add-SEC-1.1-support-for-MCF547x-and-MCF548x.patch new file mode 100644 index 000000000..53cebe184 --- /dev/null +++ b/target/linux/coldfire/patches/024-Add-SEC-1.1-support-for-MCF547x-and-MCF548x.patch @@ -0,0 +1,2093 @@ +From c925421b8c35357427499f3d298777535c2c6cfd Mon Sep 17 00:00:00 2001 +From: Alison Wang <b18965@freescale.com> +Date: Thu, 4 Aug 2011 09:59:45 +0800 +Subject: [PATCH 24/52] Add SEC 1.1 support for MCF547x and MCF548x + +Add SEC 1.1 support for MCF547x and MCF548x. The SEC driver is +in drivers/crypto. + +Signed-off-by: Alison Wang <b18965@freescale.com> +--- + arch/m68k/coldfire/m547x/mcf548x-devices.c | 2 +- + arch/m68k/include/asm/cf_io.h | 4 + + crypto/testmgr.c | 18 +- + drivers/crypto/Kconfig | 13 + + drivers/crypto/Makefile | 1 + + drivers/crypto/cf_talitos.c | 1727 ++++++++++++++++++++++++++++ + drivers/crypto/cf_talitos.h | 229 ++++ + 7 files changed, 1989 insertions(+), 5 deletions(-) + create mode 100644 drivers/crypto/cf_talitos.c + create mode 100644 drivers/crypto/cf_talitos.h + +--- a/arch/m68k/coldfire/m547x/mcf548x-devices.c ++++ b/arch/m68k/coldfire/m547x/mcf548x-devices.c +@@ -54,7 +54,7 @@ static struct resource coldfire_sec_reso + }; + + static struct platform_device coldfire_sec_device = { +- .name = "fsl-sec1", ++ .name = "talitos", + .id = -1, + .num_resources = ARRAY_SIZE(coldfire_sec_resources), + .resource = coldfire_sec_resources, +--- a/arch/m68k/include/asm/cf_io.h ++++ b/arch/m68k/include/asm/cf_io.h +@@ -192,4 +192,8 @@ static inline void memcpy_toio(volatile + #define writel(b, addr) (void)((*(volatile unsigned int *) (addr)) = (b)) + #endif /* readb */ + ++/* access ports */ ++#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) | (_v)) ++#define clrbits32(_addr, _v) out_be32((_addr), in_be32(_addr) & ~(_v)) ++ + #endif /* _IO_H */ +--- a/crypto/testmgr.c ++++ b/crypto/testmgr.c +@@ -212,7 +212,11 @@ static int test_hash(struct crypto_ahash + tcrypt_complete, &tresult); + + j = 0; ++#if defined(CONFIG_CRYPTO_DEV_CF_TALITOS) ++ for (i = 1; i < tcount; i++) { ++#else + for (i = 0; i < tcount; i++) { ++#endif + if (template[i].np) + continue; + +@@ -276,7 +280,9 @@ static int test_hash(struct crypto_ahash + hexdump(result, crypto_ahash_digestsize(tfm)); + ret = -EINVAL; + goto out; +- } ++ } else ++ printk(KERN_INFO "alg: hash: Test %d succeed for %s\n", ++ j, algo); + } + + j = 0; +@@ -344,7 +350,9 @@ static int test_hash(struct crypto_ahash + hexdump(result, crypto_ahash_digestsize(tfm)); + ret = -EINVAL; + goto out; +- } ++ } else ++ printk(KERN_INFO "alg: hash: Chunking test %d " ++ "succeed for %s\n", j, algo); + } + } + +@@ -788,7 +796,6 @@ static int test_skcipher(struct crypto_a + else + e = "decryption"; + +- printk(KERN_INFO "%s testing %s %s\n", __func__, algo, e); + init_completion(&result.completion); + + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); +@@ -963,7 +970,10 @@ static int test_skcipher(struct crypto_a + "%u for %s\n", j, e, k, algo); + hexdump(q, template[i].tap[k]); + goto out; +- } ++ } else ++ printk(KERN_INFO "alg: skcipher: Chunk " ++ "test %d pass on %s for %s\n", ++ j, e, algo); + + q += template[i].tap[k]; + for (n = 0; offset_in_page(q + n) && q[n]; n++) +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -282,6 +282,19 @@ config CRYPTO_DEV_TALITOS + To compile this driver as a module, choose M here: the module + will be called talitos. + ++config CRYPTO_DEV_CF_TALITOS ++ tristate "Talitos Freescale Coldfire Security Engine (SEC)" ++ select CRYPTO_ALGAPI ++ select CRYPTO_AUTHENC ++ select HW_RANDOM ++ depends on (M547X || M548X) ++ help ++ Say 'Y' here to use the Freescale Coldfire Security Engine (SEC) ++ to offload cryptographic algorithm computation. ++ ++ The Freescale SEC is present on Coldfire MCF547x and MCF548x ++ processors. ++ + config CRYPTO_DEV_IXP4XX + tristate "Driver for IXP4xx crypto hardware acceleration" + depends on ARCH_IXP4XX +--- a/drivers/crypto/Makefile ++++ b/drivers/crypto/Makefile +@@ -6,6 +6,7 @@ n2_crypto-y := n2_core.o n2_asm.o + obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o + obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o + obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o ++obj-$(CONFIG_CRYPTO_DEV_CF_TALITOS) += cf_talitos.o + obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o + obj-$(CONFIG_CRYPTO_DEV_MCFCAU) += mcfcau.o + obj-$(CONFIG_CRYPTO_DEV_MCFCAU_DES) += mcfcau-des.o +--- /dev/null ++++ b/drivers/crypto/cf_talitos.c +@@ -0,0 +1,1727 @@ ++/* ++ * cf_talitos - Freescale Coldfire Integrated Security Engine ++ * (SEC) device driver ++ * ++ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Author: Alison Wang <b18965@freescale.com> ++ * based on talitos.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/mod_devicetable.h> ++#include <linux/device.h> ++#include <linux/interrupt.h> ++#include <linux/crypto.h> ++#include <linux/hw_random.h> ++#include <linux/platform_device.h> ++#include <linux/dma-mapping.h> ++#include <linux/io.h> ++#include <linux/spinlock.h> ++#include <linux/rtnetlink.h> ++#include <linux/slab.h> ++ ++#include <crypto/algapi.h> ++#include <crypto/aes.h> ++#include <crypto/des.h> ++#include <crypto/sha.h> ++#include <crypto/md5.h> ++#include <crypto/aead.h> ++#include <crypto/authenc.h> ++#include <crypto/skcipher.h> ++#include <crypto/hash.h> ++#include <crypto/internal/hash.h> ++#include <crypto/scatterwalk.h> ++ ++#include <asm/m5485sim.h> ++#include "cf_talitos.h" ++ ++#define TALITOS_TIMEOUT 100000 ++#define TALITOS_MAX_DATA_LEN 65535 ++ ++#define DESC_TYPE(desc_hdr) (((desc_hdr) >> 4) & 0xf) ++#define PRIMARY_EU(desc_hdr) (((desc_hdr) >> 28) & 0xf) ++#define SECONDARY_EU(desc_hdr) (((desc_hdr) >> 16) & 0xf) ++ ++#define CF_TALITOS_DEBUG 0 ++#if CF_TALITOS_DEBUG ++#define dprintk(args...) printk(args) ++#else ++#define dprintk(...) ++#endif ++ ++/* descriptor pointer entry */ ++struct talitos_ptr { ++ u32 len; /* length */ ++ u32 ptr; /* address */ ++}; ++ ++static const struct talitos_ptr zero_entry = { ++ .len = 0, ++ .ptr = 0 ++}; ++ ++/* descriptor */ ++struct talitos_desc { ++ u32 hdr; /* header */ ++ struct talitos_ptr ptr[7]; /* ptr/len pair array */ ++ u32 next_hdr; ++}; ++ ++/** ++ * talitos_request - descriptor submission request ++ * @desc: descriptor pointer (kernel virtual) ++ * @dma_desc: descriptor's physical bus address ++ * @callback: whom to call when descriptor processing is done ++ * @context: caller context (optional) ++ */ ++struct talitos_request { ++ struct talitos_desc *desc; ++ dma_addr_t dma_desc; ++ void (*callback) (struct device *dev, struct talitos_desc *desc, ++ void *context, int error); ++ void *context; ++}; ++ ++/* per-channel fifo management */ ++struct talitos_channel { ++ /* request fifo */ ++ struct talitos_request *fifo; ++ ++ /* number of requests pending in channel h/w fifo */ ++ atomic_t submit_count ____cacheline_aligned; ++ ++ /* request submission (head) lock */ ++ spinlock_t head_lock ____cacheline_aligned; ++ /* index to next free descriptor request */ ++ int head; ++ ++ /* request release (tail) lock */ ++ spinlock_t tail_lock ____cacheline_aligned; ++ /* index to next in-progress/done descriptor request */ ++ int tail; ++}; ++ ++struct talitos_private { ++ struct device *dev; ++ struct platform_device *pdev; ++ void __iomem *reg; ++ int irq; ++ ++ /* SEC version geometry (from device tree node) */ ++ unsigned int num_channels; ++ unsigned int chfifo_len; ++ unsigned int exec_units; ++ unsigned int desc_types; ++ ++ /* SEC Compatibility info */ ++ unsigned long features; ++ ++ /* ++ * length of the request fifo ++ * fifo_len is chfifo_len rounded up to next power of 2 ++ * so we can use bitwise ops to wrap ++ */ ++ unsigned int fifo_len; ++ ++ struct talitos_channel *chan; ++ ++ /* next channel to be assigned next incoming descriptor */ ++ atomic_t last_chan ____cacheline_aligned; ++ ++ /* request callback tasklet */ ++ struct tasklet_struct done_task; ++ ++ /* list of registered algorithms */ ++ struct list_head alg_list; ++ ++ /* hwrng device */ ++ struct hwrng rng; ++}; ++ ++/* .features flag */ ++#define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 ++#define TALITOS_FTR_HW_AUTH_CHECK 0x00000002 ++#define TALITOS_FTR_SHA224_HWINIT 0x00000004 ++ ++/* ++ * map virtual single (contiguous) pointer to h/w descriptor pointer ++ */ ++static void map_single_talitos_ptr(struct device *dev, ++ struct talitos_ptr *talitos_ptr, ++ unsigned short len, void *data, ++ unsigned char extent, ++ enum dma_data_direction dir) ++{ ++ dma_addr_t dma_addr = dma_map_single(dev, data, len, dir); ++ ++ talitos_ptr->len = len; ++ talitos_ptr->ptr = dma_addr; ++} ++ ++/* ++ * unmap bus single (contiguous) h/w descriptor pointer ++ */ ++static void unmap_single_talitos_ptr(struct device *dev, ++ struct talitos_ptr *talitos_ptr, ++ enum dma_data_direction dir) ++{ ++ dma_unmap_single(dev, talitos_ptr->ptr, talitos_ptr->len, dir); ++} ++ ++static int reset_channel(struct device *dev, int ch) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ unsigned int timeout = TALITOS_TIMEOUT; ++ ++ setbits32(priv->reg + TALITOS_CCCR(ch), TALITOS_CCCR_RESET); ++ ++ while ((in_be32(priv->reg + TALITOS_CCCR(ch)) & ++ TALITOS_CCCR_RESET) && --timeout) ++ cpu_relax(); ++ ++ if (timeout == 0) { ++ dev_err(dev, "failed to reset channel %d\n", ch); ++ return -EIO; ++ } ++ ++ /* set 36-bit addressing, done writeback enable and done IRQ enable */ ++ setbits32(priv->reg + TALITOS_CCCR(ch), TALITOS_CCCR_NE | ++ TALITOS_CCCR_NT | TALITOS_CCCR_CDWE | ++ TALITOS_CCCR_CDIE); ++ ++ return 0; ++} ++ ++static int reset_device(struct device *dev) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ unsigned int timeout = TALITOS_TIMEOUT; ++ ++ setbits32(priv->reg + TALITOS_MCR, TALITOS_MCR_SWR); ++ ++ while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR) ++ && --timeout) ++ cpu_relax(); ++ ++ if (timeout == 0) { ++ dev_err(dev, "failed to reset device\n"); ++ return -EIO; ++ } ++ ++ setbits32(priv->reg + TALITOS_DEURCR, TALITOS_DEURCR_RESET); ++ setbits32(priv->reg + TALITOS_AFEURCR, TALITOS_AFEURCR_RESET); ++ setbits32(priv->reg + TALITOS_AESURCR, TALITOS_AESURCR_RESET); ++ setbits32(priv->reg + TALITOS_MDEURCR, TALITOS_MDEURCR_RESET); ++ setbits32(priv->reg + TALITOS_RNGRCR, TALITOS_RNGRCR_SR); ++ return 0; ++} ++ ++/* ++ * Reset and initialize the device ++ */ ++static int init_device(struct device *dev) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ int ch, err; ++ ++ /* ++ * Master reset ++ * errata documentation: warning: certain SEC interrupts ++ * are not fully cleared by writing the MCR:SWR bit, ++ * set bit twice to completely reset ++ */ ++ err = reset_device(dev); ++ if (err) ++ return err; ++ ++ err = reset_device(dev); ++ if (err) ++ return err; ++ ++ /* reset channels */ ++ for (ch = 0; ch < priv->num_channels; ch++) { ++ err = reset_channel(dev, ch); ++ if (err) ++ return err; ++ } ++ ++ /* enable channel done and error interrupts */ ++ out_be32(priv->reg + TALITOS_IMR, 0); ++ out_be32(priv->reg + TALITOS_IMR_LO, 0); ++ ++ out_be32(priv->reg + TALITOS_ICR, ++ TALITOS_ICR_CHERR | TALITOS_ICR_CHDONE); ++ out_be32(priv->reg + TALITOS_ICR_LO, ++ TALITOS_ICR_LO_CHERR | TALITOS_ICR_LO_CHDONE); ++ ++ return 0; ++} ++ ++/** ++ * talitos_submit - submits a descriptor to the device for processing ++ * @dev: the SEC device to be used ++ * @desc: the descriptor to be processed by the device ++ * @callback: whom to call when processing is complete ++ * @context: a handle for use by caller (optional) ++ * ++ * desc must contain valid dma-mapped (bus physical) address pointers. ++ * callback must check err and feedback in descriptor header ++ * for device processing status. ++ */ ++static int talitos_submit(struct device *dev, struct talitos_desc *desc, ++ void (*callback)(struct device *dev, ++ struct talitos_desc *desc, ++ void *context, int error), ++ void *context) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ struct talitos_request *request; ++ unsigned long flags, ch; ++ int head; ++ ++ /* ignore key parity check in triple DES */ ++ if (((desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_DEU) && ++ (desc->hdr & DESC_HDR_MODE0_DEU_3DES)) ++ setbits32(priv->reg + TALITOS_DEUIMR, TALITOS_DEUIMR_KPE_MASK); ++ ++ /* select done notification */ ++ desc->hdr |= DESC_HDR_DONE; ++ ++ /* emulate SEC's round-robin channel fifo polling scheme */ ++ ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1); ++ ++ spin_lock_irqsave(&priv->chan[ch].head_lock, flags); ++ ++ head = priv->chan[ch].head; ++ request = &priv->chan[ch].fifo[head]; ++ ++ /* map descriptor and save caller data */ ++ request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), ++ DMA_BIDIRECTIONAL); ++ request->callback = callback; ++ request->context = context; ++ ++ /* increment fifo head */ ++ priv->chan[ch].head = (priv->chan[ch].head + 1) & (priv->fifo_len - 1); ++ ++ smp_wmb(); ++ request->desc = desc; ++ ++ /* GO! */ ++ wmb(); ++ out_be32(priv->reg + TALITOS_FF(ch), request->dma_desc); ++ ++ spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); ++ ++ return -EINPROGRESS; ++} ++ ++/* ++ * process what was done, notify callback of error if not ++ */ ++static void flush_channel(struct device *dev, int ch, int error, int reset_ch) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ struct talitos_request *request, saved_req; ++ unsigned long flags; ++ int tail, status; ++ ++ spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); ++ ++ tail = priv->chan[ch].tail; ++ while (priv->chan[ch].fifo[tail].desc) { ++ request = &priv->chan[ch].fifo[tail]; ++ ++ /* descriptors with their done bits set don't get the error */ ++ rmb(); ++ if ((request->desc->hdr & DESC_HDR_DONE) == DESC_HDR_DONE) ++ status = 0; ++ else ++ if (!error) ++ break; ++ else ++ status = error; ++ ++ dma_unmap_single(dev, request->dma_desc, ++ sizeof(struct talitos_desc), ++ DMA_BIDIRECTIONAL); ++ ++ /* copy entries so we can call callback outside lock */ ++ saved_req.desc = request->desc; ++ saved_req.callback = request->callback; ++ saved_req.context = request->context; ++ ++ /* release request entry in fifo */ ++ smp_wmb(); ++ request->desc = NULL; ++ ++ /* increment fifo tail */ ++ priv->chan[ch].tail = (tail + 1) & (priv->fifo_len - 1); ++ ++ spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); ++ ++ atomic_dec(&priv->chan[ch].submit_count); ++ ++ saved_req.callback(dev, saved_req.desc, saved_req.context, ++ status); ++ /* channel may resume processing in single desc error case */ ++ if (error && !reset_ch && status == error) ++ return; ++ spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); ++ tail = priv->chan[ch].tail; ++ } ++ ++ spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); ++} ++ ++/* ++ * process completed requests for channels that have done status ++ */ ++static void talitos_done(unsigned long data) ++{ ++ struct device *dev = (struct device *)data; ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ int ch; ++ ++ for (ch = 0; ch < priv->num_channels; ch++) ++ flush_channel(dev, ch, 0, 0); ++ ++ /* At this point, all completed channels have been processed. ++ * Unmask done interrupts for channels completed later on. ++ */ ++ out_be32(priv->reg + TALITOS_IMR, 0); ++ out_be32(priv->reg + TALITOS_IMR_LO, 0); ++ ++ out_be32(priv->reg + TALITOS_ICR, ++ TALITOS_ICR_CHERR | TALITOS_ICR_CHDONE); ++ out_be32(priv->reg + TALITOS_ICR_LO, ++ TALITOS_ICR_LO_CHERR | TALITOS_ICR_LO_CHDONE); ++} ++ ++/* ++ * locate current (offending) descriptor ++ */ ++static struct talitos_desc *current_desc(struct device *dev, int ch) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ int tail = priv->chan[ch].tail; ++ dma_addr_t cur_desc; ++ ++ cur_desc = in_be32(priv->reg + TALITOS_CDPR(ch)); ++ ++ while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) { ++ tail = (tail + 1) & (priv->fifo_len - 1); ++ if (tail == priv->chan[ch].tail) { ++ dev_err(dev, "couldn't locate current descriptor\n"); ++ return NULL; ++ } ++ } ++ ++ return priv->chan[ch].fifo[tail].desc; ++} ++ ++/* ++ * user diagnostics; report root cause of error based on execution unit status ++ */ ++static void report_eu_error(struct device *dev, int ch, ++ struct talitos_desc *desc) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ int i; ++ ++ switch (desc->hdr & DESC_HDR_SEL0_MASK) { ++ case DESC_HDR_SEL0_AFEU: ++ dev_err(dev, "AFEUISR 0x%08x\n", ++ in_be32(priv->reg + TALITOS_AFEUISR)); ++ break; ++ case DESC_HDR_SEL0_DEU: ++ dev_err(dev, "DEUISR 0x%08x\n", ++ in_be32(priv->reg + TALITOS_DEUISR)); ++ break; ++ case DESC_HDR_SEL0_MDEU: ++ dev_err(dev, "MDEUISR 0x%08x\n", ++ in_be32(priv->reg + TALITOS_MDEUISR)); ++ break; ++ case DESC_HDR_SEL0_RNG: ++ dev_err(dev, "RNGISR 0x%08x\n", ++ in_be32(priv->reg + TALITOS_RNGISR)); ++ break; ++ case DESC_HDR_SEL0_AESU: ++ dev_err(dev, "AESUISR 0x%08x\n", ++ in_be32(priv->reg + TALITOS_AESUISR)); ++ break; ++ } ++ ++ switch (desc->hdr & DESC_HDR_SEL1_MASK) { ++ case DESC_HDR_SEL1_MDEU: ++ dev_err(dev, "MDEUISR 0x%08x\n", ++ in_be32(priv->reg + TALITOS_MDEUISR)); ++ break; ++ } ++ ++ for (i = 0; i < 8; i++) ++ dev_err(dev, "DESCBUF 0x%08x\n", ++ in_be32(priv->reg + TALITOS_DESCBUF(ch) + 8 * i)); ++} ++ ++/* ++ * recover from error interrupts ++ */ ++static void talitos_error(unsigned long data, u32 isr, u32 isr_lo) ++{ ++ struct device *dev = (struct device *)data; ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ int ch, error, reset_ch = 0; ++ u32 v, v_lo; ++ ++ for (ch = 0; ch < priv->num_channels; ch++) { ++ /* skip channels without errors */ ++ if (!((isr >> 29) & (1 << (ch * 2)))) ++ continue; ++ ++ error = -EINVAL; ++ ++ v = in_be32(priv->reg + TALITOS_CCPSR(ch)); ++ v_lo = in_be32(priv->reg + TALITOS_CCPSR_LO(ch)); ++ ++ if (v_lo & TALITOS_CCPSR_LO_TEA) ++ dev_err(dev, "master data transfer error\n"); ++ if (v_lo & TALITOS_CCPSR_LO_PERR) ++ dev_err(dev, "fetch pointer not complete error\n"); ++ if (v_lo & TALITOS_CCPSR_LO_DERR) ++ dev_err(dev, "illegal descriptor header error\n"); ++ if (v_lo & TALITOS_CCPSR_LO_SERR) ++ dev_err(dev, "static assignment error\n"); ++ if (v_lo & TALITOS_CCPSR_LO_EUERR) ++ report_eu_error(dev, ch, current_desc(dev, ch)); ++ ++ flush_channel(dev, ch, error, reset_ch); ++ ++ if (reset_ch) ++ reset_channel(dev, ch); ++ } ++ ++ /* purge request queues */ ++ for (ch = 0; ch < priv->num_channels; ch++) ++ flush_channel(dev, ch, -EIO, 1); ++ ++ /* reset and reinitialize the device */ ++ init_device(dev); ++} ++ ++static irqreturn_t talitos_interrupt(int irq, void *data) ++{ ++ struct device *dev = data; ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ u32 isr, isr_lo; ++ ++ isr = in_be32(priv->reg + TALITOS_ISR); ++ isr_lo = in_be32(priv->reg + TALITOS_ISR_LO); ++ /* Acknowledge interrupt */ ++ out_be32(priv->reg + TALITOS_ICR, isr); ++ out_be32(priv->reg + TALITOS_ICR_LO, isr_lo); ++ ++ if (unlikely(isr & ~TALITOS_ISR_CHDONE)) { ++ talitos_error((unsigned long)data, isr, isr_lo); ++ } else if (likely(isr & TALITOS_ISR_CHDONE)) { ++ /* mask further done interrupts. */ ++ setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE); ++ /* done_task will unmask done interrupts at exit */ ++ tasklet_schedule(&priv->done_task); ++ } ++ ++ return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE; ++} ++ ++ ++/* ++ * crypto alg ++ */ ++#define TALITOS_CRA_PRIORITY 3000 ++#define TALITOS_MAX_KEY_SIZE 64 ++#define TALITOS_MAX_IV_LENGTH 16 ++#define TALITOS_MAX_OUTPUTDATA_SIZE 64 ++#define TALITOS_MAX_INPUTDATA_SIZE 64 ++ ++#define ARC4_MIN_KEY_SIZE 4 ++#define ARC4_MAX_KEY_SIZE 16 ++#define ARC4_BLOCK_SIZE 64 ++#define MD5_BLOCK_SIZE 64 ++ ++struct talitos_ctx { ++ struct device *dev; ++ __be32 desc_hdr_template; ++ u8 key[TALITOS_MAX_KEY_SIZE]; ++ u8 iv[TALITOS_MAX_IV_LENGTH]; ++ unsigned int keylen; ++ unsigned int enckeylen; ++ unsigned int authkeylen; ++ unsigned int authsize; ++}; ++ ++#define HASH_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE ++#define TALITOS_MDEU_MAX_CONTEXT_SIZE \ ++ TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256 ++ ++struct talitos_ahash_req_ctx { ++ u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)]; ++ unsigned int hw_context_size; ++ u8 buf[HASH_MAX_BLOCK_SIZE]; ++ u8 bufnext[HASH_MAX_BLOCK_SIZE]; ++ unsigned int swinit; ++ unsigned int first; ++ unsigned int last; ++ unsigned int to_hash_later; ++ u64 nbuf; ++ struct scatterlist bufsl[2]; ++ struct scatterlist *psrc; ++}; ++ ++/* ++ * talitos_edesc - s/w-extended descriptor ++ * @src_nents: number of segments in input scatterlist ++ * @dst_nents: number of segments in output scatterlist ++ * @desc: h/w descriptor ++ * ++ * if decrypting (with authcheck), or either one of src_nents or dst_nents ++ * is greater than 1, an integrity check value is concatenated to the end ++ * of link_tbl data ++ */ ++struct talitos_edesc { ++ int src_nents; ++ int dst_nents; ++ int src_is_chained; ++ int dst_is_chained; ++ struct talitos_desc desc; ++ u8 src_buf[TALITOS_MAX_INPUTDATA_SIZE]; ++ u8 dst_buf[TALITOS_MAX_OUTPUTDATA_SIZE]; ++}; ++ ++static int talitos_map_sg(struct device *dev, struct scatterlist *sg, ++ unsigned int nents, enum dma_data_direction dir, ++ int chained) ++{ ++ if (unlikely(chained)) ++ while (sg) { ++ dma_map_sg(dev, sg, 1, dir); ++ sg = scatterwalk_sg_next(sg); ++ } ++ else ++ dma_map_sg(dev, sg, nents, dir); ++ return nents; ++} ++ ++static void talitos_unmap_sg_chain(struct device *dev, struct scatterlist *sg, ++ enum dma_data_direction dir) ++{ ++ while (sg) { ++ dma_unmap_sg(dev, sg, 1, dir); ++ sg = scatterwalk_sg_next(sg); ++ } ++} ++ ++static void talitos_sg_unmap(struct device *dev, ++ struct talitos_edesc *edesc, ++ struct scatterlist *src, ++ struct scatterlist *dst) ++{ ++ unsigned int src_nents = edesc->src_nents ? : 1; ++ unsigned int dst_nents = edesc->dst_nents ? : 1; ++ ++ if (src != dst) { ++ if (edesc->src_is_chained) ++ talitos_unmap_sg_chain(dev, src, DMA_TO_DEVICE); ++ else ++ dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); ++ ++ if (dst) { ++ if (edesc->dst_is_chained) ++ talitos_unmap_sg_chain(dev, dst, ++ DMA_FROM_DEVICE); ++ else ++ dma_unmap_sg(dev, dst, dst_nents, ++ DMA_FROM_DEVICE); ++ } ++ } else ++ if (edesc->src_is_chained) ++ talitos_unmap_sg_chain(dev, src, DMA_BIDIRECTIONAL); ++ else ++ dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); ++} ++ ++/* ++ * derive number of elements in scatterlist ++ */ ++static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained) ++{ ++ struct scatterlist *sg = sg_list; ++ int sg_nents = 0; ++ ++ *chained = 0; ++ while (nbytes > 0) { ++ sg_nents++; ++ nbytes -= sg->length; ++ if (!sg_is_last(sg) && (sg + 1)->length == 0) ++ *chained = 1; ++ sg = scatterwalk_sg_next(sg); ++ } ++ ++ return sg_nents; ++} ++ ++/** ++ * sg_copy_end_to_buffer - Copy end data from SG list to a linear buffer ++ * @sgl: The SG list ++ * @nents: Number of SG entries ++ * @buf: Where to copy to ++ * @buflen: The number of bytes to copy ++ * @skip: The number of bytes to skip before copying. ++ * Note: skip + buflen should equal SG total size. ++ * ++ * Returns the number of copied bytes. ++ * ++ **/ ++static size_t sg_copy_end_to_buffer(struct scatterlist *sgl, unsigned int nents, ++ void *buf, size_t buflen, unsigned int skip) ++{ ++ unsigned int offset = 0; ++ unsigned int boffset = 0; ++ struct sg_mapping_iter miter; ++ unsigned long flags; ++ unsigned int sg_flags = SG_MITER_ATOMIC; ++ size_t total_buffer = buflen + skip; ++ ++ sg_flags |= SG_MITER_FROM_SG; ++ ++ sg_miter_start(&miter, sgl, nents, sg_flags); ++ ++ local_irq_save(flags); ++ ++ while (sg_miter_next(&miter) && offset < total_buffer) { ++ unsigned int len; ++ unsigned int ignore; ++ ++ if ((offset + miter.length) > skip) { ++ if (offset < skip) { ++ /* Copy part of this segment */ ++ ignore = skip - offset; ++ len = miter.length - ignore; ++ if (boffset + len > buflen) ++ len = buflen - boffset; ++ memcpy(buf + boffset, miter.addr + ignore, len); ++ } else { ++ /* Copy all of this segment (up to buflen) */ ++ len = miter.length; ++ if (boffset + len > buflen) ++ len = buflen - boffset; ++ memcpy(buf + boffset, miter.addr, len); ++ } ++ boffset += len; ++ } ++ offset += miter.length; ++ } ++ ++ sg_miter_stop(&miter); ++ ++ local_irq_restore(flags); ++ return boffset; ++} ++ ++/* ++ * allocate and map the extended descriptor ++ */ ++static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, ++ struct scatterlist *src, ++ struct scatterlist *dst, ++ int hash_result, ++ unsigned int cryptlen, ++ unsigned int authsize, ++ int icv_stashing, ++ u32 cryptoflags) ++{ ++ struct talitos_edesc *edesc; ++ int src_nents, dst_nents, alloc_len; ++ int src_chained, dst_chained = 0; ++ gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : ++ GFP_ATOMIC; ++ ++ if (cryptlen + authsize > TALITOS_MAX_DATA_LEN) { ++ dev_err(dev, "length exceeds h/w max limit\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ src_nents = sg_count(src, cryptlen + authsize, &src_chained); ++ src_nents = (src_nents == 1) ? 0 : src_nents; ++ ++ if (hash_result) { ++ dst_nents = 0; ++ } else { ++ if (dst == src) { ++ dst_nents = src_nents; ++ } else { ++ dst_nents = sg_count(dst, cryptlen + authsize, ++ &dst_chained); ++ dst_nents = (dst_nents == 1) ? 0 : dst_nents; ++ } ++ } ++ ++ /* ++ * allocate space for base edesc plus the link tables, ++ * allowing for two separate entries for ICV and generated ICV (+ 2), ++ * and the ICV data itself ++ */ ++ alloc_len = sizeof(struct talitos_edesc); ++ ++ edesc = kmalloc(alloc_len, GFP_KERNEL | flags); ++ if (!edesc) { ++ dev_err(dev, "could not allocate edescriptor\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->src_is_chained = src_chained; ++ edesc->dst_is_chained = dst_chained; ++ return edesc; ++} ++ ++static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, ++ const u8 *key, unsigned int keylen) ++{ ++ struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); ++ struct ablkcipher_alg *alg = crypto_ablkcipher_alg(cipher); ++ ++ if (keylen > TALITOS_MAX_KEY_SIZE) ++ goto badkey; ++ ++ if (keylen < alg->min_keysize || keylen > alg->max_keysize) ++ goto badkey; ++ ++ memcpy(&ctx->key, key, keylen); ++ ctx->keylen = keylen; ++ ++ return 0; ++ ++badkey: ++ crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++} ++ ++static void common_nonsnoop_unmap(struct device *dev, ++ struct talitos_edesc *edesc, ++ struct ablkcipher_request *areq) ++{ ++ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE); ++ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE); ++ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], DMA_TO_DEVICE); ++ ++ talitos_sg_unmap(dev, edesc, areq->src, areq->dst); ++} ++ ++static void ablkcipher_done(struct device *dev, ++ struct talitos_desc *desc, void *context, ++ int err) ++{ ++ struct ablkcipher_request *areq = context; ++ struct talitos_edesc *edesc; ++ ++ edesc = container_of(desc, struct talitos_edesc, desc); ++ ++ if (edesc->dst_nents != 0) ++ sg_copy_from_buffer(areq->dst, edesc->dst_nents, ++ edesc->dst_buf, areq->nbytes); ++ ++ common_nonsnoop_unmap(dev, edesc, areq); ++ ++ kfree(edesc); ++ ++ areq->base.complete(&areq->base, err); ++} ++ ++static int common_nonsnoop(struct talitos_edesc *edesc, ++ struct ablkcipher_request *areq, ++ u8 *giv, ++ void (*callback) (struct device *dev, ++ struct talitos_desc *desc, ++ void *context, int error)) ++{ ++ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); ++ struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); ++ struct device *dev = ctx->dev; ++ struct talitos_desc *desc = &edesc->desc; ++ unsigned int cryptlen = areq->nbytes; ++ unsigned int ivsize; ++ int sg_count, ret; ++ ++ desc->next_hdr = 0; ++ ++ /* first DWORD empty */ ++ desc->ptr[0] = zero_entry; ++ ++ /* cipher iv */ ++ ivsize = crypto_ablkcipher_ivsize(cipher); ++ map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, giv ?: areq->info, 0, ++ DMA_TO_DEVICE); ++ ++ /* AFEU using a key */ ++ if (((desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AFEU) && ++ ((desc->hdr & DESC_HDR_MODE0_MASK) == ++ DESC_HDR_MODE0_AFEU_USE_KEY)) ++ desc->ptr[1] = zero_entry; ++ ++ /* cipher key */ ++ map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen, ++ (char *)&ctx->key, 0, DMA_TO_DEVICE); ++ ++ /* AFEU using context */ ++ if (((desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AFEU) && ++ ((desc->hdr & DESC_HDR_MODE0_MASK) == ++ DESC_HDR_MODE0_AFEU_USE_CONTEXT)) ++ desc->ptr[2] = zero_entry; ++ ++ /* ++ * cipher in ++ */ ++ desc->ptr[3].len = cpu_to_be16(cryptlen); ++ ++ sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1, ++ (areq->src == areq->dst) ? DMA_BIDIRECTIONAL ++ : DMA_TO_DEVICE, ++ edesc->src_is_chained); ++ ++ if (sg_count == 1) ++ desc->ptr[3].ptr = sg_dma_address(areq->src); ++ else { ++ sg_copy_to_buffer(areq->src, sg_count, edesc->src_buf, ++ desc->ptr[3].len); ++ desc->ptr[3].ptr = (u32)edesc->src_buf; ++ } ++ ++ /* cipher out */ ++ desc->ptr[4].len = cpu_to_be16(cryptlen); ++ ++ if (areq->src != areq->dst) ++ sg_count = talitos_map_sg(dev, areq->dst, ++ edesc->dst_nents ? : 1, ++ DMA_FROM_DEVICE, ++ edesc->dst_is_chained); ++ ++ if (sg_count == 1) ++ desc->ptr[4].ptr = sg_dma_address(areq->dst); ++ else ++ desc->ptr[4].ptr = (u32)edesc->dst_buf; ++ ++ /* iv out */ ++ map_single_talitos_ptr(dev, &desc->ptr[5], ivsize, ctx->iv, 0, ++ DMA_FROM_DEVICE); ++ ++ /* last DWORD empty */ ++ desc->ptr[6] = zero_entry; ++ ++ ret = talitos_submit(dev, desc, callback, areq); ++ if (ret != -EINPROGRESS) { ++ common_nonsnoop_unmap(dev, edesc, areq); ++ kfree(edesc); ++ } ++ return ret; ++} ++ ++static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request * ++ areq) ++{ ++ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); ++ struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); ++ ++ return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, 0, ++ areq->nbytes, 0, 0, areq->base.flags); ++} ++ ++static int ablkcipher_encrypt(struct ablkcipher_request *areq) ++{ ++ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); ++ struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); ++ struct talitos_edesc *edesc; ++ ++ /* allocate extended descriptor */ ++ edesc = ablkcipher_edesc_alloc(areq); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ /* set encrypt except AFEU */ ++ if ((ctx->desc_hdr_template & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AFEU) ++ edesc->desc.hdr = ctx->desc_hdr_template; ++ else ++ edesc->desc.hdr = ctx->desc_hdr_template | ++ DESC_HDR_MODE0_ENCRYP; ++ ++ return common_nonsnoop(edesc, areq, NULL, ablkcipher_done); ++} ++ ++static int ablkcipher_decrypt(struct ablkcipher_request *areq) ++{ ++ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); ++ struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); ++ struct talitos_edesc *edesc; ++ ++ /* allocate extended descriptor */ ++ edesc = ablkcipher_edesc_alloc(areq); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; ++ ++ return common_nonsnoop(edesc, areq, NULL, ablkcipher_done); ++} ++ ++static void common_nonsnoop_hash_unmap(struct device *dev, ++ struct talitos_edesc *edesc, ++ struct ahash_request *areq) ++{ ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE); ++ ++ /* When using hashctx-in, must unmap it. */ ++ if (edesc->desc.ptr[1].len) ++ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], ++ DMA_TO_DEVICE); ++ ++ if (edesc->desc.ptr[2].len) ++ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], ++ DMA_TO_DEVICE); ++ ++ talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL); ++} ++ ++static void ahash_done(struct device *dev, ++ struct talitos_desc *desc, void *context, ++ int err) ++{ ++ struct ahash_request *areq = context; ++ struct talitos_edesc *edesc = ++ container_of(desc, struct talitos_edesc, desc); ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ if (!req_ctx->last && req_ctx->to_hash_later) { ++ /* Position any partial block for next update/final/finup */ ++ memcpy(req_ctx->buf, req_ctx->bufnext, req_ctx->to_hash_later); ++ req_ctx->nbuf = req_ctx->to_hash_later; ++ } ++ common_nonsnoop_hash_unmap(dev, edesc, areq); ++ ++ kfree(edesc); ++ ++ areq->base.complete(&areq->base, err); ++} ++ ++static int common_nonsnoop_hash(struct talitos_edesc *edesc, ++ struct ahash_request *areq, unsigned int length, ++ void (*callback) (struct device *dev, ++ struct talitos_desc *desc, ++ void *context, int error)) ++{ ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); ++ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ struct device *dev = ctx->dev; ++ struct talitos_desc *desc = &edesc->desc; ++ int sg_count, ret; ++ ++ desc->next_hdr = 0; ++ ++ /* first DWORD empty */ ++ desc->ptr[0] = zero_entry; ++ ++ /* hash context in */ ++ if (!req_ctx->first || req_ctx->swinit) { ++ map_single_talitos_ptr(dev, &desc->ptr[1], ++ req_ctx->hw_context_size, ++ (char *)req_ctx->hw_context, 0, ++ DMA_TO_DEVICE); ++ req_ctx->swinit = 0; ++ } else { ++ desc->ptr[1] = zero_entry; ++ /* Indicate next op is not the first. */ ++ req_ctx->first = 0; ++ } ++ ++ /* HMAC key */ ++ if (ctx->keylen) ++ map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen, ++ (char *)&ctx->key, 0, DMA_TO_DEVICE); ++ else ++ desc->ptr[2] = zero_entry; ++ ++ /* ++ * data in ++ */ ++ desc->ptr[3].len = length; ++ sg_count = talitos_map_sg(dev, req_ctx->psrc, ++ edesc->src_nents ? : 1, ++ DMA_TO_DEVICE, ++ edesc->src_is_chained); ++ ++ if (sg_count == 1) ++ desc->ptr[3].ptr = sg_dma_address(req_ctx->psrc); ++ else { ++ sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->src_buf, ++ desc->ptr[3].len); ++ desc->ptr[3].ptr = (u32)edesc->src_buf; ++ } ++ ++ /* fifth DWORD empty */ ++ desc->ptr[4] = zero_entry; ++ ++ /* hash/HMAC out -or- hash context out */ ++ if (req_ctx->last) ++ map_single_talitos_ptr(dev, &desc->ptr[5], ++ crypto_ahash_digestsize(tfm), ++ areq->result, 0, DMA_FROM_DEVICE); ++ else ++ map_single_talitos_ptr(dev, &desc->ptr[5], ++ req_ctx->hw_context_size, ++ req_ctx->hw_context, 0, DMA_FROM_DEVICE); ++ ++ /* last DWORD empty */ ++ desc->ptr[6] = zero_entry; ++ ++ ret = talitos_submit(dev, desc, callback, areq); ++ if (ret != -EINPROGRESS) { ++ common_nonsnoop_hash_unmap(dev, edesc, areq); ++ kfree(edesc); ++ } ++ return ret; ++} ++ ++static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq, ++ unsigned int nbytes) ++{ ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); ++ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, 1, ++ nbytes, 0, 0, areq->base.flags); ++} ++ ++static int ahash_init(struct ahash_request *areq) ++{ ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ /* Initialize the context */ ++ req_ctx->nbuf = 0; ++ req_ctx->first = 1; /* first indicates h/w must init its context */ ++ req_ctx->swinit = 0; /* assume h/w init of context */ ++ req_ctx->hw_context_size = ++ (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE) ++ ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256 ++ : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512; ++ ++ return 0; ++} ++ ++/* ++ * on h/w without explicit sha224 support, we initialize h/w context ++ * manually with sha224 constants, and tell it to run sha256. ++ */ ++static int ahash_init_sha224_swinit(struct ahash_request *areq) ++{ ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ ahash_init(areq); ++ req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/ ++ ++ req_ctx->hw_context[0] = SHA224_H0; ++ req_ctx->hw_context[1] = SHA224_H1; ++ req_ctx->hw_context[2] = SHA224_H2; ++ req_ctx->hw_context[3] = SHA224_H3; ++ req_ctx->hw_context[4] = SHA224_H4; ++ req_ctx->hw_context[5] = SHA224_H5; ++ req_ctx->hw_context[6] = SHA224_H6; ++ req_ctx->hw_context[7] = SHA224_H7; ++ ++ /* init 64-bit count */ ++ req_ctx->hw_context[8] = 0; ++ req_ctx->hw_context[9] = 0; ++ ++ return 0; ++} ++ ++static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) ++{ ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); ++ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ struct talitos_edesc *edesc; ++ unsigned int blocksize = ++ crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); ++ unsigned int nbytes_to_hash; ++ unsigned int to_hash_later; ++ unsigned int nsg; ++ int chained; ++ ++ if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) { ++ /* Buffer up to one whole block */ ++ sg_copy_to_buffer(areq->src, ++ sg_count(areq->src, nbytes, &chained), ++ req_ctx->buf + req_ctx->nbuf, nbytes); ++ req_ctx->nbuf += nbytes; ++ return 0; ++ } ++ ++ /* At least (blocksize + 1) bytes are available to hash */ ++ nbytes_to_hash = nbytes + req_ctx->nbuf; ++ to_hash_later = nbytes_to_hash & (blocksize - 1); ++ ++ if (req_ctx->last) ++ to_hash_later = 0; ++ else if (to_hash_later) ++ /* There is a partial block. Hash the full block(s) now */ ++ nbytes_to_hash -= to_hash_later; ++ else { ++ /* Keep one block buffered */ ++ nbytes_to_hash -= blocksize; ++ to_hash_later = blocksize; ++ } ++ ++ /* Chain in any previously buffered data */ ++ if (req_ctx->nbuf) { ++ nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1; ++ sg_init_table(req_ctx->bufsl, nsg); ++ sg_set_buf(req_ctx->bufsl, req_ctx->buf, req_ctx->nbuf); ++ if (nsg > 1) ++ scatterwalk_sg_chain(req_ctx->bufsl, 2, areq->src); ++ req_ctx->psrc = req_ctx->bufsl; ++ } else ++ req_ctx->psrc = areq->src; ++ ++ if (to_hash_later) { ++ int nents = sg_count(areq->src, nbytes, &chained); ++ sg_copy_end_to_buffer(areq->src, nents, ++ req_ctx->bufnext, ++ to_hash_later, ++ nbytes - to_hash_later); ++ } ++ req_ctx->to_hash_later = to_hash_later; ++ ++ /* Allocate extended descriptor */ ++ edesc = ahash_edesc_alloc(areq, nbytes_to_hash); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ edesc->desc.hdr = ctx->desc_hdr_template; ++ ++ /* On last one, request SEC to pad; otherwise continue */ ++ if (req_ctx->last) ++ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD; ++ else ++ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT; ++ ++ /* request SEC to INIT hash. */ ++ if (req_ctx->first && !req_ctx->swinit) ++ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT; ++ ++ /* When the tfm context has a keylen, it's an HMAC. ++ * A first or last (ie. not middle) descriptor must request HMAC. ++ */ ++ if (ctx->keylen && (req_ctx->first || req_ctx->last)) ++ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC; ++ ++ return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ++ ahash_done); ++} ++ ++static int ahash_update(struct ahash_request *areq) ++{ ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ req_ctx->last = 0; ++ ++ return ahash_process_req(areq, areq->nbytes); ++} ++ ++static int ahash_final(struct ahash_request *areq) ++{ ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ req_ctx->last = 1; ++ ++ return ahash_process_req(areq, 0); ++} ++ ++static int ahash_finup(struct ahash_request *areq) ++{ ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ ++ req_ctx->last = 1; ++ ++ return ahash_process_req(areq, areq->nbytes); ++} ++ ++static int ahash_digest(struct ahash_request *areq) ++{ ++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); ++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); ++ ++ ahash->init(areq); ++ req_ctx->last = 1; ++ ++ return ahash_process_req(areq, areq->nbytes); ++} ++ ++struct talitos_alg_template { ++ u32 type; ++ union { ++ struct crypto_alg crypto; ++ struct ahash_alg hash; ++ } alg; ++ __be32 desc_hdr_template; ++}; ++ ++static struct talitos_alg_template driver_algs[] = { ++ /* ABLKCIPHER algorithms. */ ++ { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .alg.crypto = { ++ .cra_name = "ecb(arc4)", ++ .cra_driver_name = "ecb-arc4-talitos", ++ .cra_blocksize = ARC4_BLOCK_SIZE, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | ++ CRYPTO_ALG_ASYNC, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = ARC4_MIN_KEY_SIZE, ++ .max_keysize = ARC4_MAX_KEY_SIZE, ++ .ivsize = ARC4_BLOCK_SIZE, ++ } ++ }, ++ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_AFEU | ++ DESC_HDR_SEL0_AFEU | ++ DESC_HDR_MODE0_AFEU_USE_KEY, ++ }, ++ { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .alg.crypto = { ++ .cra_name = "cbc(aes)", ++ .cra_driver_name = "cbc-aes-talitos", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | ++ CRYPTO_ALG_ASYNC, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ } ++ }, ++ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | ++ DESC_HDR_SEL0_AESU | ++ DESC_HDR_MODE0_AESU_CBC, ++ }, ++ { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .alg.crypto = { ++ .cra_name = "cbc(des)", ++ .cra_driver_name = "cbc-des-talitos", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | ++ CRYPTO_ALG_ASYNC, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = DES_KEY_SIZE, ++ .max_keysize = DES_KEY_SIZE, ++ .ivsize = DES_BLOCK_SIZE, ++ } ++ }, ++ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | ++ DESC_HDR_SEL0_DEU | ++ DESC_HDR_MODE0_DEU_CBC, ++ }, ++ { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .alg.crypto = { ++ .cra_name = "cbc(des3_ede)", ++ .cra_driver_name = "cbc-3des-talitos", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | ++ CRYPTO_ALG_ASYNC, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = DES3_EDE_KEY_SIZE, ++ .max_keysize = DES3_EDE_KEY_SIZE, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ } ++ }, ++ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | ++ DESC_HDR_SEL0_DEU | ++ DESC_HDR_MODE0_DEU_CBC | ++ DESC_HDR_MODE0_DEU_3DES, ++ }, ++ /* AHASH algorithms. */ ++ { .type = CRYPTO_ALG_TYPE_AHASH, ++ .alg.hash = { ++ .init = ahash_init, ++ .update = ahash_update, ++ .final = ahash_final, ++ .finup = ahash_finup, ++ .digest = ahash_digest, ++ .halg.digestsize = MD5_DIGEST_SIZE, ++ .halg.base = { ++ .cra_name = "md5", ++ .cra_driver_name = "md5-talitos", ++ .cra_blocksize = MD5_BLOCK_SIZE, ++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | ++ CRYPTO_ALG_ASYNC, ++ .cra_type = &crypto_ahash_type ++ } ++ }, ++ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | ++ DESC_HDR_SEL0_MDEU | ++ DESC_HDR_MODE0_MDEU_MD5, ++ }, ++ { .type = CRYPTO_ALG_TYPE_AHASH, ++ .alg.hash = { ++ .init = ahash_init, ++ .update = ahash_update, ++ .final = ahash_final, ++ .finup = ahash_finup, ++ .digest = ahash_digest, ++ .halg.digestsize = SHA1_DIGEST_SIZE, ++ .halg.base = { ++ .cra_name = "sha1", ++ .cra_driver_name = "sha1-talitos", ++ .cra_blocksize = SHA1_BLOCK_SIZE, ++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | ++ CRYPTO_ALG_ASYNC, ++ .cra_type = &crypto_ahash_type ++ } ++ }, ++ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | ++ DESC_HDR_SEL0_MDEU | ++ DESC_HDR_MODE0_MDEU_SHA1, ++ }, ++}; ++ ++struct talitos_crypto_alg { ++ struct list_head entry; ++ struct device *dev; ++ struct talitos_alg_template algt; ++}; ++ ++static int talitos_cra_init(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg = tfm->__crt_alg; ++ struct talitos_crypto_alg *talitos_alg; ++ struct talitos_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH) ++ talitos_alg = container_of(__crypto_ahash_alg(alg), ++ struct talitos_crypto_alg, ++ algt.alg.hash); ++ else ++ talitos_alg = container_of(alg, struct talitos_crypto_alg, ++ algt.alg.crypto); ++ ++ /* update context with ptr to dev */ ++ ctx->dev = talitos_alg->dev; ++ ++ /* copy descriptor header template value */ ++ ctx->desc_hdr_template = talitos_alg->algt.desc_hdr_template; ++ ++ return 0; ++} ++ ++static int talitos_cra_init_ahash(struct crypto_tfm *tfm) ++{ ++ struct talitos_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ talitos_cra_init(tfm); ++ ++ ctx->keylen = 0; ++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), ++ sizeof(struct talitos_ahash_req_ctx)); ++ ++ return 0; ++} ++ ++/* ++ * given the alg's descriptor header template, determine whether descriptor ++ * type and primary/secondary execution units required match the hw ++ * capabilities description provided in the device tree node. ++ */ ++static int hw_supports(struct device *dev, __be32 desc_hdr_template) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = (DESC_TYPE(desc_hdr_template) & priv->desc_types) && ++ (PRIMARY_EU(desc_hdr_template) & priv->exec_units); ++ ++ if (SECONDARY_EU(desc_hdr_template)) ++ ret = ret && (SECONDARY_EU(desc_hdr_template) ++ & priv->exec_units); ++ ++ return ret; ++} ++ ++static int talitos_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ struct talitos_crypto_alg *t_alg, *n; ++ int i; ++ ++ list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) { ++ switch (t_alg->algt.type) { ++ case CRYPTO_ALG_TYPE_ABLKCIPHER: ++ case CRYPTO_ALG_TYPE_AEAD: ++ crypto_unregister_alg(&t_alg->algt.alg.crypto); ++ break; ++ case CRYPTO_ALG_TYPE_AHASH: ++ crypto_unregister_ahash(&t_alg->algt.alg.hash); ++ break; ++ } ++ list_del(&t_alg->entry); ++ kfree(t_alg); ++ } ++ ++ for (i = 0; i < priv->num_channels; i++) ++ kfree(priv->chan[i].fifo); ++ ++ kfree(priv->chan); ++ ++ if (priv->irq != 0) ++ free_irq(priv->irq, dev); ++ ++ tasklet_kill(&priv->done_task); ++ ++ iounmap(priv->reg); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ kfree(priv); ++ ++ return 0; ++} ++ ++static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, ++ struct talitos_alg_template ++ *template) ++{ ++ struct talitos_private *priv = dev_get_drvdata(dev); ++ struct talitos_crypto_alg *t_alg; ++ struct crypto_alg *alg; ++ ++ t_alg = kzalloc(sizeof(struct talitos_crypto_alg), GFP_KERNEL); ++ if (!t_alg) ++ return ERR_PTR(-ENOMEM); ++ ++ t_alg->algt = *template; ++ ++ switch (t_alg->algt.type) { ++ case CRYPTO_ALG_TYPE_ABLKCIPHER: ++ alg = &t_alg->algt.alg.crypto; ++ alg->cra_init = talitos_cra_init; ++ break; ++ case CRYPTO_ALG_TYPE_AHASH: ++ alg = &t_alg->algt.alg.hash.halg.base; ++ alg->cra_init = talitos_cra_init_ahash; ++ if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) && ++ !strcmp(alg->cra_name, "sha224")) { ++ t_alg->algt.alg.hash.init = ahash_init_sha224_swinit; ++ t_alg->algt.desc_hdr_template = ++ DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | ++ DESC_HDR_SEL0_MDEU | ++ DESC_HDR_MODE0_MDEU_SHA256; ++ } ++ break; ++ default: ++ dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ alg->cra_module = THIS_MODULE; ++ alg->cra_priority = TALITOS_CRA_PRIORITY; ++ alg->cra_alignmask = 0; ++ alg->cra_ctxsize = sizeof(struct talitos_ctx); ++ ++ t_alg->dev = dev; ++ ++ return t_alg; ++} ++ ++static int __devinit talitos_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct talitos_private *priv; ++ int prop; ++ struct resource *r; ++ int i, err; ++ ++ priv = kzalloc(sizeof(struct talitos_private), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ ++ priv->pdev = pdev; ++ ++ tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev); ++ ++ INIT_LIST_HEAD(&priv->alg_list); ++ ++ priv->irq = 64 + ISC_SEC; ++ /* get the irq line */ ++ err = request_irq(priv->irq, talitos_interrupt, IRQF_DISABLED, ++ dev_driver_string(dev), dev); ++ if (err) { ++ dev_err(dev, "failed to request irq %d\n", priv->irq); ++ goto err_out; ++ } else ++ MCF_ICR(ISC_SEC) = ILP_SEC; ++ ++ ++ /* get a pointer to the register memory */ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->reg = ioremap(r->start, (r->end - r->start)); ++ if (!priv->reg) ++ dev_err(dev, "failed to ioremap\n"); ++ ++ /* get SEC version capabilities from device tree */ ++ prop = in_be32(priv->reg + TALITOS_ID); ++ if (prop & TALITOS_ID_SEC_1_1) { ++ priv->num_channels = TALITOS_NCHANNELS_SEC_1_1; ++ priv->chfifo_len = TALITOS_CHFIFOLEN_SEC_1_1; ++ priv->exec_units = TALITOS_HAS_EUS_SEC_1_1; ++ priv->desc_types = TALITOS_HAS_DESCTYPES_SEC_1_1; ++ } else { ++ dev_err(dev, "failed to id device\n"); ++ goto err_out; ++ } ++ ++ priv->chan = kzalloc(sizeof(struct talitos_channel) * ++ priv->num_channels, GFP_KERNEL); ++ if (!priv->chan) { ++ dev_err(dev, "failed to allocate channel management space\n"); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ spin_lock_init(&priv->chan[i].head_lock); ++ spin_lock_init(&priv->chan[i].tail_lock); ++ } ++ ++ priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) * ++ priv->fifo_len, GFP_KERNEL); ++ if (!priv->chan[i].fifo) { ++ dev_err(dev, "failed to allocate request fifo %d\n", i); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ } ++ ++ for (i = 0; i < priv->num_channels; i++) ++ atomic_set(&priv->chan[i].submit_count, ++ -(priv->chfifo_len - 1)); ++ ++ dma_set_mask(dev, DMA_BIT_MASK(36)); ++ ++ /* reset and initialize the h/w */ ++ err = init_device(dev); ++ if (err) { ++ dev_err(dev, "failed to initialize device\n"); ++ goto err_out; ++ } ++ ++ /* register crypto algorithms the device supports */ ++ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { ++ if (hw_supports(dev, driver_algs[i].desc_hdr_template)) { ++ struct talitos_crypto_alg *t_alg; ++ char *name = NULL; ++ ++ t_alg = talitos_alg_alloc(dev, &driver_algs[i]); ++ if (IS_ERR(t_alg)) { ++ err = PTR_ERR(t_alg); ++ goto err_out; ++ } ++ ++ switch (t_alg->algt.type) { ++ case CRYPTO_ALG_TYPE_ABLKCIPHER: ++ case CRYPTO_ALG_TYPE_AEAD: ++ err = crypto_register_alg( ++ &t_alg->algt.alg.crypto); ++ name = t_alg->algt.alg.crypto.cra_driver_name; ++ break; ++ case CRYPTO_ALG_TYPE_AHASH: ++ err = crypto_register_ahash( ++ &t_alg->algt.alg.hash); ++ name = ++ t_alg->algt.alg.hash.halg.base.cra_driver_name; ++ break; ++ } ++ if (err) { ++ dev_err(dev, "%s alg registration failed\n", ++ name); ++ kfree(t_alg); ++ } else { ++ list_add_tail(&t_alg->entry, &priv->alg_list); ++ dev_info(dev, "%s\n", name); ++ } ++ } ++ } ++ ++ return 0; ++ ++err_out: ++ talitos_remove(pdev); ++ ++ return err; ++} ++ ++static struct platform_driver talitos_driver = { ++ .driver = { ++ .name = "talitos", ++ .owner = THIS_MODULE, ++ }, ++ .probe = talitos_probe, ++ .remove = talitos_remove, ++}; ++ ++static int __init talitos_init(void) ++{ ++ return platform_driver_register(&talitos_driver); ++} ++module_init(talitos_init); ++ ++static void __exit talitos_exit(void) ++{ ++ platform_driver_unregister(&talitos_driver); ++} ++module_exit(talitos_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Kim Phillips <kim.phillips@freescale.com>"); ++MODULE_DESCRIPTION("Freescale integrated security engine (SEC) driver"); +--- /dev/null ++++ b/drivers/crypto/cf_talitos.h +@@ -0,0 +1,229 @@ ++/* ++ * Freescale Coldfire SEC (talitos) device dependent data structures ++ * ++ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++/* device ID register values */ ++#define TALITOS_ID_SEC_1_1 (0x09000000) /* MCF547x and MCF548x */ ++ ++/* ++ * following num_channels, channel-fifo-depth, exec-unit-mask, and ++ * descriptor-types-mask are for forward-compatibility with openfirmware ++ * flat device trees ++ */ ++ ++/* ++ * num_channels : the number of channels available in each SEC version. ++ */ ++ ++/* n.b. this driver requires these values be a power of 2 */ ++#define TALITOS_NCHANNELS_SEC_1_1 2 ++ ++/* ++ * channel-fifo-depth : The number of descriptor ++ * pointers a channel fetch fifo can hold. ++ */ ++#define TALITOS_CHFIFOLEN_SEC_1_1 1 ++ ++/* the corresponding masks for each SEC version */ ++#define TALITOS_HAS_EUS_SEC_1_1 0x7 ++ ++/* the corresponding masks for each SEC version */ ++#define TALITOS_HAS_DESCTYPES_SEC_1_1 0xf ++ ++/* ++ * a TALITOS_xxx_HI address points to the low data bits (32-63) of the register ++ */ ++/* global register offset addresses */ ++/* EU Assaginment controller register is useless*/ ++#define TALITOS_EUACR 0x1000 ++#define TALITOS_EUACR_LO 0x1004 ++ ++#define TALITOS_IMR 0x1008 /* interrupt mask register */ ++#define TALITOS_IMR_ALL 0xf8000000 /* enable all interrupts mask */ ++#define TALITOS_IMR_ERR 0xa8000000 /* mask error interrupts */ ++#define TALITOS_IMR_DONE 0x50000000 /* mask done interrupts */ ++#define TALITOS_IMR_LO 0x100C /* interrupt mask register */ ++/* mask all channel interrupts mask */ ++#define TALITOS_IMR_LO_ALL 0x03333340 ++#define TALITOS_IMR_LO_ERR 0x02222240 /* mask error interrupts */ ++#define TALITOS_IMR_LO_DONE 0x01111100 /* mask done interrupts */ ++ ++#define TALITOS_ISR 0x1010 /* interrupt status register */ ++#define TALITOS_ISR_CHERR 0xa8000000 /* errors mask */ ++#define TALITOS_ISR_CHDONE 0x50000000 /* channel(s) done mask */ ++#define TALITOS_ISR_LO 0x1014 /* interrupt status register */ ++ ++#define TALITOS_ICR 0x1018 /* interrupt clear register */ ++#define TALITOS_ICR_CHERR 0xa8000000 /* errors enable */ ++#define TALITOS_ICR_CHDONE 0x50000000 /* channel(s) done enable */ ++#define TALITOS_ICR_LO 0x101C /* interrupt clear register */ ++#define TALITOS_ICR_LO_CHERR 0x02222240 /* errors enable */ ++#define TALITOS_ICR_LO_CHDONE 0x01111100 /* channel(s) done enable */ ++ ++#define TALITOS_ID 0x1020 ++ ++/* EU Assaginment status register is useless*/ ++#define TALITOS_EUASR 0x1028 ++#define TALITOS_EUASR_LO 0x102C ++ ++#define TALITOS_MCR 0x1030 /* master control register */ ++#define TALITOS_MCR_SWR 0x01000000 ++ ++#define TALITOS_MEAR 0x1038 ++ ++/* channel register address stride */ ++#define TALITOS_CH_STRIDE 0x1000 ++ ++/* channel register offset addresses and bits */ ++#define TALITOS_CCCR(ch) (ch * TALITOS_CH_STRIDE + 0x200c) ++#define TALITOS_CCCR_RESET 0x1 /* Channel Reset bit */ ++#define TALITOS_CCCR_CDWE 0x10 /* Channel done writeback enable bit */ ++#define TALITOS_CCCR_NE 0x8 /* Fetch Next Descriptor Enable bit */ ++#define TALITOS_CCCR_NT 0x4 /* Notification type bit */ ++#define TALITOS_CCCR_CDIE 0x2 /* Channel Done Interrupt Enable bit */ ++ ++/* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CCPSR(ch) (ch * TALITOS_CH_STRIDE + 0x2010) ++#define TALITOS_CCPSR_LO(ch) (ch * TALITOS_CH_STRIDE + 0x2014) ++#define TALITOS_CCPSR_LO_TEA 0x2000 /* Transfer error acknowledge */ ++#define TALITOS_CCPSR_LO_PERR 0x1000 /* Pointer not complete error */ ++#define TALITOS_CCPSR_LO_DERR 0x400 /* Descriptor error */ ++#define TALITOS_CCPSR_LO_SERR 0x200 /* Static assignment error */ ++#define TALITOS_CCPSR_LO_EUERR 0x100 /* EU error */ ++ ++/* channel fetch fifo register */ ++#define TALITOS_FF(ch) (ch * TALITOS_CH_STRIDE + 0x204c) ++ ++/* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CDPR(ch) (ch * TALITOS_CH_STRIDE + 0x2044) ++ ++/* Descriptor Buffer (debug) 0x2080-0x20BF*/ ++#define TALITOS_DESCBUF(ch) (ch * TALITOS_CH_STRIDE + 0x2080) ++ ++/* execution unit register offset addresses and bits */ ++#define TALITOS_DEURCR 0xa018 /* DEU reset control register */ ++#define TALITOS_DEURCR_RESET 0x01000000 /* DEU reset bit */ ++#define TALITOS_DEUSR 0xa028 /* DEU status register */ ++#define TALITOS_DEUSR_RESET 0x01000000 /* DEU Reset status bit */ ++#define TALITOS_DEUISR 0xa030 /* DEU interrupt status register */ ++#define TALITOS_DEUIMR 0xa038 /* DEU interrupt mask register */ ++#define TALITOS_DEUIMR_MASK 0xf63f0000 /* DEU interrupt control mask*/ ++#define TALITOS_DEUIMR_KPE_MASK 0x00200000 /* DEU interrupt KPE mask*/ ++ ++#define TALITOS_AESURCR 0x12018 /* AESU reset control register */ ++#define TALITOS_AESURCR_RESET 0x01000000 /* AESU reset bit */ ++#define TALITOS_AESUSR 0x12028 /* AESU status register */ ++#define TALITOS_AESUSR_RESET 0x01000000 /* AESU Reset status bit */ ++#define TALITOS_AESUISR 0x12030 /* AESU interrupt status register */ ++#define TALITOS_AESUIMR 0x12038 /* AESU interrupt mask register */ ++#define TALITOS_AESUIMR_MASK 0xf61f0000 /* AESU interrupt control mask*/ ++ ++#define TALITOS_MDEURCR 0xc018 /* MDEU reset control register */ ++#define TALITOS_MDEURCR_RESET 0x01000000 /* MDEU reset bit */ ++#define TALITOS_MDEUSR 0xc028 /* MDEU status register */ ++#define TALITOS_MDEUSR_RESET 0x01000000 /* MDEU Reset status bit */ ++#define TALITOS_MDEUISR 0xc030 /* MDEU interrupt status register */ ++#define TALITOS_MDEUIMR 0xc038 /* MDEU interrupt mask register */ ++#define TALITOS_MDEUIMR_MASK 0xc41f0000 /* MDEU interrupt control mask*/ ++ ++#define TALITOS_AFEURCR 0x8018 /* AFEU reset control register */ ++#define TALITOS_AFEURCR_RESET 0x01000000 /* AFEU reset bit */ ++#define TALITOS_AFEUSR 0x8028 /* AFEU status register */ ++#define TALITOS_AFEUSR_RESET 0x01000000 /* AFEU Reset status bit */ ++#define TALITOS_AFEUISR 0x8030 /* AFEU interrupt status register */ ++#define TALITOS_AFEUIMR 0x8038 /* AFEU interrupt mask register */ ++#define TALITOS_AFEUIMR_MASK 0xf61f0000 /* AFEU interrupt control mask*/ ++ ++#define TALITOS_RNGRCR 0xe018 /* RNG Reset control register */ ++#define TALITOS_RNGRCR_SR 0x01000000 /* RNG RNGRCR:Software Reset */ ++#define TALITOS_RNGSR 0xe028 /* RNG status register */ ++#define TALITOS_RNGSR_RD 0x01000000 /* RNG Reset done */ ++#define TALITOS_RNGISR 0xe030 /* RNG Interrupt status register */ ++#define TALITOS_RNGIMR 0xe038 /* RNG interrupt mask register */ ++#define TALITOS_RNGIMR_MASK 0xc2100000 /* RNG interrupt control mask*/ ++ ++#define TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256 0x28 ++#define TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512 0x48 ++ ++/***************************RC4*******************/ ++#define ARC4_SEC_MIN_KEY_SIZE 5 ++#define ARC4_SEC_MAX_KEY_SIZE 16 ++#define ARC4_SEC_CONTEXT_LEN 259 ++#define SEC_ALG_AFEU_KEY 0x10200050 ++#define SEC_ALG_AFEU_CONTEXT 0x10700050 ++ ++/* talitos descriptor header (hdr) bits */ ++ ++/* primary execution unit select */ ++#define DESC_HDR_SEL0_MASK 0xf0000000 ++#define DESC_HDR_SEL0_AFEU 0x10000000 ++#define DESC_HDR_SEL0_DEU 0x20000000 ++#define DESC_HDR_SEL0_MDEU 0x30000000 ++#define DESC_HDR_SEL0_RNG 0x40000000 ++#define DESC_HDR_SEL0_AESU 0x60000000 ++ ++/* primary execution unit mode (MODE0) and derivatives */ ++#define DESC_HDR_MODE0_MASK 0x0ff00000 ++#define DESC_HDR_MODE0_ENCRYP 0x00100000 ++#define DESC_HDR_MODE0_AFEU_USE_KEY 0x00200000 ++#define DESC_HDR_MODE0_AFEU_USE_CONTEXT 0x00700000 ++#define DESC_HDR_MODE0_AESU_CBC 0x00200000 ++#define DESC_HDR_MODE0_AESU_ENC 0x00100000 ++#define DESC_HDR_MODE0_DEU_CBC 0x00400000 ++#define DESC_HDR_MODE0_DEU_3DES 0x00200000 ++#define DESC_HDR_MODE0_DEU_ENC 0x00100000 ++#define DESC_HDR_MODE0_MDEU_CONT 0x08000000 ++#define DESC_HDR_MODE0_MDEU_INIT 0x01000000 /* init starting regs */ ++#define DESC_HDR_MODE0_MDEU_HMAC 0x00800000 ++#define DESC_HDR_MODE0_MDEU_PAD 0x00400000 /* PD */ ++#define DESC_HDR_MODE0_MDEU_MD5 0x00200000 ++#define DESC_HDR_MODE0_MDEU_SHA256 0x00100000 ++#define DESC_HDR_MODE0_MDEU_SHA1 0x00000000 /* SHA-160 */ ++#define DESC_HDR_MODE0_MDEU_MD5_HMAC \ ++ (DESC_HDR_MODE0_MDEU_MD5 | DESC_HDR_MODE0_MDEU_HMAC) ++#define DESC_HDR_MODE0_MDEU_SHA256_HMAC \ ++ (DESC_HDR_MODE0_MDEU_SHA256 | DESC_HDR_MODE0_MDEU_HMAC) ++#define DESC_HDR_MODE0_MDEU_SHA1_HMAC \ ++ (DESC_HDR_MODE0_MDEU_SHA1 | DESC_HDR_MODE0_MDEU_HMAC) ++ ++/* secondary execution unit select (SEL1) */ ++/* it's MDEU or nothing */ ++#define DESC_HDR_SEL1_MASK 0x000f0000 ++#define DESC_HDR_SEL1_MDEU 0x00030000 ++ ++/* secondary execution unit mode (MODE1) and derivatives */ ++#define DESC_HDR_MODE1_MDEU_INIT 0x00001000 /* init starting regs */ ++#define DESC_HDR_MODE1_MDEU_HMAC 0x00000800 ++#define DESC_HDR_MODE1_MDEU_PAD 0x00000400 /* PD */ ++#define DESC_HDR_MODE1_MDEU_MD5 0x00000200 ++#define DESC_HDR_MODE1_MDEU_SHA256 0x00000100 ++#define DESC_HDR_MODE1_MDEU_SHA1 0x00000000 /* SHA-160 */ ++#define DESC_HDR_MODE1_MDEU_MD5_HMAC \ ++ (DESC_HDR_MODE1_MDEU_MD5 | DESC_HDR_MODE1_MDEU_HMAC) ++#define DESC_HDR_MODE1_MDEU_SHA256_HMAC \ ++ (DESC_HDR_MODE1_MDEU_SHA256 | DESC_HDR_MODE1_MDEU_HMAC) ++#define DESC_HDR_MODE1_MDEU_SHA1_HMAC \ ++ (DESC_HDR_MODE1_MDEU_SHA1 | DESC_HDR_MODE1_MDEU_HMAC) ++ ++/* direction of overall data flow (DIR) */ ++#define DESC_HDR_DIR_OUTBOUND 0x00000000 ++#define DESC_HDR_DIR_INBOUND 0x00000002 ++ ++/* done notification (DN) */ ++#define DESC_HDR_DONE 0x00000001 ++ ++/* descriptor types */ ++#define DESC_HDR_TYPE_AESU_CTR_NONSNOOP (0 << 4) ++#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU (1 << 4) ++#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU (2 << 4) ++#define DESC_HDR_TYPE_NONHMAC_SNOOP_NO_AFEU (3 << 4) ++#define DESC_HDR_TYPE_COMMON_NONSNOOP_AFEU (5 << 4) ++ ++#define TALITOS_HDR_DONE_BITS 0xff000000 |