--- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -243,4 +243,75 @@ OMAP processors have SHA1/MD5 hw accelerator. Select this if you want to use the OMAP module for SHA1/MD5 algorithms. +config CRYPTO_DEV_LANTIQ + bool "Support for Lantiq crypto engine" + select CRYPTO_ALGAPI + default y + help + Will support Lantiq crypto hardware + If you are unsure, say M. + +menuconfig CRYPTO_DEV_LANTIQ_DES + bool "Lantiq crypto hardware for DES algorithm" + depends on CRYPTO_DEV_LANTIQ + select CRYPTO_BLKCIPHER + default y + help + Use crypto hardware for DES/3DES algorithm. + If unsure say N. + +menuconfig CRYPTO_DEV_LANTIQ_AES + bool "Lantiq crypto hardware for AES algorithm" + depends on CRYPTO_DEV_LANTIQ + select CRYPTO_BLKCIPHER + default y + help + Use crypto hardware for AES algorithm. + If unsure say N. + +menuconfig CRYPTO_DEV_LANTIQ_ARC4 + bool "Lantiq crypto hardware for ARC4 algorithm" + depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9) + select CRYPTO_BLKCIPHER + default y + help + Use crypto hardware for ARC4 algorithm. + If unsure say N. + +menuconfig CRYPTO_DEV_LANTIQ_MD5 + bool "Lantiq crypto hardware for MD5 algorithm" + depends on CRYPTO_DEV_LANTIQ + select CRYPTO_BLKCIPHER + default y + help + Use crypto hardware for MD5 algorithm. + If unsure say N. + +menuconfig CRYPTO_DEV_LANTIQ_SHA1 + bool "Lantiq crypto hardware for SHA1 algorithm" + depends on CRYPTO_DEV_LANTIQ + select CRYPTO_BLKCIPHER + default y + help + Use crypto hardware for SHA1 algorithm. + If unsure say N. + +menuconfig CRYPTO_DEV_LANTIQ_SHA1_HMAC + bool "Lantiq crypto hardware for SHA1_HMAC algorithm" + depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9) + select CRYPTO_BLKCIPHER + default y + help + Use crypto hardware for SHA1_HMAC algorithm. + If unsure say N. + +menuconfig CRYPTO_DEV_LANTIQ_MD5_HMAC + bool "Lantiq crypto hardware for MD5_HMAC algorithms" + depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9) + select CRYPTO_BLKCIPHER + default y + help + Use crypto hardware for MD5_HMAC algorithm. + If unsure say N. + endif # CRYPTO_HW --- /dev/null +++ b/drivers/crypto/lantiq/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_falcon.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_danube.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_ar9.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ_DES) += des.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ_AES) += aes.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) += arc4.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ_SHA1) += sha1.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC) += sha1_hmac.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ_MD5) += md5.o +obj-$(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC) += md5_hmac.o --- /dev/null +++ b/drivers/crypto/lantiq/aes.c @@ -0,0 +1,1029 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file aes.c + \ingroup LQ_DEU + \brief AES Encryption Driver main file +*/ + +/** + \defgroup LQ_AES_FUNCTIONS LQ_AES_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq AES driver Functions +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "deu.h" + +#ifdef CONFIG_CRYPTO_DEV_DMA +# include "deu_dma.h" +#endif + +static spinlock_t cipher_lock; + +/* Definition of constants */ + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 +#define AES_BLOCK_SIZE 16 +#define CTR_RFC3686_NONCE_SIZE 4 +#define CTR_RFC3686_IV_SIZE 8 +#define CTR_RFC3686_MAX_KEY_SIZE (AES_MAX_KEY_SIZE \ + + CTR_RFC3686_NONCE_SIZE) + +struct aes_ctx { + int key_length; + u32 buf[AES_MAX_KEY_SIZE]; + u8 nonce[CTR_RFC3686_NONCE_SIZE]; +}; + +/** \fn int aes_set_key(struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len) + * \ingroup LQ_AES_FUNCTIONS + * \brief sets the AES keys + * \param tfm linux crypto algo transform + * \param in_key input key + * \param key_len key lengths of 16, 24 and 32 bytes supported + * \return -EINVAL - bad key length, 0 - SUCCESS +*/ +static int aes_set_key(struct crypto_tfm *tfm, + const u8 *in_key, + unsigned int key_len) +{ + struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + + DPRINTF(0, "ctx @%p, key_len %d\n", ctx, key_len); + + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->key_length = key_len; + memcpy((u8 *)(ctx->buf), in_key, key_len); + + return 0; +} + +#ifndef CONFIG_CRYPTO_DEV_DMA +/** \fn void deu_aes(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode) + * \ingroup LQ_AES_FUNCTIONS + * \brief main interface to AES hardware + * \param ctx_arg crypto algo context + * \param out_arg output bytestream + * \param in_arg input bytestream + * \param iv_arg initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param mode operation mode such as ebc, cbc, ctr + * +*/ +static void deu_aes(void *ctx_arg, + u8 *out_arg, + const u8 *in_arg, + u8 *iv_arg, + size_t nbytes, + int encdec, + int mode) +#else + +/** \fn void deu_aes_core(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode) + * \ingroup LQ_AES_FUNCTIONS + * \brief main interface to AES hardware + * \param ctx_arg crypto algo context + * \param out_arg output bytestream + * \param in_arg input bytestream + * \param iv_arg initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param mode operation mode such as ebc, cbc, ctr + * +*/ +static void deu_aes_core(void *ctx_arg, + u8 *out_arg, + const u8 *in_arg, + u8 *iv_arg, + size_t nbytes, + int encdec, + int mode) +#endif + +{ + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + volatile struct deu_aes *aes = (volatile struct deu_aes *)AES_START; + struct aes_ctx *ctx = (struct aes_ctx *)ctx_arg; + u32 *in_key = ctx->buf; + ulong flag; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + int key_len = ctx->key_length; + +#ifndef CONFIG_CRYPTO_DEV_DMA + int i = 0; + int byte_cnt = nbytes; +#else + volatile struct deu_dma *dma = (struct deu_dma *)LQ_DEU_DMA_CON; + struct dma_device_info *dma_device = lq_deu[0].dma_device; + /* struct deu_drv_priv *deu_priv = + * (struct deu_drv_priv *)dma_device->priv; */ + int wlen = 0; + u32 *outcopy = NULL; + u32 *dword_mem_aligned_in = NULL; + +# ifdef CONFIG_CRYPTO_DEV_POLL_DMA + u32 timeout = 0; + u32 *out_dma = NULL; +# endif +#endif + + DPRINTF(0, "ctx @%p, mode %d, encdec %d\n", ctx, mode, encdec); + + CRTCL_SECT_START; + + /* 128, 192 or 256 bit key length */ + aes->ctrl.K = key_len / 8 - 2; + if (key_len == 128 / 8) { + aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0)); + aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1)); + aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2)); + aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3)); + } + else if (key_len == 192 / 8) { + aes->K5R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0)); + aes->K4R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1)); + aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2)); + aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3)); + aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 4)); + aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 5)); + } + else if (key_len == 256 / 8) { + aes->K7R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0)); + aes->K6R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1)); + aes->K5R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2)); + aes->K4R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3)); + aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 4)); + aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 5)); + aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 6)); + aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 7)); + } + else { + CRTCL_SECT_END; + return; /* -EINVAL; */ + } + + /* let HW pre-process DEcryption key in any case (even if + ENcryption is used). Key Valid (KV) bit is then only + checked in decryption routine! */ + aes->ctrl.PNK = 1; + +#ifdef CONFIG_CRYPTO_DEV_DMA + while (aes->ctrl.BUS) { + /* this will not take long */ + } + AES_DMA_MISC_CONFIG(); +#endif + + aes->ctrl.E_D = !encdec; /* encryption */ + aes->ctrl.O = mode; /* 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */ + aes->ctrl.SM = 1; /* start after writing input register */ + aes->ctrl.DAU = 0; /* Disable Automatic Update of init + vector */ + aes->ctrl.ARS = 1; /* Autostart Select - write to IHR */ + + /* aes->ctrl.F = 128; */ /* default; only for CFB and OFB modes; + change only for + customer-specific apps */ + if (mode > 0) { + aes->IV3R = DEU_ENDIAN_SWAP(*(u32 *)iv_arg); + aes->IV2R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 1)); + aes->IV1R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 2)); + aes->IV0R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 3)); + }; + +#ifndef CONFIG_CRYPTO_DEV_DMA + i = 0; + while (byte_cnt >= 16) { + aes->ID3R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 0)); + aes->ID2R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 1)); + aes->ID1R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 2)); + /* start crypto */ + aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 3)); + + while (aes->ctrl.BUS) { + /* this will not take long */ + } + + *((volatile u32 *)out_arg + (i * 4) + 0) = aes->OD3R; + *((volatile u32 *)out_arg + (i * 4) + 1) = aes->OD2R; + *((volatile u32 *)out_arg + (i * 4) + 2) = aes->OD1R; + *((volatile u32 *)out_arg + (i * 4) + 3) = aes->OD0R; + + i++; + byte_cnt -= 16; + } +#else /* dma */ + /* Prepare Rx buf length used in dma psuedo interrupt */ + /* deu_priv->deu_rx_buf = out_arg; */ + /* deu_priv->deu_rx_len = nbytes; */ + + /* memory alignment issue */ + dword_mem_aligned_in = (u32 *)DEU_DWORD_REORDERING(in_arg, + aes_buff_in, + BUFFER_IN, nbytes); + + dma->ctrl.ALGO = 1; /* AES */ + dma->ctrl.BS = 0; + aes->ctrl.DAU = 0; + dma->ctrl.EN = 1; + + while (aes->ctrl.BUS) { + /* wait for AES to be ready */ + }; + + wlen = dma_device_write(dma_device, (u8 *)dword_mem_aligned_in, + nbytes, NULL); + if (wlen != nbytes) { + dma->ctrl.EN = 0; + CRTCL_SECT_END; + printk(KERN_ERR "[%s %s %d]: dma_device_write fail!\n", + __FILE__, __func__, __LINE__); + return; /* -EINVAL; */ + } + + WAIT_AES_DMA_READY(); + +# ifdef CONFIG_CRYPTO_DEV_POLL_DMA + outcopy = (u32 *)DEU_DWORD_REORDERING(out_arg, aes_buff_out, + BUFFER_OUT, nbytes); + + /* polling DMA rx channel */ + while ((dma_device_read(dma_device, (u8 **)&out_dma, NULL)) == 0) { + timeout++; + + if (timeout >= 333000) { + dma->ctrl.EN = 0; + CRTCL_SECT_END; + printk (KERN_ERR "[%s %s %d]: timeout!!\n", + __FILE__, __func__, __LINE__); + return; /* -EINVAL; */ + } + } + + WAIT_AES_DMA_READY(); + + AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes); + +# else /* not working at the moment.. */ + CRTCL_SECT_END; + + /* sleep and wait for Rx finished */ + DEU_WAIT_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, + deu_priv->deu_event_flags); + + CRTCL_SECT_START; +# endif + +#endif /* dma */ + + /* tc.chen : copy iv_arg back */ + if (mode > 0) { + *((u32 *)iv_arg) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg)); + *((u32 *)iv_arg + 1) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 1)); + *((u32 *)iv_arg + 2) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 2)); + *((u32 *)iv_arg + 3) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 3)); + } + + CRTCL_SECT_END; +} + +/** \fn int ctr_rfc3686_aes_set_key(struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len) + * \ingroup LQ_AES_FUNCTIONS + * \brief sets RFC3686 key + * \param tfm linux crypto algo transform + * \param in_key input key + * \param key_len key lengths of 20, 28 and 36 bytes supported; last 4 bytes is nonce + * \return 0 - SUCCESS + * -EINVAL - bad key length +*/ +static int ctr_rfc3686_aes_set_key(struct crypto_tfm *tfm, + const uint8_t *in_key, + unsigned int key_len) +{ + struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + + memcpy(ctx->nonce, in_key + (key_len - CTR_RFC3686_NONCE_SIZE), + CTR_RFC3686_NONCE_SIZE); + + key_len -= CTR_RFC3686_NONCE_SIZE; /* remove 4 bytes of nonce */ + + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->key_length = key_len; + + memcpy((u8 *)(ctx->buf), in_key, key_len); + + return 0; +} + +/** \fn void deu_aes(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) + * \ingroup LQ_AES_FUNCTIONS + * \brief main interface with DEU hardware in DMA mode + * \param ctx_arg crypto algo context + * \param out_arg output bytestream + * \param in_arg input bytestream + * \param iv_arg initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param mode operation mode such as ebc, cbc, ctr +*/ + +#ifdef CONFIG_CRYPTO_DEV_DMA +static void deu_aes(void *ctx_arg, + u8 *out_arg, + const u8 *in_arg, + u8 *iv_arg, + u32 nbytes, + int encdec, + int mode) +{ + u32 remain = nbytes; + u32 inc; + + while (remain > 0) { + if (remain >= DEU_MAX_PACKET_SIZE) + inc = DEU_MAX_PACKET_SIZE; + else + inc = remain; + + remain -= inc; + + deu_aes_core(ctx_arg, out_arg, in_arg, iv_arg, inc, encdec, + mode); + + out_arg += inc; + in_arg += inc; + } +} +#endif + +/* definitions from linux/include/crypto.h: +#define CRYPTO_TFM_MODE_ECB 0x00000001 +#define CRYPTO_TFM_MODE_CBC 0x00000002 +#define CRYPTO_TFM_MODE_CFB 0x00000004 +#define CRYPTO_TFM_MODE_CTR 0x00000008 +#define CRYPTO_TFM_MODE_OFB 0x00000010 +but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */ + +/** \fn void deu_aes_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_AES_FUNCTIONS + * \brief sets AES hardware to ECB mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_aes_ecb(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + deu_aes(ctx, dst, src, NULL, nbytes, encdec, 0); +} + +/** \fn void deu_aes_cbc(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_AES_FUNCTIONS + * \brief sets AES hardware to CBC mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_aes_cbc(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + deu_aes(ctx, dst, src, iv, nbytes, encdec, 1); +} + +#if 0 +/** \fn void deu_aes_ofb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_AES_FUNCTIONS + * \brief sets AES hardware to OFB mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_aes_ofb(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + deu_aes(ctx, dst, src, iv, nbytes, encdec, 2); +} + +/** \fn void deu_aes_cfb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_AES_FUNCTIONS + * \brief sets AES hardware to CFB mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_aes_cfb(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + deu_aes(ctx, dst, src, iv, nbytes, encdec, 3); +} +#endif + +/** \fn void deu_aes_ctr(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_AES_FUNCTIONS + * \brief sets AES hardware to CTR mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_aes_ctr(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + deu_aes(ctx, dst, src, iv, nbytes, encdec, 4); +} + +/** \fn void aes_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) + * \ingroup LQ_AES_FUNCTIONS + * \brief encrypt AES_BLOCK_SIZE of data + * \param tfm linux crypto algo transform + * \param out output bytestream + * \param in input bytestream +*/ +static void aes_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) +{ + struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + deu_aes(ctx, out, in, NULL, AES_BLOCK_SIZE, CRYPTO_DIR_ENCRYPT, 0); +} + +/** \fn void aes_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) + * \ingroup LQ_AES_FUNCTIONS + * \brief decrypt AES_BLOCK_SIZE of data + * \param tfm linux crypto algo transform + * \param out output bytestream + * \param in input bytestream +*/ +static void aes_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) +{ + struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + deu_aes(ctx, out, in, NULL, AES_BLOCK_SIZE, CRYPTO_DIR_DECRYPT, 0); +} + +/* + * \brief AES function mappings +*/ +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_driver_name = "lq_deu-aes", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt, + } + } +}; + +/** \fn int ecb_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief ECB AES encrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int ecb_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, + NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/** \fn int ecb_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief ECB AES decrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int ecb_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, + NULL, nbytes, CRYPTO_DIR_DECRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/* + * \brief AES function mappings +*/ +static struct crypto_alg ecb_aes_alg = { + .cra_name = "ecb(aes)", + .cra_driver_name = "lq_deu-ecb(aes)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = aes_set_key, + .encrypt = ecb_aes_encrypt, + .decrypt = ecb_aes_decrypt, + } + } +}; + +/** \fn int cbc_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief CBC AES encrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int cbc_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + u8 *iv = walk.iv; + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, + iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/** \fn int cbc_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief CBC AES decrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int cbc_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + u8 *iv = walk.iv; + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, + iv, nbytes, CRYPTO_DIR_DECRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/* + * \brief AES function mappings +*/ +static struct crypto_alg cbc_aes_alg = { + .cra_name = "cbc(aes)", + .cra_driver_name = "lq_deu-cbc(aes)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = aes_set_key, + .encrypt = cbc_aes_encrypt, + .decrypt = cbc_aes_decrypt, + } + } +}; + +/** \fn int ctr_basic_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief Counter mode AES encrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int ctr_basic_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + u8 *iv = walk.iv; + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, + iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/** \fn int ctr_basic_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief Counter mode AES decrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int ctr_basic_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + u8 *iv = walk.iv; + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, + iv, nbytes, CRYPTO_DIR_DECRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/* + * \brief AES function mappings +*/ +static struct crypto_alg ctr_basic_aes_alg = { + .cra_name = "ctr(aes)", + .cra_driver_name = "lq_deu-ctr(aes)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_basic_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = aes_set_key, + .encrypt = ctr_basic_aes_encrypt, + .decrypt = ctr_basic_aes_decrypt, + } + } +}; + +/** \fn int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief Counter mode AES (rfc3686) encrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + u8 rfc3686_iv[16]; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + /* set up counter block */ + memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); + memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv, + CTR_RFC3686_IV_SIZE); + + /* initialize counter portion of counter block */ + *(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = + cpu_to_be32(1); + + while ((nbytes = walk.nbytes)) { + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, + rfc3686_iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/** \fn int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_AES_FUNCTIONS + * \brief Counter mode AES (rfc3686) decrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + u8 rfc3686_iv[16]; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + /* set up counter block */ + memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); + memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv, + CTR_RFC3686_IV_SIZE); + + /* initialize counter portion of counter block */ + *(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = + cpu_to_be32(1); + + while ((nbytes = walk.nbytes)) { + nbytes -= (nbytes % AES_BLOCK_SIZE); + deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, + rfc3686_iv, nbytes, CRYPTO_DIR_DECRYPT, 0); + nbytes &= AES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/* + * \brief AES function mappings +*/ +static struct crypto_alg ctr_rfc3686_aes_alg = { + .cra_name = "rfc3686(ctr(aes))", + .cra_driver_name = "lq_deu-ctr-rfc3686(aes)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_rfc3686_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = CTR_RFC3686_MAX_KEY_SIZE, + .ivsize = CTR_RFC3686_IV_SIZE, + .setkey = ctr_rfc3686_aes_set_key, + .encrypt = ctr_rfc3686_aes_encrypt, + .decrypt = ctr_rfc3686_aes_decrypt, + } + } +}; + +/** \fn int lq_deu_init_aes (void) + * \ingroup LQ_AES_FUNCTIONS + * \brief function to initialize AES driver + * \return ret +*/ +int lq_deu_init_aes(void) +{ + int ret; + + if ((ret = crypto_register_alg(&aes_alg))) + goto aes_err; + + if ((ret = crypto_register_alg(&ecb_aes_alg))) + goto ecb_aes_err; + + if ((ret = crypto_register_alg(&cbc_aes_alg))) + goto cbc_aes_err; + + if ((ret = crypto_register_alg(&ctr_basic_aes_alg))) + goto ctr_basic_aes_err; + + if ((ret = crypto_register_alg(&ctr_rfc3686_aes_alg))) + goto ctr_rfc3686_aes_err; + + deu_aes_chip_init(); + + CRTCL_SECT_INIT; + +#ifdef CONFIG_CRYPTO_DEV_DMA + if (ALLOCATE_MEMORY(BUFFER_IN, AES_ALGO) < 0) { + printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", + __FILE__, __func__, __LINE__); + goto ctr_rfc3686_aes_err; + } + if (ALLOCATE_MEMORY(BUFFER_OUT, AES_ALGO) < 0) { + printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", + __FILE__, __func__, __LINE__); + goto ctr_rfc3686_aes_err; + } +#endif + + printk(KERN_NOTICE "Lantiq DEU AES initialized%s.\n", + disable_deudma ? "" : " (DMA)"); + return ret; + +ctr_rfc3686_aes_err: + crypto_unregister_alg(&ctr_rfc3686_aes_alg); + printk(KERN_ERR "Lantiq ctr_rfc3686_aes initialization failed!\n"); + return ret; +ctr_basic_aes_err: + crypto_unregister_alg(&ctr_basic_aes_alg); + printk(KERN_ERR "Lantiq ctr_basic_aes initialization failed!\n"); + return ret; +cbc_aes_err: + crypto_unregister_alg(&cbc_aes_alg); + printk(KERN_ERR "Lantiq cbc_aes initialization failed!\n"); + return ret; +ecb_aes_err: + crypto_unregister_alg(&ecb_aes_alg); + printk(KERN_ERR "Lantiq aes initialization failed!\n"); + return ret; +aes_err: + printk(KERN_ERR "Lantiq DEU AES initialization failed!\n"); + return ret; +} + +/** \fn void lq_deu_fini_aes(void) + * \ingroup LQ_AES_FUNCTIONS + * \brief unregister aes driver +*/ +void lq_deu_fini_aes(void) +{ + crypto_unregister_alg(&aes_alg); + crypto_unregister_alg(&ecb_aes_alg); + crypto_unregister_alg(&cbc_aes_alg); + crypto_unregister_alg(&ctr_basic_aes_alg); + crypto_unregister_alg(&ctr_rfc3686_aes_alg); + +#ifdef CONFIG_CRYPTO_DEV_DMA + FREE_MEMORY(aes_buff_in); + FREE_MEMORY(aes_buff_out); +#endif +} --- /dev/null +++ b/drivers/crypto/lantiq/arc4.c @@ -0,0 +1,397 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file arc4.c + \ingroup LQ_DEU + \brief ARC4 encryption DEU driver file +*/ + +/** + \defgroup LQ_ARC4_FUNCTIONS LQ_ARC4_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq DEU driver functions +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SOL_LANTIQ_XWAY + +#include "deu.h" + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + +static spinlock_t cipher_lock; + +/* Preprocessor declerations */ +#define ARC4_MIN_KEY_SIZE 1 +/* #define ARC4_MAX_KEY_SIZE 256 */ +#define ARC4_MAX_KEY_SIZE 16 +#define ARC4_BLOCK_SIZE 1 + +/* + * \brief arc4 private structure +*/ +struct arc4_ctx { + int key_length; + u8 buf[120]; +}; + +/** \fn static void deu_arc4(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) + \ingroup LQ_ARC4_FUNCTIONS + \brief main interface to AES hardware + \param ctx_arg crypto algo context + \param out_arg output bytestream + \param in_arg input bytestream + \param iv_arg initialization vector + \param nbytes length of bytestream + \param encdec 1 for encrypt; 0 for decrypt + \param mode operation mode such as ebc, cbc, ctr +*/ +static void deu_arc4(void *ctx_arg, + u8 *out_arg, + const u8 *in_arg, + u8 *iv_arg, + u32 nbytes, + int encdec, + int mode) +{ + volatile struct deu_arc4 *arc4 = (struct deu_arc4 *) ARC4_START; + int i = 0; + ulong flag; + +#if 1 /* need to handle nbytes not multiple of 16 */ + volatile u32 tmp_array32[4]; + volatile u8 *tmp_ptr8; + int remaining_bytes, j; +#endif + + CRTCL_SECT_START; + + arc4->IDLEN = nbytes; + +#if 1 + while (i < nbytes) { + arc4->ID3R = *((u32 *) in_arg + (i>>2) + 0); + arc4->ID2R = *((u32 *) in_arg + (i>>2) + 1); + arc4->ID1R = *((u32 *) in_arg + (i>>2) + 2); + arc4->ID0R = *((u32 *) in_arg + (i>>2) + 3); + + arc4->ctrl.GO = 1; + + while (arc4->ctrl.BUS) { + /* this will not take long */ } + +#if 1 + /* need to handle nbytes not multiple of 16 */ + tmp_array32[0] = arc4->OD3R; + tmp_array32[1] = arc4->OD2R; + tmp_array32[2] = arc4->OD1R; + tmp_array32[3] = arc4->OD0R; + + remaining_bytes = nbytes - i; + if (remaining_bytes > 16) + remaining_bytes = 16; + + tmp_ptr8 = (u8 *)&tmp_array32[0]; + for (j = 0; j < remaining_bytes; j++) + *out_arg++ = *tmp_ptr8++; +#else + *((u32 *) out_arg + (i>>2) + 0) = arc4->OD3R; + *((u32 *) out_arg + (i>>2) + 1) = arc4->OD2R; + *((u32 *) out_arg + (i>>2) + 2) = arc4->OD1R; + *((u32 *) out_arg + (i>>2) + 3) = arc4->OD0R; +#endif + + i += 16; + } +#else /* dma */ + +#endif /* dma */ + + CRTCL_SECT_END; +} + +/** \fn arc4_chip_init(void) + \ingroup LQ_ARC4_FUNCTIONS + \brief initialize arc4 hardware +*/ +static void arc4_chip_init(void) +{ + /* do nothing */ +} + +/** \fn static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) + \ingroup LQ_ARC4_FUNCTIONS + \brief sets ARC4 key + \param tfm linux crypto algo transform + \param in_key input key + \param key_len key lengths less than or equal to 16 bytes supported +*/ +static int arc4_set_key(struct crypto_tfm *tfm, + const u8 *inkey, + unsigned int key_len) +{ + /* struct arc4_ctx *ctx = crypto_tfm_ctx(tfm); */ + volatile struct deu_arc4 *arc4 = (struct deu_arc4 *) ARC4_START; + + u32 *in_key = (u32 *)inkey; + + /* must program all bits at one go?!!! */ +#if 1 + /* #ifndef CONFIG_CRYPTO_DEV_VR9_DMA */ + *LQ_ARC4_CON = ( (1<<31) | ((key_len - 1)<<27) | (1<<26) | (3<<16) ); + /* NDC=1,ENDI=1,GO=0,KSAE=1,SM=0 */ + + arc4->K3R = *((u32 *) in_key + 0); + arc4->K2R = *((u32 *) in_key + 1); + arc4->K1R = *((u32 *) in_key + 2); + arc4->K0R = *((u32 *) in_key + 3); +#else /* dma */ + *AMAZONS_ARC4_CON = ( (1<<31) | ((key_len - 1)<<27) | (1<<26) | (3<<16) | (1<<4) ); + /* NDC=1,ENDI=1,GO=0,KSAE=1,SM=1 */ + + arc4->K3R = *((u32 *) in_key + 0); + arc4->K2R = *((u32 *) in_key + 1); + arc4->K1R = *((u32 *) in_key + 2); + arc4->K0R = *((u32 *) in_key + 3); + +#if 0 + arc4->K3R = deu_endian_swap(*((u32 *) in_key + 0)); + arc4->K2R = deu_endian_swap(*((u32 *) in_key + 1)); + arc4->K1R = deu_endian_swap(*((u32 *) in_key + 2)); + arc4->K0R = deu_endian_swap(*((u32 *) in_key + 3)); +#endif + +#endif + +#if 0 /* arc4 is a ugly state machine, KSAE can only be set once per session */ + ctx->key_length = key_len; + + memcpy((u8 *)(ctx->buf), in_key, key_len); +#endif + + return 0; +} + +/** \fn static void deu_arc4_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + \ingroup LQ_ARC4_FUNCTIONS + \brief sets ARC4 hardware to ECB mode + \param ctx crypto algo context + \param dst output bytestream + \param src input bytestream + \param iv initialization vector + \param nbytes length of bytestream + \param encdec 1 for encrypt; 0 for decrypt + \param inplace not used +*/ +static void deu_arc4_ecb(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + deu_arc4(ctx, dst, src, NULL, nbytes, encdec, 0); +} + +/** \fn static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) + \ingroup LQ_ARC4_FUNCTIONS + \brief encrypt/decrypt ARC4_BLOCK_SIZE of data + \param tfm linux crypto algo transform + \param out output bytestream + \param in input bytestream +*/ +static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + struct arc4_ctx *ctx = crypto_tfm_ctx(tfm); + + deu_arc4(ctx, out, in, NULL, ARC4_BLOCK_SIZE, + CRYPTO_DIR_DECRYPT, CRYPTO_TFM_MODE_ECB); +} + +/* + * \brief ARC4 function mappings +*/ +static struct crypto_alg arc4_alg = { + .cra_name = "arc4", + .cra_driver_name = "lq_deu-arc4", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = ARC4_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct arc4_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = ARC4_MIN_KEY_SIZE, + .cia_max_keysize = ARC4_MAX_KEY_SIZE, + .cia_setkey = arc4_set_key, + .cia_encrypt = arc4_crypt, + .cia_decrypt = arc4_crypt, + } + } +}; + +/** \fn static int ecb_arc4_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + \ingroup LQ_ARC4_FUNCTIONS + \brief ECB ARC4 encrypt using linux crypto blkcipher + \param desc blkcipher descriptor + \param dst output scatterlist + \param src input scatterlist + \param nbytes data size in bytes +*/ +static int ecb_arc4_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + DPRINTF(1, "\n"); + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + deu_arc4_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, + NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0); + nbytes &= ARC4_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/** \fn static int ecb_arc4_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + \ingroup LQ_ARC4_FUNCTIONS + \brief ECB ARC4 decrypt using linux crypto blkcipher + \param desc blkcipher descriptor + \param dst output scatterlist + \param src input scatterlist + \param nbytes data size in bytes +*/ +static int ecb_arc4_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + DPRINTF(1, "\n"); + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + deu_arc4_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, + NULL, nbytes, CRYPTO_DIR_DECRYPT, 0); + nbytes &= ARC4_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/* + * \brief ARC4 function mappings +*/ +static struct crypto_alg ecb_arc4_alg = { + .cra_name = "ecb(arc4)", + .cra_driver_name = "lq_deu-ecb(arc4)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = ARC4_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct arc4_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_arc4_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = ARC4_MIN_KEY_SIZE, + .max_keysize = ARC4_MAX_KEY_SIZE, + .setkey = arc4_set_key, + .encrypt = ecb_arc4_encrypt, + .decrypt = ecb_arc4_decrypt, + } + } +}; + +/** \fn int lq_deu_init_arc4(void) + \ingroup LQ_ARC4_FUNCTIONS + \brief initialize arc4 driver +*/ +int lq_deu_init_arc4(void) +{ + int ret; + + if ((ret = crypto_register_alg(&arc4_alg))) + goto arc4_err; + + if ((ret = crypto_register_alg(&ecb_arc4_alg))) + goto ecb_arc4_err; + + arc4_chip_init(); + + CRTCL_SECT_INIT; + + printk(KERN_NOTICE "Lantiq DEU ARC4 initialized %s.\n", + disable_deudma ? "" : " (DMA)"); + return ret; + +arc4_err: + crypto_unregister_alg(&arc4_alg); + printk(KERN_ERR "Lantiq arc4 initialization failed!\n"); + return ret; +ecb_arc4_err: + crypto_unregister_alg(&ecb_arc4_alg); + printk(KERN_ERR "Lantiq ecb_arc4 initialization failed!\n"); + + return ret; +} + +/** \fn void lq_deu_fini_arc4(void) + \ingroup LQ_ARC4_FUNCTIONS + \brief unregister arc4 driver +*/ +void lq_deu_fini_arc4(void) +{ + crypto_unregister_alg(&arc4_alg); + crypto_unregister_alg(&ecb_arc4_alg); +} + +#endif + +#endif --- /dev/null +++ b/drivers/crypto/lantiq/des.c @@ -0,0 +1,929 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver +*/ + +/** + \file des.c + \ingroup LQ_DEU + \brief DES encryption DEU driver file +*/ + +/** + \defgroup LQ_DES_FUNCTIONS LQ_DES_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq DES Encryption functions +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SOL_LANTIQ_XWAY + +#include "deu.h" + +#ifdef CONFIG_CRYPTO_DEV_DMA +# include "deu_dma.h" +#endif + +static spinlock_t cipher_lock; + +/* Preprocessor declarations */ +#define DES_KEY_SIZE 8 +#define DES_EXPKEY_WORDS 32 +#define DES_BLOCK_SIZE 8 +#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS) +#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE + +struct des_ctx { + int controlr_M; + int key_length; + u8 iv[DES_BLOCK_SIZE]; + u32 expkey[DES3_EDE_EXPKEY_WORDS]; +}; + +/** \fn int des_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len) + * \ingroup LQ_DES_FUNCTIONS + * \brief sets DES key + * \param tfm linux crypto algo transform + * \param key input key + * \param key_len key length +*/ +static int des_setkey(struct crypto_tfm *tfm, + const u8 *key, + unsigned int key_len) +{ + struct des_ctx *ctx = crypto_tfm_ctx(tfm); + + DPRINTF(0, "ctx @%p, key_len %d %d\n", ctx, key_len); + + ctx->controlr_M = 0; /* des */ + ctx->key_length = key_len; + + memcpy((u8 *)(ctx->expkey), key, key_len); + + return 0; +} + +#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA +/** \fn void deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) + * \ingroup LQ_DES_FUNCTIONS + * \brief main interface to DES hardware + * \param ctx_arg crypto algo context + * \param out_arg output bytestream + * \param in_arg input bytestream + * \param iv_arg initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param mode operation mode such as ebc, cbc +*/ + +static void deu_des(void *ctx_arg, + u8 *out_arg, + const u8 *in_arg, + u8 *iv_arg, + u32 nbytes, + int encdec, + int mode) +#else +/** \fn void deu_des_core(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) + * \ingroup LQ_DES_FUNCTIONS + * \brief main interface to DES hardware + * \param ctx_arg crypto algo context + * \param out_arg output bytestream + * \param in_arg input bytestream + * \param iv_arg initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param mode operation mode such as ebc, cbc +*/ +static void deu_des_core(void *ctx_arg, + u8 *out_arg, + const u8 *in_arg, + u8 *iv_arg, + u32 nbytes, + int encdec, + int mode) +#endif +{ + volatile struct deu_des *des = (struct deu_des *) DES_3DES_START; + struct des_ctx *dctx = ctx_arg; + u32 *key = dctx->expkey; + ulong flag; + +#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA + int i = 0; + int nblocks = 0; +#else + volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON; + struct dma_device_info *dma_device = lq_deu[0].dma_device; + /* struct deu_drv_priv *deu_priv = + * (struct deu_drv_priv *)dma_device->priv; */ + int wlen = 0; + u32 *outcopy = NULL; + u32 *dword_mem_aligned_in = NULL; + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_POLL_DMA + u32 timeout = 0; + u32 *out_dma = NULL; +#endif + +#endif + + DPRINTF(0, "ctx @%p, mode %d, encdec %d\n", dctx, mode, encdec); + + CRTCL_SECT_START; + + des->ctrl.E_D = !encdec; /* encryption */ + des->ctrl.O = mode; /* 0 ECB, 1 CBC, 2 OFB, 3 CFB, 4 CTR */ + des->ctrl.SM = 1; /* start after writing input register */ + des->ctrl.DAU = 0; /* Disable Automatic Update of init vect */ + des->ctrl.ARS = 1; /* Autostart Select - write to IHR */ + + des->ctrl.M = dctx->controlr_M; + /* write keys */ + if (dctx->controlr_M == 0) { + /* DES mode */ + des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0)); + des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1)); +#ifdef CRYPTO_DEBUG + printk("key1: %x\n", (*((u32 *) key + 0))); + printk("key2: %x\n", (*((u32 *) key + 1))); +#endif + } else { + /* 3DES mode (EDE-x) */ + switch (dctx->key_length) { + case 24: + des->K3HR = DEU_ENDIAN_SWAP(*((u32 *) key + 4)); + des->K3LR = DEU_ENDIAN_SWAP(*((u32 *) key + 5)); + /* no break; */ + case 16: + des->K2HR = DEU_ENDIAN_SWAP(*((u32 *) key + 2)); + des->K2LR = DEU_ENDIAN_SWAP(*((u32 *) key + 3)); + /* no break; */ + case 8: + des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0)); + des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1)); + break; + default: + CRTCL_SECT_END; + return; + } + } + + /* write init vector (not required for ECB mode) */ + if (mode > 0) { + des->IVHR = DEU_ENDIAN_SWAP(*(u32 *) iv_arg); + des->IVLR = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 1)); + } + +#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA + nblocks = nbytes / 4; + + for (i = 0; i < nblocks; i += 2) { + /* wait for busy bit to clear */ + + /*--- Workaround --------------------------------------------- + do a dummy read to the busy flag because it is not raised + early enough in CFB/OFB 3DES modes */ +#ifdef CRYPTO_DEBUG + printk("ihr: %x\n", (*((u32 *) in_arg + i))); + printk("ilr: %x\n", (*((u32 *) in_arg + 1 + i))); +#endif + des->IHR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + i)); + /* start crypto */ + des->ILR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + 1 + i)); + + while (des->ctrl.BUS) { + /* this will not take long */ + } + + *((u32 *) out_arg + 0 + i) = des->OHR; + *((u32 *) out_arg + 1 + i) = des->OLR; + +#ifdef CRYPTO_DEBUG + printk("ohr: %x\n", (*((u32 *) out_arg + i))); + printk("olr: %x\n", (*((u32 *) out_arg + 1 + i))); +#endif + } + +#else /* dma mode */ + + /* Prepare Rx buf length used in dma psuedo interrupt */ + /* deu_priv->deu_rx_buf = out_arg; */ + /* deu_priv->deu_rx_len = nbytes; */ + + /* memory alignment issue */ + dword_mem_aligned_in = (u32 *) DEU_DWORD_REORDERING(in_arg, des_buff_in, + BUFFER_IN, nbytes); + + dma->ctrl.ALGO = 0; /* DES */ + des->ctrl.DAU = 0; + dma->ctrl.BS = 0; + dma->ctrl.EN = 1; + + while (des->ctrl.BUS) { + /* wait for AES to be ready */ + }; + + wlen = dma_device_write(dma_device, (u8 *) dword_mem_aligned_in, nbytes, + NULL); + if (wlen != nbytes) { + dma->ctrl.EN = 0; + CRTCL_SECT_END; + printk(KERN_ERR "[%s %s %d]: dma_device_write fail!\n", + __FILE__, __func__, __LINE__); + return; /* -EINVAL; */ + } + + WAIT_DES_DMA_READY(); + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_POLL_DMA + outcopy = (u32 *) DEU_DWORD_REORDERING(out_arg, des_buff_out, + BUFFER_OUT, nbytes); + + /* polling DMA rx channel */ + while ((dma_device_read(dma_device, (u8 **) &out_dma, NULL)) == 0) { + timeout++; + + if (timeout >= 333000) { + dma->ctrl.EN = 0; + CRTCL_SECT_END; + printk(KERN_ERR "[%s %s %d]: timeout!!\n", + __FILE__, __func__, __LINE__); + return; /* -EINVAL; */ + } + } + + WAIT_DES_DMA_READY(); + + DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes); +#else + CRTCL_SECT_END; /* Sleep and wait for Rx finished */ + DEU_WAIT_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, + deu_priv->deu_event_flags); + CRTCL_SECT_START; +#endif + +#endif /* dma mode */ + + if (mode > 0) { + *(u32 *) iv_arg = DEU_ENDIAN_SWAP(des->IVHR); + *((u32 *) iv_arg + 1) = DEU_ENDIAN_SWAP(des->IVLR); + }; + + CRTCL_SECT_END; +} + +/* definitions from linux/include/crypto.h: +#define CRYPTO_TFM_MODE_ECB 0x00000001 +#define CRYPTO_TFM_MODE_CBC 0x00000002 +#define CRYPTO_TFM_MODE_CFB 0x00000004 +#define CRYPTO_TFM_MODE_CTR 0x00000008 +#define CRYPTO_TFM_MODE_OFB 0x00000010 +but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */ + +/** \fn void deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) + * \ingroup LQ_DES_FUNCTIONS + * \brief main interface to DES hardware + * \param ctx_arg crypto algo context + * \param out_arg output bytestream + * \param in_arg input bytestream + * \param iv_arg initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param mode operation mode such as ebc, cbc +*/ + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA +static void deu_des(void *ctx_arg, + u8 *out_arg, + const u8 *in_arg, + u8 *iv_arg, + u32 nbytes, + int encdec, + int mode) +{ + u32 remain = nbytes; + u32 inc; + + DPRINTF(0, "\n"); + + while (remain > 0) { + if (remain >= DEU_MAX_PACKET_SIZE) + inc = DEU_MAX_PACKET_SIZE; + else + inc = remain; + + remain -= inc; + + deu_des_core(ctx_arg, out_arg, in_arg, iv_arg, inc, encdec, + mode); + + out_arg += inc; + in_arg += inc; + } +} +#endif + +/** \fn void deu_des_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_DES_FUNCTIONS + * \brief sets DES hardware to ECB mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ + +static void deu_des_ecb(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + DPRINTF(0, "ctx @%p\n", ctx); + deu_des(ctx, dst, src, NULL, nbytes, encdec, 0); +} + +/** \fn void deu_des_cbc(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_DES_FUNCTIONS + * \brief sets DES hardware to CBC mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_des_cbc(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + DPRINTF(0, "ctx @%p\n", ctx); + deu_des(ctx, dst, src, iv, nbytes, encdec, 1); +} + +#if 0 +/** \fn void deu_des_ofb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_DES_FUNCTIONS + * \brief sets DES hardware to OFB mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_des_ofb(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + DPRINTF(0, "ctx @%p\n", ctx); + deu_des(ctx, dst, src, iv, nbytes, encdec, 2); +} + +/** \fn void deu_des_cfb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + \ingroup LQ_DES_FUNCTIONS + \brief sets DES hardware to CFB mode + \param ctx crypto algo context + \param dst output bytestream + \param src input bytestream + \param iv initialization vector + \param nbytes length of bytestream + \param encdec 1 for encrypt; 0 for decrypt + \param inplace not used +*/ +static void deu_des_cfb(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + DPRINTF(0, "ctx @%p\n", ctx); + deu_des(ctx, dst, src, iv, nbytes, encdec, 3); +} + +/** \fn void deu_des_ctr(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) + * \ingroup LQ_DES_FUNCTIONS + * \brief sets DES hardware to CTR mode + * \param ctx crypto algo context + * \param dst output bytestream + * \param src input bytestream + * \param iv initialization vector + * \param nbytes length of bytestream + * \param encdec 1 for encrypt; 0 for decrypt + * \param inplace not used +*/ +static void deu_des_ctr(void *ctx, + uint8_t *dst, + const uint8_t *src, + uint8_t *iv, + size_t nbytes, + int encdec, + int inplace) +{ + DPRINTF(0, "ctx @%p\n", ctx); + deu_des(ctx, dst, src, iv, nbytes, encdec, 4); +} +#endif + +/** \fn void des_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) + * \ingroup LQ_DES_FUNCTIONS + * \brief encrypt DES_BLOCK_SIZE of data + * \param tfm linux crypto algo transform + * \param out output bytestream + * \param in input bytestream +*/ +static void des_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) +{ + struct des_ctx *ctx = crypto_tfm_ctx(tfm); + DPRINTF(0, "ctx @%p\n", ctx); + deu_des(ctx, out, in, NULL, DES_BLOCK_SIZE, CRYPTO_DIR_ENCRYPT, 0); +} + +/** \fn void des_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) + * \ingroup LQ_DES_FUNCTIONS + * \brief encrypt DES_BLOCK_SIZE of data + * \param tfm linux crypto algo transform + * \param out output bytestream + * \param in input bytestream +*/ +static void des_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) +{ + struct des_ctx *ctx = crypto_tfm_ctx(tfm); + DPRINTF(0, "ctx @%p\n", ctx); + deu_des(ctx, out, in, NULL, DES_BLOCK_SIZE, CRYPTO_DIR_DECRYPT, 0); +} + +/* + * \brief RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the first two or last two independent 64-bit keys are + * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the + * same as DES. Implementers MUST reject keys that exhibit this + * property. + * + */ + +/** \fn int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) + * \ingroup LQ_DES_FUNCTIONS + * \brief sets 3DES key + * \param tfm linux crypto algo transform + * \param key input key + * \param keylen key length +*/ +static int des3_ede_setkey(struct crypto_tfm *tfm, + const u8 *key, + unsigned int key_len) +{ + struct des_ctx *ctx = crypto_tfm_ctx(tfm); + + DPRINTF(0, "ctx @%p, key_len %d\n", ctx, key_len); + + ctx->controlr_M = key_len / 8 + 1; /* 3DES EDE1 / EDE2 / EDE3 Mode */ + ctx->key_length = key_len; + + memcpy((u8 *)(ctx->expkey), key, key_len); + + return 0; +} + +/* + * \brief DES function mappings +*/ +static struct crypto_alg des_alg = { + .cra_name = "des", + .cra_driver_name = "lq_deu-des", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct des_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(des_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = DES_KEY_SIZE, + .cia_max_keysize = DES_KEY_SIZE, + .cia_setkey = des_setkey, + .cia_encrypt = des_encrypt, + .cia_decrypt = des_decrypt + } + } +}; + +/* + * \brief DES function mappings +*/ +static struct crypto_alg des3_ede_alg = { + .cra_name = "des3_ede", + .cra_driver_name = "lq_deu-des3_ede", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct des_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(des3_ede_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = DES_KEY_SIZE, + .cia_max_keysize = DES_KEY_SIZE, + .cia_setkey = des3_ede_setkey, + .cia_encrypt = des_encrypt, + .cia_decrypt = des_decrypt + } + } +}; + +/** \fn int ecb_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_DES_FUNCTIONS + * \brief ECB DES encrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes +*/ +static int ecb_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + DPRINTF(0, "ctx @%p\n", ctx); + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes -= (nbytes % DES_BLOCK_SIZE); + deu_des_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, + NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0); + nbytes &= DES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/** \fn int ecb_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_DES_FUNCTIONS + * \brief ECB DES decrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int ecb_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + DPRINTF(0, "ctx @%p\n", ctx); + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes -= (nbytes % DES_BLOCK_SIZE); + deu_des_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, + NULL, nbytes, CRYPTO_DIR_DECRYPT, 0); + nbytes &= DES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/* + * \brief DES function mappings +*/ +static struct crypto_alg ecb_des_alg = { + .cra_name = "ecb(des)", + .cra_driver_name = "lq_deu-ecb(des)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .setkey = des_setkey, + .encrypt = ecb_des_encrypt, + .decrypt = ecb_des_decrypt, + } + } +}; + +/* + * \brief DES function mappings +*/ +static struct crypto_alg ecb_des3_ede_alg = { + .cra_name = "ecb(des3_ede)", + .cra_driver_name = "lq_deu-ecb(des3_ede)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_des3_ede_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .setkey = des3_ede_setkey, + .encrypt = ecb_des_encrypt, + .decrypt = ecb_des_decrypt, + } + } +}; + +/** \fn int cbc_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_DES_FUNCTIONS + * \brief CBC DES encrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int cbc_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + DPRINTF(0, "ctx @%p\n", ctx); + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + u8 *iv = walk.iv; + /* printk("iv = %08x\n", *(u32 *)iv); */ + nbytes -= (nbytes % DES_BLOCK_SIZE); + deu_des_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, + iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); + nbytes &= DES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/** \fn int cbc_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) + * \ingroup LQ_DES_FUNCTIONS + * \brief CBC DES decrypt using linux crypto blkcipher + * \param desc blkcipher descriptor + * \param dst output scatterlist + * \param src input scatterlist + * \param nbytes data size in bytes + * \return err +*/ +static int cbc_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + DPRINTF(0, "ctx @%p\n", ctx); + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + u8 *iv = walk.iv; + /* printk("iv = %08x\n", *(u32 *)iv); */ + nbytes -= (nbytes % DES_BLOCK_SIZE); + deu_des_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, + iv, nbytes, CRYPTO_DIR_DECRYPT, 0); + nbytes &= DES_BLOCK_SIZE - 1; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +/* + * \brief DES function mappings +*/ +static struct crypto_alg cbc_des_alg = { + .cra_name = "cbc(des)", + .cra_driver_name = "lq_deu-cbc(des)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des_setkey, + .encrypt = cbc_des_encrypt, + .decrypt = cbc_des_decrypt, + } + } +}; + +/* + * \brief DES function mappings +*/ +static struct crypto_alg cbc_des3_ede_alg = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "lq_deu-cbc(des3_ede)", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(cbc_des3_ede_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des3_ede_setkey, + .encrypt = cbc_des_encrypt, + .decrypt = cbc_des_decrypt, + } + } +}; + +/** \fn int lq_deu_init_des(void) + * \ingroup LQ_DES_FUNCTIONS + * \brief initialize des driver +*/ +int lq_deu_init_des(void) +{ + int ret = 0; + + ret = crypto_register_alg(&des_alg); + if (ret < 0) + goto des_err; + + ret = crypto_register_alg(&ecb_des_alg); + if (ret < 0) + goto ecb_des_err; + + ret = crypto_register_alg(&cbc_des_alg); + if (ret < 0) + goto cbc_des_err; + + ret = crypto_register_alg(&des3_ede_alg); + if (ret < 0) + goto des3_ede_err; + + ret = crypto_register_alg(&ecb_des3_ede_alg); + if (ret < 0) + goto ecb_des3_ede_err; + + ret = crypto_register_alg(&cbc_des3_ede_alg); + if (ret < 0) + goto cbc_des3_ede_err; + + deu_des_chip_init(); + + CRTCL_SECT_INIT; + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + if (ALLOCATE_MEMORY(BUFFER_IN, DES_ALGO) < 0) { + printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", + __FILE__, __func__, __LINE__); + goto cbc_des3_ede_err; + } + if (ALLOCATE_MEMORY(BUFFER_OUT, DES_ALGO) < 0) { + printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", + __FILE__, __func__, __LINE__); + goto cbc_des3_ede_err; + } +#endif + + printk(KERN_NOTICE "Lantiq DEU DES initialized%s.\n", + disable_deudma ? "" : " (DMA)"); + return ret; + +des_err: + crypto_unregister_alg(&des_alg); + printk(KERN_ERR "Lantiq des initialization failed!\n"); + + return ret; + +ecb_des_err: + crypto_unregister_alg(&ecb_des_alg); + printk(KERN_ERR "Lantiq ecb_des initialization failed!\n"); + + return ret; + +cbc_des_err: + crypto_unregister_alg(&cbc_des_alg); + printk(KERN_ERR "Lantiq cbc_des initialization failed!\n"); + + return ret; + +des3_ede_err: + crypto_unregister_alg(&des3_ede_alg); + printk(KERN_ERR "Lantiq des3_ede initialization failed!\n"); + + return ret; + +ecb_des3_ede_err: + crypto_unregister_alg(&ecb_des3_ede_alg); + printk(KERN_ERR "Lantiq ecb_des3_ede initialization failed!\n"); + + return ret; + +cbc_des3_ede_err: + crypto_unregister_alg(&cbc_des3_ede_alg); + printk(KERN_ERR "Lantiq cbc_des3_ede initialization failed!\n"); + + return ret; +} + +/** \fn void lq_deu_fini_des(void) + * \ingroup LQ_DES_FUNCTIONS + * \brief unregister des driver +*/ +void lq_deu_fini_des(void) +{ + crypto_unregister_alg(&des_alg); + crypto_unregister_alg(&ecb_des_alg); + crypto_unregister_alg(&cbc_des_alg); + crypto_unregister_alg(&des3_ede_alg); + crypto_unregister_alg(&ecb_des3_ede_alg); + crypto_unregister_alg(&cbc_des3_ede_alg); + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + FREE_MEMORY(des_buff_in); + FREE_MEMORY(des_buff_out); +#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA_DANUBE */ +} + +#endif --- /dev/null +++ b/drivers/crypto/lantiq/deu.c @@ -0,0 +1,195 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file deu.c + \ingroup LQ_DEU + \brief main DEU driver file +*/ + +/** + \defgroup LQ_DEU_FUNCTIONS LQ_DEU_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq DEU functions +*/ + +#include +#if defined(CONFIG_MODVERSIONS) +#define MODVERSIONS +#include +#endif +#include +#include +#include +#include +#include +#include +#include /* Stuff about file systems that we need */ +#include + +#if 0 +#ifdef CONFIG_SOC_LANTIQ_XWAY +# include +#endif +#endif + +#include "deu.h" + +struct lq_crypto_priv lq_crypto_ops; + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA +int disable_deudma = 0; +#else +int disable_deudma = 1; +#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */ + +#ifdef CRYPTO_DEBUG +char deu_debug_level = 3; +#endif + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_MODULE +# define STATIC static +#else +# define STATIC +#endif + +/** \fn static int lq_deu_init(void) + * \ingroup LQ_DEU_FUNCTIONS + * \brief link all modules that have been selected in kernel config for Lantiq HW crypto support + * \return ret +*/ +int lq_deu_init(void) +{ + int ret = -ENOSYS; + u32 config; + + printk(KERN_INFO "Lantiq crypto hardware driver version %s\n", + LQ_DEU_DRV_VERSION); + + config = deu_chip_init(); + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + deu_dma_init(); +#endif + +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_AES) + if(config & LQ_DEU_ID_AES) { + if ((ret = lq_deu_init_aes())) { + printk(KERN_ERR "Lantiq AES initialization failed!\n"); + } + } else { + printk(KERN_ERR "Lantiq AES not supported!\n"); + } +#endif + +#ifdef CONFIG_SOL_LANTIQ_XWAY +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DES) + if(config & LQ_DEU_ID_DES) { + if ((ret = lq_deu_init_des())) { + printk(KERN_ERR "Lantiq DES initialization failed!\n"); + } + } else { + printk(KERN_ERR "Lantiq DES not supported!\n"); + } +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) && defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA) + if ((ret = lq_deu_init_arc4())) { + printk(KERN_ERR "Lantiq ARC4 initialization failed!\n"); + } +#endif +#endif + +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1) + if(config & LQ_DEU_ID_HASH) { + if ((ret = lq_deu_init_sha1())) { + printk(KERN_ERR "Lantiq SHA1 initialization failed!\n"); + } + } else { + printk(KERN_ERR "Lantiq SHA1 not supported!\n"); + } +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5) + if(config & LQ_DEU_ID_HASH) { + if ((ret = lq_deu_init_md5())) { + printk(KERN_ERR "Lantiq MD5 initialization failed!\n"); + } + } else { + printk(KERN_ERR "Lantiq MD5 not supported!\n"); + } +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC) + if ((ret = lq_deu_init_sha1_hmac())) { + printk(KERN_ERR "Lantiq SHA1_HMAC initialization failed!\n"); + } +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC) + if ((ret = lq_deu_init_md5_hmac())) { + printk(KERN_ERR "Lantiq MD5_HMAC initialization failed!\n"); + } +#endif + return ret; +} + +/** \fn static void lq_deu_fini(void) + * \ingroup LQ_DEU_FUNCTIONS + * \brief remove the loaded crypto algorithms +*/ +void lq_deu_exit(void) +{ +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_AES) + lq_deu_fini_aes(); +#endif +#ifdef CONFIG_SOL_LANTIQ_XWAY +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DES) + lq_deu_fini_des(); +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) \ + && defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA) + lq_deu_fini_arc4(); +#endif +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1) + lq_deu_fini_sha1(); +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5) + lq_deu_fini_md5(); +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC) + lq_deu_fini_sha1_hmac(); +#endif +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC) + lq_deu_fini_md5_hmac(); +#endif + + printk("DEU has exited successfully\n"); + +#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA) + deu_dma_exit(); + printk("DMA has deregistered successfully\n"); +#endif +} + +EXPORT_SYMBOL(lq_deu_init); +EXPORT_SYMBOL(lq_deu_exit); --- /dev/null +++ b/drivers/crypto/lantiq/deu.h @@ -0,0 +1,248 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file deu.h + \brief Main DEU driver header file +*/ + +/** + \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS + \ingroup LQ_DEU + \brief Lantiq DEU definitions +*/ + + +#ifndef DEU_H +#define DEU_H + +#undef CRYPTO_DEBUG + +#define LQ_DEU_DRV_VERSION "1.0.1" + +#if defined(CONFIG_LANTIQ_DANUBE) +# include "deu_danube.h" +#elif defined(CONFIG_LANTIQ_AR9) +# include "deu_ar9.h" +#elif defined(CONFIG_SOC_LANTIQ_FALCON) +# include "deu_falcon.h" +#else +//# error "Unknown platform" +# include "deu_danube.h" +#endif + +struct lq_crypto_priv { +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + u32 *des_buff_in; + u32 *des_buff_out; + u32 *aes_buff_in; + u32 *aes_buff_out; + + int (*dma_init)(void); + void (*dma_exit)(void); + u32 (*dma_align)(const u8 *, u32 *, int, int); + void (*aes_dma_memcpy)(u32 *, u32 *, u8 *, int); + void (*des_dma_memcpy)(u32 *, u32 *, u8 *, int); + int (*aes_dma_malloc)(int); + int (*des_dma_malloc)(int); + void (*dma_free)(u32 *); +#endif + + u32 (*endian_swap)(u32); + u32 (*input_swap)(u32); + void (*aes_chip_init)(void); + void (*des_chip_init)(void); + u32 (*chip_init)(void); +}; + +extern struct lq_crypto_priv lq_crypto_ops; + +#define LQ_DEU_ALIGNMENT 16 + +#define PFX "lq_deu: " + +#define LQ_DEU_CRA_PRIORITY 300 +#define LQ_DEU_COMPOSITE_PRIORITY 400 + +#define CRYPTO_DIR_ENCRYPT 1 +#define CRYPTO_DIR_DECRYPT 0 + +#define CRTCL_SECT_INIT spin_lock_init(&cipher_lock) +#define CRTCL_SECT_START spin_lock_irqsave(&cipher_lock, flag) +#define CRTCL_SECT_END spin_unlock_irqrestore(&cipher_lock, flag) + +#define LQ_DEU_ID_REV 0x00001F +#define LQ_DEU_ID_ID 0x00FF00 +#define LQ_DEU_ID_DMA 0x010000 +#define LQ_DEU_ID_HASH 0x020000 +#define LQ_DEU_ID_AES 0x040000 +#define LQ_DEU_ID_3DES 0x080000 +#define LQ_DEU_ID_DES 0x100000 + +extern int disable_deudma; + +int lq_deu_init(void); +void lq_deu_exit(void); + +int lq_deu_init_des(void); +int lq_deu_init_aes(void); +int lq_deu_init_arc4(void); +int lq_deu_init_sha1(void); +int lq_deu_init_md5(void); +int lq_deu_init_sha1_hmac(void); +int lq_deu_init_md5_hmac(void); + +void lq_deu_fini_des(void); +void lq_deu_fini_aes(void); +void lq_deu_fini_arc4(void); +void lq_deu_fini_sha1(void); +void lq_deu_fini_md5(void); +void lq_deu_fini_sha1_hmac(void); +void lq_deu_fini_md5_hmac(void); + +/* board specific functions */ +/* { */ +static inline u32 deu_chip_init(void) +{ + return lq_crypto_ops.chip_init(); +} + +static inline void deu_des_chip_init(void) +{ + lq_crypto_ops.des_chip_init(); +} + +static inline void deu_aes_chip_init(void) +{ + lq_crypto_ops.aes_chip_init(); +} + +static inline u32 deu_input_swap(u32 input) +{ + return lq_crypto_ops.input_swap(input); +} + +static inline u32 deu_endian_swap(u32 input) +{ + return lq_crypto_ops.endian_swap(input); +} + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA +static inline int deu_aes_dma_malloc(int value) +{ + return lq_crypto_ops.aes_dma_malloc(value); +} + +static inline int deu_des_dma_malloc(int value) +{ + return lq_crypto_ops.des_dma_malloc(value); +} + +static inline u32 *deu_dma_align(const u8 *arg, + u32 *buff_alloc, + int in_out, + int nbytes) +{ + return lq_crypto_ops.dma_align(arg, buff_alloc, in_out, nbytes); +} + +static inline void deu_aes_dma_memcpy(u32 *outcopy, + u32 *out_dma, + u8 *out_arg, + int nbytes) +{ + lq_crypto_ops.aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes); +} + +static inline void deu_des_dma_memcpy(u32 *outcopy, + u32 *out_dma, + u8 *out_arg, + int nbytes) +{ + lq_crypto_ops.des_dma_memcpy(outcopy, out_dma, out_arg, nbytes); +} + +static inline void deu_dma_free(u32 *addr) +{ + lq_crypto_ops.dma_free(addr); +} + +static inline int deu_dma_init(void) +{ + lq_crypto_ops.dma_init(); +} + +static inline void deu_dma_exit(void) +{ + lq_crypto_ops.dma_exit(); +} +#endif + +/* } */ + +#define DEU_WAKELIST_INIT(queue) \ + init_waitqueue_head(&queue) + +#define DEU_WAIT_EVENT_TIMEOUT(queue, event, flags, timeout) \ + do { \ + wait_event_interruptible_timeout((queue), \ + test_bit((event), \ + &(flags)), (timeout)); \ + clear_bit((event), &(flags)); \ + }while (0) + + +#define DEU_WAKEUP_EVENT(queue, event, flags) \ + do { \ + set_bit((event), &(flags)); \ + wake_up_interruptible(&(queue)); \ + }while (0) + +#define DEU_WAIT_EVENT(queue, event, flags) \ + do { \ + wait_event_interruptible(queue, \ + test_bit((event), &(flags))); \ + clear_bit((event), &(flags)); \ + }while (0) + +struct deu_drv_priv { + wait_queue_head_t deu_thread_wait; +#define DEU_EVENT 1 + volatile long deu_event_flags; + u8 *deu_rx_buf; + u32 deu_rx_len; +}; + +#ifdef CRYPTO_DEBUG +extern char deu_debug_level; +# define DPRINTF(level, format, args...) \ + if (level < deu_debug_level) \ + printk(KERN_INFO "[%s %s %d]: " format, \ + __FILE__, __func__, __LINE__, ##args) +#else +# define DPRINTF(level, format, args...) do { } while(0) +#endif + +#endif /* DEU_H */ --- /dev/null +++ b/drivers/crypto/lantiq/deu_ar9.c @@ -0,0 +1,327 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +#include +#include +#include +#include +#include /* dma_cache_inv */ +#include + +#ifdef CONFIG_SOC_LANTIQ_XWAY + +#include "deu.h" + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file deu_ar9.c + \brief Lantiq DEU board specific driver file for ar9 +*/ + +/** + \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS + \ingroup LQ_DEU + \brief board specific functions +*/ + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA +struct lq_deu_device lq_deu[1]; + +static u8 *g_dma_page_ptr = NULL; +static u8 *g_dma_block = NULL; +static u8 *g_dma_block2 = NULL; + +/** \fn int dma_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Initialize DMA for DEU usage. DMA specific registers are + * intialized here, including a pointer to the device, memory + * space for the device and DEU-DMA descriptors + * \return -1: fail, 0: SUCCESS +*/ +static int dma_init(void) +{ + volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON; + struct dma_device_info *dma_device = NULL; + int i = 0; + + struct dma_device_info *deu_dma_device_ptr; + + /* get one free page and share between g_dma_block and g_dma_block2 */ + printk("PAGE_SIZE = %ld\n", PAGE_SIZE); + /* need 16-byte alignment memory block */ + g_dma_page_ptr = (u8 *)__get_free_page(GFP_KERNEL); + /* need 16-byte alignment memory block */ + g_dma_block = g_dma_page_ptr; + /* need 16-byte alignment memory block */ + g_dma_block2 = (u8 *)(g_dma_page_ptr + (PAGE_SIZE >> 1)); + + /* deu_dma_priv_init(); */ + + deu_dma_device_ptr = dma_device_reserve("DEU"); + if (!deu_dma_device_ptr) { + printk("DEU: reserve DMA fail!\n"); + return -1; + } + lq_deu[0].dma_device = deu_dma_device_ptr; + + dma_device = deu_dma_device_ptr; + /* dma_device->priv = &deu_dma_priv; */ + dma_device->buffer_alloc = &deu_dma_buffer_alloc; + dma_device->buffer_free = &deu_dma_buffer_free; + dma_device->intr_handler = &deu_dma_intr_handler; + + dma_device->tx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; + dma_device->rx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; + dma_device->port_num = 1; + dma_device->tx_burst_len = 2; + dma_device->rx_burst_len = 2; + dma_device->max_rx_chan_num = 1; + dma_device->max_tx_chan_num = 1; + dma_device->port_packet_drop_enable = 0; + + for (i = 0; i < dma_device->max_rx_chan_num; i++) { + dma_device->rx_chan[i]->packet_size = DEU_MAX_PACKET_SIZE; + dma_device->rx_chan[i]->desc_len = 1; + dma_device->rx_chan[i]->control = LQ_DMA_CH_ON; + dma_device->rx_chan[i]->byte_offset = 0; + dma_device->rx_chan[i]->chan_poll_enable = 1; + } + + for (i = 0; i < dma_device->max_tx_chan_num; i++) { + dma_device->tx_chan[i]->control = LQ_DMA_CH_ON; + dma_device->tx_chan[i]->desc_len = 1; + dma_device->tx_chan[i]->chan_poll_enable = 1; + } + + dma_device->current_tx_chan = 0; + dma_device->current_rx_chan = 0; + + i = dma_device_register(dma_device); + for (i = 0; i < dma_device->max_rx_chan_num; i++) { + (dma_device->rx_chan[i])->open(dma_device->rx_chan[i]); + } + + dma->ctrl.BS = 0; + dma->ctrl.RXCLS = 0; + dma->ctrl.EN = 1; + + return 0; +} + +/** \fn u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Not used for AR9 + * \param arg Pointer to the input / output memory address + * \param buffer_alloc A pointer to the buffer + * \param in_buff Input (if == 1) or Output (if == 0) buffer + * \param nbytes Number of bytes of data +*/ +static u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) +{ + return (u32 *) arg; +} + +/** \fn void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief copy the DMA data to the memory address space for AES + * \param outcopy Not used + * \param out_dma A pointer to the memory address that stores the DMA data + * \param out_arg The pointer to the memory address that needs to be copied to] + * \param nbytes Number of bytes of data +*/ +static void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) +{ + memcpy(out_arg, out_dma, nbytes); +} + +/** \fn void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief copy the DMA data to the memory address space for DES + * \param outcopy Not used + * \param out_dma A pointer to the memory address that stores the DMA data + * \param out_arg The pointer to the memory address that needs to be copied to] + * \param nbytes Number of bytes of data +*/ +static void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) +{ + memcpy(out_arg, out_dma, nbytes); +} + +/** \fn dma_exit(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief unregister dma devices after exit +*/ +static void dma_exit(void) +{ + if (g_dma_page_ptr) + free_page((u32) g_dma_page_ptr); + dma_device_release(lq_deu[0].dma_device); + dma_device_unregister(lq_deu[0].dma_device); +} +#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */ + +/** \fn u32 endian_swap(u32 input) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Swap data given to the function + * \param input Data input to be swapped + * \return either the swapped data or the input data depending on whether it is in DMA mode or FPI mode +*/ +static u32 endian_swap(u32 input) +{ +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + u8 *ptr = (u8 *)&input; + return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); +#else + return input; +#endif +} + +/** \fn u32 input_swap(u32 input) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Not used + * \return input +*/ +static u32 input_swap(u32 input) +{ + return input; +} + +/** \fn void aes_chip_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief initialize AES hardware +*/ +static void aes_chip_init(void) +{ + volatile struct deu_aes *aes = (struct deu_aes *) AES_START; + + aes->ctrl.SM = 1; +#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA + aes->ctrl.ARS = 1; +#else + aes->ctrl.NDC = 1; /* to write to ENDI */ + asm("sync"); + aes->ctrl.ENDI = 0; + asm("sync"); + aes->ctrl.ARS = 0; /* 0 for dma */ + asm("sync"); +#endif +} + +/** \fn void des_chip_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief initialize DES hardware +*/ +static void des_chip_init(void) +{ + volatile struct deu_des *des = (struct deu_des *) DES_3DES_START; + +#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA + /* start crypto engine with write to ILR */ + des->ctrl.SM = 1; + asm("sync"); + des->ctrl.ARS = 1; +#else + des->ctrl.SM = 1; + des->ctrl.NDC = 1; + asm("sync"); + des->ctrl.ENDI = 0; + asm("sync"); + des->ctrl.ARS = 0; /* 0 for dma */ + +#endif +} + +static u32 chip_init(void) +{ + volatile struct deu_clk_ctrl *clc = (struct deu_clk_ctrl *) LQ_DEU_CLK; + +#if 0 + lq_pmu_enable(1<<20); +#endif + + clc->FSOE = 0; + clc->SBWE = 0; + clc->SPEN = 0; + clc->SBWE = 0; + clc->DISS = 0; + clc->DISR = 0; + + return *LQ_DEU_ID; +} + +static int lq_crypto_probe(struct platform_device *pdev) +{ +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + lq_crypto_ops.dma_init = dma_init; + lq_crypto_ops.dma_exit = dma_exit; + lq_crypto_ops.aes_dma_memcpy = aes_dma_memcpy; + lq_crypto_ops.des_dma_memcpy = des_dma_memcpy; + lq_crypto_ops.aes_dma_malloc = aes_dma_malloc; + lq_crypto_ops.des_dma_malloc = des_dma_malloc; + lq_crypto_ops.dma_align = dma_align; + lq_crypto_ops.dma_free = dma_free; +#endif + + lq_crypto_ops.endian_swap = endian_swap; + lq_crypto_ops.input_swap = input_swap; + lq_crypto_ops.aes_chip_init = aes_chip_init; + lq_crypto_ops.des_chip_init = des_chip_init; + lq_crypto_ops.chip_init = chip_init; + + printk("lq_ar9_deu: driver loaded!\n"); + + lq_deu_init(); + + return 0; +} + +static int lq_crypto_remove(struct platform_device *pdev) +{ + lq_deu_exit(); + + return 0; +} + +static struct platform_driver lq_crypto = { + .probe = lq_crypto_probe, + .remove = lq_crypto_remove, + .driver = { + .owner = THIS_MODULE, + .name = "lq_ar9_deu" + } +}; + +static int __init lq_crypto_init(void) +{ + return platform_driver_register(&lq_crypto); +} +module_init(lq_crypto_init); + +static void __exit lq_crypto_exit(void) +{ + platform_driver_unregister(&lq_crypto); +} +module_exit(lq_crypto_exit); + +#endif --- /dev/null +++ b/drivers/crypto/lantiq/deu_ar9.h @@ -0,0 +1,291 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief DEU driver module +*/ + +/** + \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS + \ingroup LQ_DEU + \brief Lantiq DEU definitions +*/ + +/** + \file deu_ar9.h + \brief DEU driver header file +*/ + + +#ifndef DEU_AR9_H +#define DEU_AR9_H + +#define LQ_DEU_BASE_ADDR (KSEG1 | 0x1E103100) +#define LQ_DEU_CLK ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0000)) +#define LQ_DEU_ID ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0008)) +#define LQ_DES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0010)) +#define LQ_AES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0050)) +#define LQ_HASH_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x00B0)) +#define LQ_ARC4_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0100)) + +#define ARC4_START LQ_ARC4_CON +#define DES_3DES_START LQ_DES_CON +#define HASH_START LQ_HASH_CON +#define AES_START LQ_AES_CON + +#ifdef CONFIG_CRYPTO_DEV_DMA +# include "deu_dma.h" +# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \ + deu_dma_align(ptr, buffer, in_out, bytes) +# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ + deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes) +# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ + deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes) +# define BUFFER_IN 1 +# define BUFFER_OUT 0 +# define AES_ALGO 1 +# define DES_ALGO 0 +# define ALLOCATE_MEMORY(val, type) 1 +# define FREE_MEMORY(buff) +extern struct lq_deu_device lq_deu[1]; +#endif /* CONFIG_CRYPTO_DEV_DMA */ + +/* SHA CONSTANTS */ +#define HASH_CON_VALUE 0x0700002C + +#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input) +#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input) +#define DELAY_PERIOD 10 +#define FIND_DEU_CHIP_VERSION chip_version() + +#define WAIT_AES_DMA_READY() \ + do { \ + int i; \ + volatile struct deu_dma *dma = \ + (struct deu_dma *) LQ_DEU_DMA_CON; \ + volatile struct deu_aes *aes = \ + (volatile struct deu_aes *) AES_START; \ + for (i = 0; i < 10; i++) \ + udelay(DELAY_PERIOD); \ + while (dma->ctrl.BSY) {}; \ + while (aes->ctrl.BUS) {}; \ + } while (0) + +#define WAIT_DES_DMA_READY() \ + do { \ + int i; \ + volatile struct deu_dma *dma = \ + (struct deu_dma *) LQ_DEU_DMA_CON; \ + volatile struct deu_des *des = \ + (struct deu_des *) DES_3DES_START; \ + for (i = 0; i < 10; i++) \ + udelay(DELAY_PERIOD); \ + while (dma->ctrl.BSY) {}; \ + while (des->ctrl.BUS) {}; \ + } while (0) + +#define AES_DMA_MISC_CONFIG() \ + do { \ + volatile struct deu_aes *aes = \ + (volatile struct deu_aes *) AES_START; \ + aes->ctrl.KRE = 1; \ + aes->ctrl.GO = 1; \ + } while(0) + +#define SHA_HASH_INIT \ + do { \ + volatile struct deu_hash *hash = \ + (struct deu_hash *) HASH_START; \ + hash->ctrl.SM = 1; \ + hash->ctrl.ALGO = 0; \ + hash->ctrl.INIT = 1; \ + } while(0) + +/* DEU Common Structures for AR9*/ + +struct deu_clk_ctrl { + u32 Res:26; + u32 FSOE:1; + u32 SBWE:1; + u32 EDIS:1; + u32 SPEN:1; + u32 DISS:1; + u32 DISR:1; +}; + +struct deu_des { + struct deu_des_ctrl { /* 10h */ + u32 KRE:1; + u32 reserved1:5; + u32 GO:1; + u32 STP:1; + u32 Res2:6; + u32 NDC:1; + u32 ENDI:1; + u32 Res3:2; + u32 F:3; + u32 O:3; + u32 BUS:1; + u32 DAU:1; + u32 ARS:1; + u32 SM:1; + u32 E_D:1; + u32 M:3; + } ctrl; + + u32 IHR; /* 14h */ + u32 ILR; /* 18h */ + u32 K1HR; /* 1c */ + u32 K1LR; + u32 K2HR; + u32 K2LR; + u32 K3HR; + u32 K3LR; /* 30h */ + u32 IVHR; /* 34h */ + u32 IVLR; /* 38 */ + u32 OHR; /* 3c */ + u32 OLR; /* 40 */ +}; + +struct deu_aes { + struct deu_aes_ctrl { + u32 KRE:1; + u32 reserved1:4; + u32 PNK:1; + u32 GO:1; + u32 STP:1; + u32 reserved2:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved3:2; + u32 F:3; /* fbs */ + u32 O:3; /* om */ + u32 BUS:1; /* bsy */ + u32 DAU:1; + u32 ARS:1; + u32 SM:1; + u32 E_D:1; + u32 KV:1; + u32 K:2; /* KL */ + } ctrl; + + u32 ID3R; /* 80h */ + u32 ID2R; /* 84h */ + u32 ID1R; /* 88h */ + u32 ID0R; /* 8Ch */ + u32 K7R; /* 90h */ + u32 K6R; /* 94h */ + u32 K5R; /* 98h */ + u32 K4R; /* 9Ch */ + u32 K3R; /* A0h */ + u32 K2R; /* A4h */ + u32 K1R; /* A8h */ + u32 K0R; /* ACh */ + u32 IV3R; /* B0h */ + u32 IV2R; /* B4h */ + u32 IV1R; /* B8h */ + u32 IV0R; /* BCh */ + u32 OD3R; /* D4h */ + u32 OD2R; /* D8h */ + u32 OD1R; /* DCh */ + u32 OD0R; /* E0h */ +}; + +struct deu_arc4 { + struct arc4_controlr { + u32 KRE:1; + u32 KLEN:4; + u32 KSAE:1; + u32 GO:1; + u32 STP:1; + u32 reserved1:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved2:8; + u32 BUS:1; /* bsy */ + u32 reserved3:1; + u32 ARS:1; + u32 SM:1; + u32 reserved4:4; + } ctrl; + + u32 K3R; /* 104h */ + u32 K2R; /* 108h */ + u32 K1R; /* 10Ch */ + u32 K0R; /* 110h */ + u32 IDLEN; /* 114h */ + u32 ID3R; /* 118h */ + u32 ID2R; /* 11Ch */ + u32 ID1R; /* 120h */ + u32 ID0R; /* 124h */ + u32 OD3R; /* 128h */ + u32 OD2R; /* 12Ch */ + u32 OD1R; /* 130h */ + u32 OD0R; /* 134h */ +}; + +struct deu_hash { + struct deu_hash_ctrl { + u32 reserved1:5; + u32 KHS:1; + u32 GO:1; + u32 INIT:1; + u32 reserved2:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved3:7; + u32 DGRY:1; + u32 BSY:1; + u32 reserved4:1; + u32 IRCL:1; + u32 SM:1; + u32 KYUE:1; + u32 HMEN:1; + u32 SSEN:1; + u32 ALGO:1; + } ctrl; + + u32 MR; /* B4h */ + u32 D1R; /* B8h */ + u32 D2R; /* BCh */ + u32 D3R; /* C0h */ + u32 D4R; /* C4h */ + u32 D5R; /* C8h */ + u32 dummy; /* CCh */ + u32 KIDX; /* D0h */ + u32 KEY; /* D4h */ + u32 DBN; /* D8h */ +}; + +struct deu_dma { + struct deu_dma_ctrl { + u32 reserved1:22; + u32 BS:2; + u32 BSY:1; + u32 reserved2:1; + u32 ALGO:2; + u32 RXCLS:2; + u32 reserved3:1; + u32 EN:1; + } ctrl; +}; + +#endif /* DEU_AR9_H */ --- /dev/null +++ b/drivers/crypto/lantiq/deu_danube.c @@ -0,0 +1,484 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +#include +#include +#include +#include +#include /* dma_cache_inv */ +#include + +#ifdef CONFIG_SOC_LANTIQ_XWAY + +#include "deu.h" + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief DEU driver module +*/ + +/** + \file deu_danube.c + \ingroup LQ_DEU + \brief board specific DEU driver file for danube +*/ + +/** + \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS + \ingroup LQ_DEU + \brief board specific DEU functions +*/ + +static int danube_pre_1_4; + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA +u32 *des_buff_in = NULL; +u32 *des_buff_out = NULL; +u32 *aes_buff_in = NULL; +u32 *aes_buff_out = NULL; + +struct lq_deu_device lq_deu[1]; + +static u8 *g_dma_page_ptr = NULL; +static u8 *g_dma_block = NULL; +static u8 *g_dma_block2 = NULL; + +/** \fn int dma_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Initialize DMA for DEU usage. DMA specific registers are + * intialized here, including a pointer to the device, memory + * space for the device and DEU-DMA descriptors + * \return -1 if fail, otherwise return 0 +*/ +static int dma_init(void) +{ + struct dma_device_info *dma_device = NULL; + int i = 0; + volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON; + struct dma_device_info *deu_dma_device_ptr; + + /* get one free page and share between g_dma_block and g_dma_block2 */ + printk("PAGE_SIZE = %ld\n", PAGE_SIZE); + /* need 16-byte alignment memory block */ + g_dma_page_ptr = (u8 *)__get_free_page(GFP_KERNEL); + /* need 16-byte alignment memory block */ + g_dma_block = g_dma_page_ptr; + /* need 16-byte alignment memory block */ + g_dma_block2 = (u8 *)(g_dma_page_ptr + (PAGE_SIZE >> 1)); + + deu_dma_device_ptr = dma_device_reserve("DEU"); + if (!deu_dma_device_ptr) { + printk("DEU: reserve DMA fail!\n"); + return -1; + } + lq_deu[0].dma_device = deu_dma_device_ptr; + dma_device = deu_dma_device_ptr; + /* dma_device->priv = &deu_dma_priv; */ + dma_device->buffer_alloc = &deu_dma_buffer_alloc; + dma_device->buffer_free = &deu_dma_buffer_free; + dma_device->intr_handler = &deu_dma_intr_handler; + dma_device->tx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; + dma_device->rx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; + dma_device->port_num = 1; + dma_device->tx_burst_len = 4; + dma_device->max_rx_chan_num = 1; + dma_device->max_tx_chan_num = 1; + dma_device->port_packet_drop_enable = 0; + + for (i = 0; i < dma_device->max_rx_chan_num; i++) { + dma_device->rx_chan[i]->packet_size = DEU_MAX_PACKET_SIZE; + dma_device->rx_chan[i]->desc_len = 1; + dma_device->rx_chan[i]->control = LQ_DMA_CH_ON; + dma_device->rx_chan[i]->byte_offset = 0; + dma_device->rx_chan[i]->chan_poll_enable = 1; + + } + + for (i = 0; i < dma_device->max_tx_chan_num; i++) { + dma_device->tx_chan[i]->control = LQ_DMA_CH_ON; + dma_device->tx_chan[i]->desc_len = 1; + dma_device->tx_chan[i]->chan_poll_enable = 1; + } + + dma_device->current_tx_chan = 0; + dma_device->current_rx_chan = 0; + + dma_device_register(dma_device); + for (i = 0; i < dma_device->max_rx_chan_num; i++) { + (dma_device->rx_chan[i])->open(dma_device->rx_chan[i]); + } + + dma->ctrl.BS = 0; + dma->ctrl.RXCLS = 0; + dma->ctrl.EN = 1; + + + *LQ_DMA_PS = 1; + + /* DANUBE PRE 1.4 SOFTWARE FIX */ + if (danube_pre_1_4) + *LQ_DMA_PCTRL = 0x14; + else + *LQ_DMA_PCTRL = 0xF14; + + return 0; +} + +/** \fn u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief A fix to align mis-aligned address for Danube version 1.3 chips + * which has memory alignment issues. + * \param arg Pointer to the input / output memory address + * \param buffer_alloc A pointer to the buffer + * \param in_buff Input (if == 1) or Output (if == 0) buffer + * \param nbytes Number of bytes of data + * \return returns arg: if address is aligned, buffer_alloc: if memory address is not aligned +*/ +static u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) +{ + if (danube_pre_1_4) { + /* for input buffer */ + if (in_buff) { + if (((u32) arg) & 0xF) { + memcpy(buffer_alloc, arg, nbytes); + return (u32 *) buffer_alloc; + } else { + return (u32 *) arg; + } + } + else { + /* for output buffer */ + if (((u32) arg) & 0x3) + return buffer_alloc; + else + return (u32 *) arg; + } + } + + return (u32 *) arg; +} + +/** \fn void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief copy the DMA data to the memory address space for AES. The swaping + * of the 4 bytes is done only for Danube version 1.3 (FIX). Otherwise, + * it is a direct memory copy to out_arg pointer + * \param outcopy Pointer to the address to store swapped copy + * \param out_dma A pointer to the memory address that stores the DMA data + * \param out_arg The pointer to the memory address that needs to be copied to + * \param nbytes Number of bytes of data +*/ +static void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) +{ + int i = 0; + int x = 0; + + /* DANUBE PRE 1.4 SOFTWARE FIX */ + if (danube_pre_1_4) { + for (i = 0; i < (nbytes / 4); i++) { + x = i ^ 0x3; + outcopy[i] = out_dma[x]; + + } + if (((u32) out_arg) & 0x3) { + memcpy((u8 *)out_arg, outcopy, nbytes); + } + } else { + memcpy(out_arg, out_dma, nbytes); + } +} + +/** \fn void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief copy the DMA data to the memory address space for DES. The swaping + * of the 4 bytes is done only for Danube version 1.3 (FIX). Otherwise, + * it is a direct memory copy to out_arg pointer + * \param outcopy Pointer to the address to store swapped copy + * \param out_dma A pointer to the memory address that stores the DMA data + * \param out_arg The pointer to the memory address that needs to be copied to + * \param nbytes Number of bytes of data +*/ +static void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) +{ + int i = 0; + int x = 0; + + /* DANUBE PRE 1.4 SOFTWARE FIX */ + if (danube_pre_1_4) { + for (i = 0; i < (nbytes / 4); i++) { + x = i ^ 1; + outcopy[i] = out_dma[x]; + + } + if (((u32) out_arg) & 0x3) { + memcpy((u8 *)out_arg, outcopy, nbytes); + } + } else { + memcpy(out_arg, out_dma, nbytes); + } +} + +/** \fn int des_dma_malloc(int value) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief allocates memory to the necessary memory input/output buffer + * location, used during the DES algorithm DMA transfer (memory + * alignment issues) + * \param value value determinds whether the calling of the function is for a + * input buffer or for an output buffer memory allocation +*/ +static int des_dma_malloc(int value) +{ + if (danube_pre_1_4) { + if (value == BUFFER_IN) { + des_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); + if (!des_buff_in) + return -1; + else + return 0; + } + else { + des_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); + if (!des_buff_out) + return -1; + else + return 0; + } + } else { + return 0; + } +} + +/** \fn int aes_dma_malloc(int value) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief allocates memory to the necessary memory input/output buffer + * location, used during the AES algorithm DMA transfer (memory + * alignment issues) + * \param value value determinds whether the calling of the function is for a + * input buffer or for an output buffer memory allocation +*/ +static int aes_dma_malloc(int value) +{ + if (danube_pre_1_4) { + if (value == BUFFER_IN) { + aes_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); + if (!aes_buff_in) + return -1; + else + return 0; + } + else { + aes_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); + if (!aes_buff_out) + return -1; + else + return 0; + } + } else { + return 0; + } +} + +/** \fn void dma_free(u32 *addr) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief frees previously allocated memory + * \param addr memory address of the buffer that needs to be freed +*/ +static void dma_free(u32 *addr) +{ + if (addr) + kfree(addr); + return; +} + +/** \fn dma_exit(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief unregister dma devices after exit +*/ +static void dma_exit(void) +{ + if (g_dma_page_ptr) + free_page((u32) g_dma_page_ptr); + dma_device_release(lq_deu[0].dma_device); + dma_device_unregister(lq_deu[0].dma_device); +} +#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */ + +/** \fn u32 endian_swap(u32 input) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief function is not used + * \param input Data input to be swapped + * \return input +*/ +static u32 endian_swap(u32 input) +{ + return input; +} + +/** \fn u32 input_swap(u32 input) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Swap the input data if the current chip is Danube version + * 1.4 and do nothing to the data if the current chip is + * Danube version 1.3 + * \param input data that needs to be swapped + * \return input or swapped input +*/ +static u32 input_swap(u32 input) +{ + if (!danube_pre_1_4) { + u8 *ptr = (u8 *)&input; + return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); + } else { + return input; + } +} + +/** \fn void aes_chip_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief initialize AES hardware +*/ +static void aes_chip_init(void) +{ + volatile struct deu_aes *aes = (struct deu_aes *) AES_START; + +#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA + /* start crypto engine with write to ILR */ + aes->ctrl.SM = 1; + aes->ctrl.ARS = 1; +#else + aes->ctrl.SM = 1; + aes->ctrl.ARS = 1; /* 0 for dma */ +#endif +} + +/** \fn void des_chip_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief initialize DES hardware +*/ +static void des_chip_init(void) +{ + volatile struct deu_des *des = (struct deu_des *) DES_3DES_START; + +#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA + /* start crypto engine with write to ILR */ + des->ctrl.SM = 1; + des->ctrl.ARS = 1; +#else + des->ctrl.SM = 1; + des->ctrl.ARS = 1; /* 0 for dma */ +#endif +} + +/** \fn void deu_chip_version(void) + * \ingroup LQ_DES_FUNCTIONS + * \brief To find the version of the chip by looking at the chip ID + * \param danube_pre_1_4 (sets to 1 if Chip is Danube less than v1.4) +*/ +static void deu_chip_version(void) +{ + /* DANUBE PRE 1.4 SOFTWARE FIX */ + int chip_id = 0; + chip_id = *LQ_MPS_CHIPID; + chip_id >>= 28; + + if (chip_id >= 4) { + danube_pre_1_4 = 0; + printk("Danube Chip ver. 1.4 detected. \n"); + } + else { + danube_pre_1_4 = 1; + printk("Danube Chip ver. 1.3 or below detected. \n"); + } +} + +static u32 chip_init(void) +{ + volatile struct deu_clk_ctrl *clc = (struct deu_clk_ctrl *) LQ_DEU_CLK; + +#if 0 + lq_pmu_enable(1<<20); +#endif + + deu_chip_version(); + + clc->FSOE = 0; + clc->SBWE = 0; + clc->SPEN = 0; + clc->SBWE = 0; + clc->DISS = 0; + clc->DISR = 0; + + return *LQ_DEU_ID; +} + +static int lq_crypto_probe(struct platform_device *pdev) +{ +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + lq_crypto_ops.dma_init = dma_init; + lq_crypto_ops.dma_exit = dma_exit; + lq_crypto_ops.aes_dma_memcpy = aes_dma_memcpy; + lq_crypto_ops.des_dma_memcpy = des_dma_memcpy; + lq_crypto_ops.aes_dma_malloc = aes_dma_malloc; + lq_crypto_ops.des_dma_malloc = des_dma_malloc; + lq_crypto_ops.dma_align = dma_align; + lq_crypto_ops.dma_free = dma_free; +#endif + + lq_crypto_ops.endian_swap = endian_swap; + lq_crypto_ops.input_swap = input_swap; + lq_crypto_ops.aes_chip_init = aes_chip_init; + lq_crypto_ops.des_chip_init = des_chip_init; + lq_crypto_ops.chip_init = chip_init; + + printk("lq_danube_deu: driver loaded!\n"); + + lq_deu_init(); + + return 0; +} + +static int lq_crypto_remove(struct platform_device *pdev) +{ + lq_deu_exit(); + + return 0; +} + +static struct platform_driver lq_crypto = { + .probe = lq_crypto_probe, + .remove = lq_crypto_remove, + .driver = { + .owner = THIS_MODULE, + .name = "lq_danube_deu" + } +}; + +static int __init lq_crypto_init(void) +{ + return platform_driver_register(&lq_crypto); +} +module_init(lq_crypto_init); + +static void __exit lq_crypto_exit(void) +{ + platform_driver_unregister(&lq_crypto); +} +module_exit(lq_crypto_exit); + +#endif --- /dev/null +++ b/drivers/crypto/lantiq/deu_danube.h @@ -0,0 +1,255 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief DEU driver module +*/ + +/** + \file deu_danube.h + \brief board specific driver header file for danube +*/ + +/** + \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS + \ingroup LQ_DEU + \brief board specific DEU header files +*/ + +#ifndef DEU_DANUBE_H +#define DEU_DANUBE_H + +#define LQ_DEU_BASE_ADDR (KSEG1 | 0x1E103100) +#define LQ_DEU_CLK ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0000)) +#define LQ_DEU_ID ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0008)) +#define LQ_DES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0010)) +#define LQ_AES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0050)) +#define LQ_HASH_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x00B0)) +#define LQ_ARC4_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0100)) + +#define ARC4_START LQ_ARC4_CON +#define DES_3DES_START LQ_DES_CON +#define HASH_START LQ_HASH_CON +#define AES_START LQ_AES_CON + +#define LQ_MPS (KSEG1 | 0x1F107000) +#define LQ_MPS_CHIPID ((volatile u32*)(LQ_MPS + 0x0344)) +#define LQ_MPS_CHIPID_VERSION_GET(value) (((value) >> 28) & 0xF) +#define LQ_MPS_CHIPID_VERSION_SET(value) (((value) & 0xF) << 28) +#define LQ_MPS_CHIPID_PARTNUM_GET(value) (((value) >> 12) & 0xFFFF) +#define LQ_MPS_CHIPID_PARTNUM_SET(value) (((value) & 0xFFFF) << 12) +#define LQ_MPS_CHIPID_MANID_GET(value) (((value) >> 1) & 0x7FF) +#define LQ_MPS_CHIPID_MANID_SET(value) (((value) & 0x7FF) << 1) + +#ifdef CONFIG_CRYPTO_DEV_DMA +# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \ + deu_dma_align(ptr, buffer, in_out, bytes) +# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ + deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes) +# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ + deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes) +# define BUFFER_IN 1 +# define BUFFER_OUT 0 +# define DELAY_PERIOD 9 +# define AES_ALGO 1 +# define DES_ALGO 0 +# define FREE_MEMORY(buff) deu_dma_free(buff) +# define ALLOCATE_MEMORY(val, type) type ? \ + deu_aes_dma_malloc(val) : \ + deu_des_dma_malloc(val) +#endif /* CONFIG_CRYPTO_DEV_DMA */ + +#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input) +#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input) +#define AES_DMA_MISC_CONFIG() + +#define WAIT_AES_DMA_READY() \ + do { \ + int i; \ + volatile struct deu_dma *dma = \ + (struct deu_dma *) LQ_DEU_DMA_CON; \ + volatile struct deu_aes *aes = \ + (volatile struct deu_aes *) AES_START; \ + for (i = 0; i < 10; i++) \ + udelay(DELAY_PERIOD); \ + while (dma->ctrl.BSY) {}; \ + while (aes->ctrl.BUS) {}; \ + } while (0) + +#define WAIT_DES_DMA_READY() \ + do { \ + int i; \ + volatile struct deu_dma *dma = \ + (struct deu_dma *) LQ_DEU_DMA_CON; \ + volatile struct deu_des *des = \ + (struct deu_des *) DES_3DES_START; \ + for (i = 0; i < 10; i++) \ + udelay(DELAY_PERIOD); \ + while (dma->ctrl.BSY) {}; \ + while (des->ctrl.BUS) {}; \ + } while (0) + +#define SHA_HASH_INIT \ + do { \ + volatile struct deu_hash *hash = \ + (struct deu_hash *) HASH_START; \ + hash->ctrl.SM = 1; \ + hash->ctrl.ALGO = 0; \ + hash->ctrl.INIT = 1; \ + } while(0) + +/* DEU STRUCTURES */ + +struct deu_clk_ctrl { + u32 Res:26; + u32 FSOE:1; + u32 SBWE:1; + u32 EDIS:1; + u32 SPEN:1; + u32 DISS:1; + u32 DISR:1; +}; + +struct deu_des { + struct deu_des_ctrl { + u32 KRE:1; + u32 reserved1:5; + u32 GO:1; + u32 STP:1; + u32 Res2:6; + u32 NDC:1; + u32 ENDI:1; + u32 Res3:2; + u32 F:3; + u32 O:3; + u32 BUS:1; + u32 DAU:1; + u32 ARS:1; + u32 SM:1; + u32 E_D:1; + u32 M:3; + } ctrl; + + u32 IHR; + u32 ILR; + u32 K1HR; + u32 K1LR; + u32 K2HR; + u32 K2LR; + u32 K3HR; + u32 K3LR; + u32 IVHR; + u32 IVLR; + u32 OHR; + u32 OLR; +}; + +struct deu_aes { + struct deu_aes_ctrl { + u32 KRE:1; + u32 reserved1:4; + u32 PNK:1; + u32 GO:1; + u32 STP:1; + u32 reserved2:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved3:2; + u32 F:3; /* fbs */ + u32 O:3; /* om */ + u32 BUS:1; /* bsy */ + u32 DAU:1; + u32 ARS:1; + u32 SM:1; + u32 E_D:1; + u32 KV:1; + u32 K:2; /* KL */ + } ctrl; + + u32 ID3R; /* 80h */ + u32 ID2R; /* 84h */ + u32 ID1R; /* 88h */ + u32 ID0R; /* 8Ch */ + u32 K7R; /* 90h */ + u32 K6R; /* 94h */ + u32 K5R; /* 98h */ + u32 K4R; /* 9Ch */ + u32 K3R; /* A0h */ + u32 K2R; /* A4h */ + u32 K1R; /* A8h */ + u32 K0R; /* ACh */ + u32 IV3R; /* B0h */ + u32 IV2R; /* B4h */ + u32 IV1R; /* B8h */ + u32 IV0R; /* BCh */ + u32 OD3R; /* D4h */ + u32 OD2R; /* D8h */ + u32 OD1R; /* DCh */ + u32 OD0R; /* E0h */ +}; + +struct deu_hash { + struct deu_hash_ctrl { + u32 reserved1:5; + u32 KHS:1; + u32 GO:1; + u32 INIT:1; + u32 reserved2:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved3:7; + u32 DGRY:1; + u32 BSY:1; + u32 reserved4:1; + u32 IRCL:1; + u32 SM:1; + u32 KYUE:1; + u32 HMEN:1; + u32 SSEN:1; + u32 ALGO:1; + } ctrl; + + u32 MR; /* B4h */ + u32 D1R; /* B8h */ + u32 D2R; /* BCh */ + u32 D3R; /* C0h */ + u32 D4R; /* C4h */ + u32 D5R; /* C8h */ + u32 dummy; /* CCh */ + u32 KIDX; /* D0h */ + u32 KEY; /* D4h */ + u32 DBN; /* D8h */ +}; + +struct deu_dma { + struct deu_dma_ctrl { + u32 reserved1:22; + u32 BS:2; + u32 BSY:1; + u32 reserved2:1; + u32 ALGO:2; + u32 RXCLS:2; + u32 reserved3:1; + u32 EN:1; + } ctrl; +}; + +#endif /* DEU_DANUBE_H */ --- /dev/null +++ b/drivers/crypto/lantiq/deu_dma.c @@ -0,0 +1,147 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup LQ_API + \brief Lantiq DEU driver module +*/ + +/** + \file deu_dma.c + \ingroup LQ_DEU + \brief DMA DEU driver file +*/ + +/** + \defgroup LQ_DMA_FUNCTIONS LQ_DMA_FUNCTIONS + \ingroup LQ_DEU + \brief DMA DEU driver functions +*/ + +#include +#include +#include +#include +#include +#include +#include "deu.h" +#include "deu_dma.h" + +/* extern struct deu_drv_priv deu_dma_priv; */ + +/** \fn int deu_dma_intr_handler(struct dma_device_info *dma_dev, int status) + * \ingroup LQ_DMA_FUNCTIONS + * \brief callback function for DEU DMA interrupt + * \param dma_dev dma device + * \param status not used +*/ +int deu_dma_intr_handler(struct dma_device_info *dma_dev, int status) +{ +#if 0 + int len = 0; + while (len <= 20000) { len++; } + u8 *buf; + int len = 0; + + struct deu_drv_priv *deu_priv = (struct deu_drv_priv *)dma_dev->priv; + /* printk("status:%d \n",status); */ + switch(status) { + case RCV_INT: + len = dma_device_read(dma_dev, (u8 **)&buf, NULL); + if ( len != deu_priv->deu_rx_len) { + printk(KERN_ERR "%s packet length %d is not " + "equal to expect %d\n", + __func__, len, deu_priv->deu_rx_len); + return -1; + } + memcpy(deu_priv->deu_rx_buf, buf, deu_priv->deu_rx_len); + /* Reset for next usage */ + deu_priv->deu_rx_buf = NULL; + deu_priv->deu_rx_len = 0; + DEU_WAKEUP_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, + deu_priv->deu_event_flags); + break; + case TX_BUF_FULL_INT: + /* delay for buffer to be cleared */ + while (len <= 20000) { len++; } + break; + + case TRANSMIT_CPT_INT: + break; + default: + break; + } +#endif + return 0; +} + +extern u8 *g_dma_block; +extern u8 *g_dma_block2; + +/** \fn u8 *deu_dma_buffer_alloc(int len, int *byte_offset, void **opt) + * \ingroup LQ_DMA_FUNCTIONS + * \brief callback function for allocating buffers for dma receive descriptors + * \param len not used + * \param byte_offset dma byte offset + * \param *opt not used + * +*/ +u8 *deu_dma_buffer_alloc(int len, int *byte_offset, void **opt) +{ + u8 *swap = NULL; + + /* dma-core needs at least 2 blocks of memory */ + swap = g_dma_block; + g_dma_block = g_dma_block2; + g_dma_block2 = swap; + + /* dma_cache_wback_inv((unsigned long) g_dma_block,(PAGE_SIZE >> 1)); */ + *byte_offset = 0; + + return g_dma_block; +} + +/** \fn int deu_dma_buffer_free(u8 * dataptr, void *opt) + * \ingroup LQ_DMA_FUNCTIONS + * \brief callback function for freeing dma transmit descriptors + * \param dataptr data pointer to be freed + * \param opt not used +*/ +int deu_dma_buffer_free(u8 *dataptr, void *opt) +{ +#if 0 + printk("Trying to free memory buffer\n"); + if (dataptr == NULL && opt == NULL) + return 0; + else if (opt == NULL) { + kfree(dataptr); + return 1; + } + else if (dataptr == NULL) { + kfree(opt); + return 1; + } + else { + kfree(opt); + kfree(dataptr); + } +#endif + return 0; +} --- /dev/null +++ b/drivers/crypto/lantiq/deu_dma.h @@ -0,0 +1,78 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \addtogroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file deu_dma.h + \ingroup LQ_DEU + \brief DMA DEU driver header file +*/ + +#ifndef DEU_DMA_H +#define DEU_DMA_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifndef CONFIG_CRYPTO_DEV_POLL_DMA +# define CONFIG_CRYPTO_DEV_POLL_DMA +#endif + +/* must match the size of memory block allocated for + * g_dma_block and g_dma_block2 */ +#define DEU_MAX_PACKET_SIZE (PAGE_SIZE >> 1) + +struct lq_deu_device { + struct dma_device_info *dma_device; + u8 *dst; + u8 *src; + int len; + int dst_count; + int src_count; + int recv_count; + int packet_size; + int packet_num; + wait_queue_t wait; +}; + +extern struct lq_deu_device lq_deu[1]; + +extern int deu_dma_intr_handler(struct dma_device_info *, int); +extern u8 *deu_dma_buffer_alloc(int, int *, void **); +extern int deu_dma_buffer_free(u8 *, void *); +extern void deu_dma_inactivate_poll(struct dma_device_info* dma_dev); +extern void deu_dma_activate_poll(struct dma_device_info* dma_dev); +extern struct dma_device_info* deu_dma_reserve(struct dma_device_info** + dma_device); +extern int deu_dma_release(struct dma_device_info** dma_device); + +#endif /* IFMIPS_DEU_DMA_H */ --- /dev/null +++ b/drivers/crypto/lantiq/md5.c @@ -0,0 +1,285 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file md5.c + \ingroup LQ_DEU + \brief MD5 encryption DEU driver file +*/ + +/** + \defgroup LQ_MD5_FUNCTIONS LQ_MD5_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq DEU MD5 functions +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "deu.h" + +#define MD5_DIGEST_SIZE 16 +#define MD5_HMAC_BLOCK_SIZE 64 +#define MD5_BLOCK_WORDS 16 +#define MD5_HASH_WORDS 4 + +static spinlock_t cipher_lock; + +struct md5_ctx { + u32 hash[MD5_HASH_WORDS]; + u32 block[MD5_BLOCK_WORDS]; + u64 byte_count; +}; + +/** \fn static u32 md5_endian_swap(u32 input) + * \ingroup LQ_MD5_FUNCTIONS + * \brief perform dword level endian swap + * \param input value of dword that requires to be swapped +*/ +static u32 md5_endian_swap(u32 input) +{ + u8 *ptr = (u8 *)&input; + + return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); +} + +/** \fn static void md5_transform(u32 *hash, u32 const *in) + * \ingroup LQ_MD5_FUNCTIONS + * \brief main interface to md5 hardware + * \param hash current hash value + * \param in 64-byte block of input +*/ +static void md5_transform(u32 *hash, u32 const *in) +{ + int i; + volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; + ulong flag; + + CRTCL_SECT_START; + + for (i = 0; i < 16; i++) { + hashs->MR = md5_endian_swap(in[i]); + }; + + /* wait for processing */ + while (hashs->ctrl.BSY) { + /* this will not take long */ + } + + CRTCL_SECT_END; +} + +/** \fn static inline void md5_transform_helper(struct md5_ctx *ctx) + * \ingroup LQ_MD5_FUNCTIONS + * \brief interfacing function for md5_transform() + * \param ctx crypto context +*/ +static inline void md5_transform_helper(struct md5_ctx *ctx) +{ + /* le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); */ + md5_transform(ctx->hash, ctx->block); +} + +/** \fn static void md5_init(struct crypto_tfm *tfm) + * \ingroup LQ_MD5_FUNCTIONS + * \brief initialize md5 hardware + * \param tfm linux crypto algo transform +*/ +static int md5_init(struct shash_desc *desc) +{ + struct md5_ctx *mctx = shash_desc_ctx(desc); + volatile struct deu_hash *hash = (struct deu_hash *) HASH_START; + + hash->ctrl.SM = 1; + hash->ctrl.ALGO = 1; /* 1 = md5 0 = sha1 */ + hash->ctrl.INIT = 1; /* Initialize the hash operation by writing + a '1' to the INIT bit. */ + + mctx->byte_count = 0; + + return 0; +} + +/** \fn static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) + * \ingroup LQ_MD5_FUNCTIONS + * \brief on-the-fly md5 computation + * \param tfm linux crypto algo transform + * \param data input data + * \param len size of input data +*/ +static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len) +{ + struct md5_ctx *mctx = shash_desc_ctx(desc); + const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); + + mctx->byte_count += len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + return 0; + } + + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, avail); + + md5_transform_helper(mctx); + data += avail; + len -= avail; + + while (len >= sizeof(mctx->block)) { + memcpy(mctx->block, data, sizeof(mctx->block)); + md5_transform_helper(mctx); + data += sizeof(mctx->block); + len -= sizeof(mctx->block); + } + + memcpy(mctx->block, data, len); + + return 0; +} + +/** \fn static void md5_final(struct crypto_tfm *tfm, u8 *out) + * \ingroup LQ_MD5_FUNCTIONS + * \brief compute final md5 value + * \param tfm linux crypto algo transform + * \param out final md5 output value +*/ +static int md5_final(struct shash_desc *desc, u8 *out) +{ + struct md5_ctx *mctx = shash_desc_ctx(desc); + const unsigned int offset = mctx->byte_count & 0x3f; + char *p = (char *)mctx->block + offset; + int padding = 56 - (offset + 1); + volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; + unsigned long flag; + + *p++ = 0x80; + if (padding < 0) { + memset(p, 0x00, padding + sizeof (u64)); + md5_transform_helper(mctx); + p = (char *)mctx->block; + padding = 56; + } + + memset(p, 0, padding); + mctx->block[14] = md5_endian_swap(mctx->byte_count << 3); + mctx->block[15] = md5_endian_swap(mctx->byte_count >> 29); + +#if 0 + le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - + sizeof(u64)) / sizeof(u32)); +#endif + + md5_transform(mctx->hash, mctx->block); + + CRTCL_SECT_START; + + *((u32 *) out + 0) = md5_endian_swap(hashs->D1R); + *((u32 *) out + 1) = md5_endian_swap(hashs->D2R); + *((u32 *) out + 2) = md5_endian_swap(hashs->D3R); + *((u32 *) out + 3) = md5_endian_swap(hashs->D4R); + + CRTCL_SECT_END; + + /* Wipe context */ + memset(mctx, 0, sizeof(*mctx)); + + return 0; +} + +static int md5_export(struct shash_desc *desc, void *out) +{ + struct md5_ctx *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int md5_import(struct shash_desc *desc, const void *in) +{ + struct md5_ctx *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +/* + * \brief MD5 function mappings +*/ +static struct shash_alg md5_alg = { + .digestsize = MD5_DIGEST_SIZE, + .init = md5_init, + .update = md5_update, + .final = md5_final, + .export = md5_export, + .import = md5_import, + .descsize = sizeof(struct md5_ctx), + .statesize = sizeof(struct md5_ctx), + .base = { + .cra_name = "md5", + .cra_driver_name = "lq_deu-md5", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +/** \fn int lq_deu_init_md5(void) + * \ingroup LQ_MD5_FUNCTIONS + * \brief initialize md5 driver +*/ +int lq_deu_init_md5(void) +{ + int ret; + + if ((ret = crypto_register_shash(&md5_alg))) + goto md5_err; + + CRTCL_SECT_INIT; + + printk(KERN_NOTICE "Lantiq DEU MD5 initialized%s.\n", + disable_deudma ? "" : " (DMA)"); + return ret; + +md5_err: + printk(KERN_ERR "Lantiq DEU MD5 initialization failed!\n"); + return ret; +} + +/** \fn void lq_deu_fini_md5(void) + * \ingroup LQ_MD5_FUNCTIONS + * \brief unregister md5 driver +*/ + +void lq_deu_fini_md5(void) +{ + crypto_unregister_shash(&md5_alg); +} + --- /dev/null +++ b/drivers/crypto/lantiq/md5_hmac.c @@ -0,0 +1,329 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file md5_hmac.c + \ingroup LQ_DEU + \brief MD5-HMAC encryption DEU driver file +*/ + +/** + \defgroup LQ_MD5_HMAC_FUNCTIONS LQ_MD5_HMAC_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq md5-hmac driver functions +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "deu.h" + +#define MD5_DIGEST_SIZE 16 +#define MD5_HMAC_BLOCK_SIZE 64 +#define MD5_BLOCK_WORDS 16 +#define MD5_HASH_WORDS 4 +#define MD5_HMAC_DBN_TEMP_SIZE 1024 /* size in dword, + needed for dbn workaround */ + +static spinlock_t cipher_lock; + +struct md5_hmac_ctx { + u32 hash[MD5_HASH_WORDS]; + u32 block[MD5_BLOCK_WORDS]; + u64 byte_count; + u32 dbn; + u32 temp[MD5_HMAC_DBN_TEMP_SIZE]; +}; + +/** \fn static u32 md5_endian_swap(u32 input) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief perform dword level endian swap + * \param input value of dword that requires to be swapped +*/ +static u32 md5_endian_swap(u32 input) +{ + u8 *ptr = (u8 *)&input; + + return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); +} + +/** \fn static void md5_hmac_transform(struct crypto_tfm *tfm, u32 const *in) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief save input block to context + * \param tfm linux crypto algo transform + * \param in 64-byte block of input +*/ +static void md5_hmac_transform(struct shash_desc *desc, u32 const *in) +{ + struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); + + memcpy(&mctx->temp[mctx->dbn<<4], in, 64); /* dbn workaround */ + mctx->dbn += 1; + + if ( (mctx->dbn<<4) > MD5_HMAC_DBN_TEMP_SIZE ) + { + printk("MD5_HMAC_DBN_TEMP_SIZE exceeded\n"); + } +} + +/** \fn int md5_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief sets md5 hmac key + * \param tfm linux crypto algo transform + * \param key input key + * \param keylen key length greater than 64 bytes IS NOT SUPPORTED +*/ +static int md5_hmac_setkey(struct crypto_shash *tfm, + const u8 *key, + unsigned int keylen) +{ + volatile struct deu_hash *hash = (struct deu_hash *) HASH_START; + int i, j; + u32 *in_key = (u32 *)key; + + hash->KIDX = 0x80000000; /* reset all 16 words of the key to '0' */ + asm("sync"); + + j = 0; + for (i = 0; i < keylen; i+=4) + { + hash->KIDX = j; + asm("sync"); + hash->KEY = *((u32 *) in_key + j); + j++; + } + + return 0; +} + +/** \fn void md5_hmac_init(struct crypto_tfm *tfm) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief initialize md5 hmac context + * \param tfm linux crypto algo transform +*/ +static int md5_hmac_init(struct shash_desc *desc) +{ + struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); + + memset(mctx, 0, sizeof(struct md5_hmac_ctx)); + mctx->dbn = 0; /* dbn workaround */ + return 0; +} + +/** \fn void md5_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief on-the-fly md5 hmac computation + * \param tfm linux crypto algo transform + * \param data input data + * \param len size of input data +*/ +static int md5_hmac_update(struct shash_desc *desc, + const u8 *data, + unsigned int len) +{ + struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); + const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); + + mctx->byte_count += len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + return 0; + } + + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, avail); + + md5_hmac_transform(desc, mctx->block); + data += avail; + len -= avail; + + while (len >= sizeof(mctx->block)) { + memcpy(mctx->block, data, sizeof(mctx->block)); + md5_hmac_transform(desc, mctx->block); + data += sizeof(mctx->block); + len -= sizeof(mctx->block); + } + + memcpy(mctx->block, data, len); + + return 0; +} + +/** \fn void md5_hmac_final(struct crypto_tfm *tfm, u8 *out) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief compute final md5 hmac value + * \param tfm linux crypto algo transform + * \param out final md5 hmac output value +*/ +static int md5_hmac_final(struct shash_desc *desc, u8 *out) +{ + struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); + const unsigned int offset = mctx->byte_count & 0x3f; + char *p = (char *)mctx->block + offset; + int padding = 56 - (offset + 1); + volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; + u32 flag; + int i = 0; + int dbn; + u32 *in = &mctx->temp[0]; + + *p++ = 0x80; + if (padding < 0) { + memset(p, 0x00, padding + sizeof (u64)); + md5_hmac_transform(desc, mctx->block); + p = (char *)mctx->block; + padding = 56; + } + + memset(p, 0, padding); + /* need to add 512 bit of the IPAD operation */ + mctx->block[14] = md5_endian_swap((mctx->byte_count + 64) << 3); + mctx->block[15] = 0x00000000; + + md5_hmac_transform(desc, mctx->block); + + CRTCL_SECT_START; + + printk("dbn = %d\n", mctx->dbn); + hashs->DBN = mctx->dbn; + + /* khs, go, init, ndc, endi, kyue, hmen, md5 */ + *LQ_HASH_CON = 0x0703002D; + + /* wait for processing */ + while (hashs->ctrl.BSY) { + /* this will not take long */ + } + + for (dbn = 0; dbn < mctx->dbn; dbn++) + { + for (i = 0; i < 16; i++) { + hashs->MR = in[i]; + }; + + hashs->ctrl.GO = 1; + asm("sync"); + + /* wait for processing */ + while (hashs->ctrl.BSY) { + /* this will not take long */ + } + + in += 16; + } + +#if 1 + /* wait for digest ready */ + while (! hashs->ctrl.DGRY) { + /* this will not take long */ + } +#endif + + *((u32 *) out + 0) = hashs->D1R; + *((u32 *) out + 1) = hashs->D2R; + *((u32 *) out + 2) = hashs->D3R; + *((u32 *) out + 3) = hashs->D4R; + *((u32 *) out + 4) = hashs->D5R; + + CRTCL_SECT_END; + + return 0; +} + +static int md5_hmac_export(struct shash_desc *desc, void *out) +{ + struct md5_hmac_ctx *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int md5_hmac_import(struct shash_desc *desc, const void *in) +{ + struct md5_hmac_ctx *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +/* + * \brief MD5_HMAC function mappings +*/ +static struct shash_alg md5_hmac_alg = { + .digestsize = MD5_DIGEST_SIZE, + .init = md5_hmac_init, + .update = md5_hmac_update, + .final = md5_hmac_final, + .setkey = md5_hmac_setkey, + .export = md5_hmac_export, + .import = md5_hmac_import, + .descsize = sizeof(struct md5_hmac_ctx), + .statesize = sizeof(struct md5_hmac_ctx), + .base = { + .cra_name = "hmac(md5)", + .cra_driver_name = "lq_deu-md5_hmac", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +/** \fn int lq_deu_init_md5_hmac(void) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief initialize md5 hmac driver +*/ +int lq_deu_init_md5_hmac(void) +{ + int ret; + + if ((ret = crypto_register_shash(&md5_hmac_alg))) + goto md5_hmac_err; + + CRTCL_SECT_INIT; + + printk(KERN_NOTICE "Lantiq DEU MD5_HMAC initialized%s.\n", + disable_deudma ? "" : " (DMA)"); + return ret; + +md5_hmac_err: + printk(KERN_ERR "Lantiq DEU MD5_HMAC initialization failed!\n"); + return ret; +} + +/** \fn void lq_deu_fini_md5_hmac(void) + * \ingroup LQ_MD5_HMAC_FUNCTIONS + * \brief unregister md5 hmac driver +*/ +void lq_deu_fini_md5_hmac(void) +{ + crypto_unregister_shash(&md5_hmac_alg); +} + --- /dev/null +++ b/drivers/crypto/lantiq/sha1.c @@ -0,0 +1,262 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file sha1.c + \ingroup LQ_DEU + \brief SHA1 encryption DEU driver file +*/ + +/** + \defgroup LQ_SHA1_FUNCTIONS LQ_SHA1_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq DEU sha1 functions +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "deu.h" + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_HMAC_BLOCK_SIZE 64 + +static spinlock_t cipher_lock; + +/* + * \brief SHA1 private structure +*/ +struct sha1_ctx { + u64 count; + u32 state[5]; + u8 buffer[64]; +}; + +/** \fn static void sha1_transform(u32 *state, const u32 *in) + * \ingroup LQ_SHA1_FUNCTIONS + * \brief main interface to sha1 hardware + * \param state current state + * \param in 64-byte block of input +*/ +static void sha1_transform(u32 *state, const u32 *in) +{ + int i = 0; + volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; + unsigned long flag; + + CRTCL_SECT_START; + + for (i = 0; i < 16; i++) { + hashs->MR = in[i]; + }; + + /* wait for processing */ + while (hashs->ctrl.BSY) { + /* this will not take long */ + } + + CRTCL_SECT_END; +} + +/** \fn static void sha1_init(struct crypto_tfm *tfm) + * \ingroup LQ_SHA1_FUNCTIONS + * \brief initialize sha1 hardware + * \param tfm linux crypto algo transform +*/ +static int sha1_init(struct shash_desc *desc) +{ + struct sha1_ctx *sctx = shash_desc_ctx(desc); + + SHA_HASH_INIT; + + sctx->count = 0; + + return 0; +} + +/** \fn static void sha1_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) + * \ingroup LQ_SHA1_FUNCTIONS + * \brief on-the-fly sha1 computation + * \param tfm linux crypto algo transform + * \param data input data + * \param len size of input data +*/ +static int sha1_update(struct shash_desc *desc, const u8 *data, unsigned int len) +{ + struct sha1_ctx *sctx = shash_desc_ctx(desc); + unsigned int i, j; + + j = (sctx->count >> 3) & 0x3f; + sctx->count += len << 3; + + if ((j + len) > 63) { + memcpy(&sctx->buffer[j], data, (i = 64 - j)); + sha1_transform(sctx->state, (const u32 *)sctx->buffer); + for (; i + 63 < len; i += 64) { + sha1_transform(sctx->state, (const u32 *)&data[i]); + } + + j = 0; + } else { + i = 0; + } + + memcpy(&sctx->buffer[j], &data[i], len - i); + + return 0; +} + +/** \fn static void sha1_final(struct crypto_tfm *tfm, u8 *out) + * \ingroup LQ_SHA1_FUNCTIONS + * \brief compute final sha1 value + * \param tfm linux crypto algo transform + * \param out final md5 output value +*/ +static int sha1_final(struct shash_desc *desc, u8 *out) +{ + struct sha1_ctx *sctx = shash_desc_ctx(desc); + u32 index, padlen; + u64 t; + u8 bits[8] = { 0, }; + static const u8 padding[64] = { 0x80, }; + volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; + ulong flag; + + t = sctx->count; + bits[7] = 0xff & t; + t >>= 8; + bits[6] = 0xff & t; + t >>= 8; + bits[5] = 0xff & t; + t >>= 8; + bits[4] = 0xff & t; + t >>= 8; + bits[3] = 0xff & t; + t >>= 8; + bits[2] = 0xff & t; + t >>= 8; + bits[1] = 0xff & t; + t >>= 8; + bits[0] = 0xff & t; + + /* Pad out to 56 mod 64 */ + index = (sctx->count >> 3) & 0x3f; + padlen = (index < 56) ? (56 - index) : ((64 + 56) - index); + sha1_update(desc, padding, padlen); + + /* Append length */ + sha1_update(desc, bits, sizeof bits); + + CRTCL_SECT_START; + + *((u32 *) out + 0) = hashs->D1R; + *((u32 *) out + 1) = hashs->D2R; + *((u32 *) out + 2) = hashs->D3R; + *((u32 *) out + 3) = hashs->D4R; + *((u32 *) out + 4) = hashs->D5R; + + CRTCL_SECT_END; + + /* Wipe context*/ + memset(sctx, 0, sizeof *sctx); + + return 0; +} + +static int sha1_export(struct shash_desc *desc, void *out) +{ + struct sha1_ctx *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int sha1_import(struct shash_desc *desc, const void *in) +{ + struct sha1_ctx *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +/* + * \brief SHA1 function mappings +*/ +static struct shash_alg deu_sha1_alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = sha1_init, + .update = sha1_update, + .final = sha1_final, + .export = sha1_export, + .import = sha1_import, + .descsize = sizeof(struct sha1_ctx), + .statesize = sizeof(struct sha1_ctx), + .base = { + .cra_name = "sha1", + .cra_driver_name = "lq_deu-sha1", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +/** \fn int lq_deu_init_sha1(void) + * \ingroup LQ_SHA1_FUNCTIONS + * \brief initialize sha1 driver +*/ +int lq_deu_init_sha1(void) +{ + int ret; + + if ((ret = crypto_register_shash(&deu_sha1_alg))) + goto sha1_err; + + CRTCL_SECT_INIT; + + printk(KERN_NOTICE "Lantiq DEU SHA1 initialized%s.\n", + disable_deudma ? "" : " (DMA)"); + return ret; + +sha1_err: + printk(KERN_ERR "Lantiq DEU SHA1 initialization failed!\n"); + return ret; +} + +/** \fn void lq_deu_fini_sha1(void) + * \ingroup LQ_SHA1_FUNCTIONS + * \brief unregister sha1 driver +*/ +void lq_deu_fini_sha1(void) +{ + crypto_unregister_shash(&deu_sha1_alg); +} --- /dev/null +++ b/drivers/crypto/lantiq/sha1_hmac.c @@ -0,0 +1,325 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file sha1_hmac.c + \ingroup LQ_DEU + \brief SHA1-HMAC DEU driver file +*/ + +/** + \defgroup LQ_SHA1_HMAC_FUNCTIONS LQ_SHA1_HMAC_FUNCTIONS + \ingroup LQ_DEU + \brief Lantiq sha1 hmac functions +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "deu.h" + +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_HMAC_BLOCK_SIZE 64 +/* size in dword, needed for dbn workaround */ +#define SHA1_HMAC_DBN_TEMP_SIZE 1024 + +static spinlock_t cipher_lock; + +struct sha1_hmac_ctx { + u64 count; + u32 state[5]; + u8 buffer[64]; + u32 dbn; + u32 temp[SHA1_HMAC_DBN_TEMP_SIZE]; +}; + +/** \fn static void sha1_hmac_transform(struct crypto_tfm *tfm, u32 const *in) + * \ingroup LQ_SHA1_HMAC_FUNCTIONS + * \brief save input block to context + * \param tfm linux crypto algo transform + * \param in 64-byte block of input +*/ +static void sha1_hmac_transform(struct shash_desc *desc, u32 const *in) +{ + struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); + + memcpy(&sctx->temp[sctx->dbn<<4], in, 64); /* dbn workaround */ + sctx->dbn += 1; + + if ((sctx->dbn<<4) > SHA1_HMAC_DBN_TEMP_SIZE) { + printk("SHA1_HMAC_DBN_TEMP_SIZE exceeded\n"); + } +} + +/** \fn int sha1_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) + * \ingroup LQ_SHA1_HMAC_FUNCTIONS + * \brief sets sha1 hmac key + * \param tfm linux crypto algo transform + * \param key input key + * \param keylen key length greater than 64 bytes IS NOT SUPPORTED +*/ +static int sha1_hmac_setkey(struct crypto_shash *tfm, + const u8 *key, + unsigned int keylen) +{ + volatile struct deu_hash *hash = (struct deu_hash *) HASH_START; + int i, j; + u32 *in_key = (u32 *)key; + + hash->KIDX = 0x80000000; /* reset all 16 words of the key to '0' */ + asm("sync"); + + j = 0; + for (i = 0; i < keylen; i+=4) + { + hash->KIDX = j; + asm("sync"); + hash->KEY = *((u32 *) in_key + j); + j++; + } + + return 0; +} + +static int sha1_hmac_export(struct shash_desc *desc, void *out) +{ + struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int sha1_hmac_import(struct shash_desc *desc, const void *in) +{ + struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +/** \fn void sha1_hmac_init(struct crypto_tfm *tfm) + * \ingroup LQ_SHA1_HMAC_FUNCTIONS + * \brief initialize sha1 hmac context + * \param tfm linux crypto algo transform +*/ +static int sha1_hmac_init(struct shash_desc *desc) +{ + struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx, 0, sizeof(struct sha1_hmac_ctx)); + sctx->dbn = 0; /* dbn workaround */ + + return 0; +} + +/** \fn static void sha1_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) + * \ingroup LQ_SHA1_HMAC_FUNCTIONS + * \brief on-the-fly sha1 hmac computation + * \param tfm linux crypto algo transform + * \param data input data + * \param len size of input data +*/ +static int sha1_hmac_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); + unsigned int i, j; + + j = (sctx->count >> 3) & 0x3f; + sctx->count += len << 3; + /* printk("sctx->count = %d\n", (sctx->count >> 3)); */ + + if ((j + len) > 63) { + memcpy(&sctx->buffer[j], data, (i = 64 - j)); + sha1_hmac_transform(desc, (const u32 *)sctx->buffer); + for (; i + 63 < len; i += 64) { + sha1_hmac_transform(desc, (const u32 *)&data[i]); + } + + j = 0; + } else { + i = 0; + } + + memcpy(&sctx->buffer[j], &data[i], len - i); + + return 0; +} + +/** \fn static void sha1_hmac_final(struct crypto_tfm *tfm, u8 *out) + * \ingroup LQ_SHA1_HMAC_FUNCTIONS + * \brief ompute final sha1 hmac value + * \param tfm linux crypto algo transform + * \param out final sha1 hmac output value +*/ +static int sha1_hmac_final(struct shash_desc *desc, u8 *out) +{ + struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); + u32 index, padlen; + u64 t; + u8 bits[8] = { 0, }; + static const u8 padding[64] = { 0x80, }; + volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; + ulong flag; + int i = 0; + int dbn; + u32 *in = &sctx->temp[0]; + + t = sctx->count + 512; /* need to add 512 bit of the IPAD operation */ + bits[7] = 0xff & t; + t >>= 8; + bits[6] = 0xff & t; + t >>= 8; + bits[5] = 0xff & t; + t >>= 8; + bits[4] = 0xff & t; + t >>= 8; + bits[3] = 0xff & t; + t >>= 8; + bits[2] = 0xff & t; + t >>= 8; + bits[1] = 0xff & t; + t >>= 8; + bits[0] = 0xff & t; + + /* Pad out to 56 mod 64 */ + index = (sctx->count >> 3) & 0x3f; + padlen = (index < 56) ? (56 - index) : ((64 + 56) - index); + sha1_hmac_update(desc, padding, padlen); + + /* Append length */ + sha1_hmac_update(desc, bits, sizeof bits); + + CRTCL_SECT_START; + + hashs->DBN = sctx->dbn; + + /* for vr9 change, ENDI = 1 */ + *LQ_HASH_CON = HASH_CON_VALUE; + + /* wait for processing */ + while (hashs->ctrl.BSY) { + /* this will not take long */ + } + + for (dbn = 0; dbn < sctx->dbn; dbn++) + { + for (i = 0; i < 16; i++) { + hashs->MR = in[i]; + }; + + hashs->ctrl.GO = 1; + asm("sync"); + + /* wait for processing */ + while (hashs->ctrl.BSY) { + /* this will not take long */ + } + + in += 16; + + return 0; + } + +#if 1 + /* wait for digest ready */ + while (! hashs->ctrl.DGRY) { + /* this will not take long */ + } +#endif + + *((u32 *) out + 0) = hashs->D1R; + *((u32 *) out + 1) = hashs->D2R; + *((u32 *) out + 2) = hashs->D3R; + *((u32 *) out + 3) = hashs->D4R; + *((u32 *) out + 4) = hashs->D5R; + + CRTCL_SECT_END; +} + +/* + * \brief SHA1-HMAC function mappings +*/ +static struct shash_alg sha1_hmac_alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = sha1_hmac_init, + .update = sha1_hmac_update, + .final = sha1_hmac_final, + .export = sha1_hmac_export, + .import = sha1_hmac_import, + .setkey = sha1_hmac_setkey, + .descsize = sizeof(struct sha1_hmac_ctx), + .statesize = sizeof(struct sha1_hmac_ctx), + .base = { + .cra_name = "hmac(sha1)", + .cra_driver_name = "lq_deu-sha1_hmac", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +/** \fn int lq_deu_init_sha1_hmac(void) + * \ingroup LQ_SHA1_HMAC_FUNCTIONS + * \brief initialize sha1 hmac driver +*/ +int lq_deu_init_sha1_hmac(void) +{ + int ret; + + if ((ret = crypto_register_shash(&sha1_hmac_alg))) + goto sha1_err; + + CRTCL_SECT_INIT; + + printk(KERN_NOTICE "Lantiq DEU SHA1_HMAC initialized%s.\n", + disable_deudma ? "" : " (DMA)"); + return ret; + +sha1_err: + printk(KERN_ERR "Lantiq DEU SHA1_HMAC initialization failed!\n"); + return ret; +} + +/** \fn void lq_deu_fini_sha1_hmac(void) + * \ingroup LQ_SHA1_HMAC_FUNCTIONS + * \brief unregister sha1 hmac driver +*/ +void lq_deu_fini_sha1_hmac(void) +{ + crypto_unregister_shash(&sha1_hmac_alg); +} + +#endif --- /dev/null +++ b/drivers/crypto/lantiq/deu_falcon.c @@ -0,0 +1,163 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus + */ + +#include +#include +#include +#include +#include /* dma_cache_inv */ +#include + +#ifdef CONFIG_SOC_LANTIQ_FALCON + +#include "deu.h" + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief Lantiq DEU driver module +*/ + +/** + \file deu_falcon.c + \brief Lantiq DEU board specific driver file for ar9 +*/ + +/** + \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS + \ingroup LQ_DEU + \brief board specific functions +*/ + +#include +#include +#include +#include + +#define reg_r32(reg) __raw_readl(reg) +#define reg_w32(val, reg) __raw_writel(val, reg) +#define reg_w32_mask(clear, set, reg) reg_w32((reg_r32(reg) & ~(clear)) | (set), reg) + +static gpon_sys1_t * const sys1 = (gpon_sys1_t *)GPON_SYS1_BASE; +static gpon_status_t * const status = (gpon_status_t *)GPON_STATUS_BASE; + +/** \fn u32 endian_swap(u32 input) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Swap data given to the function + * \param input Data input to be swapped + * \return either the swapped data or the input data depending on whether it is in DMA mode or FPI mode +*/ +static u32 endian_swap(u32 input) +{ + return input; +} + +/** \fn u32 input_swap(u32 input) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief Not used + * \return input +*/ +static u32 input_swap(u32 input) +{ + return input; +} + +/** \fn void aes_chip_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief initialize AES hardware +*/ +static void aes_chip_init(void) +{ + volatile struct deu_aes *aes = (struct deu_aes *) AES_START; + + aes->ctrl.SM = 1; + aes->ctrl.ARS = 1; +} + +/** \fn void des_chip_init(void) + * \ingroup BOARD_SPECIFIC_FUNCTIONS + * \brief initialize DES hardware +*/ +static void des_chip_init(void) +{ +} + +static u32 chip_init(void) +{ + sys1_hw_clk_enable(CLKEN_SHA1_SET | CLKEN_AES_SET); + sys1_hw_activate(ACT_SHA1_SET | ACT_AES_SET); + + return LQ_DEU_ID_AES | LQ_DEU_ID_HASH; +} + +static int lq_crypto_probe(struct platform_device *pdev) +{ +#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA + lq_crypto_ops.dma_init = NULL; + lq_crypto_ops.dma_exit = NULL; + lq_crypto_ops.aes_dma_memcpy = NULL; + lq_crypto_ops.des_dma_memcpy = NULL; + lq_crypto_ops.aes_dma_malloc = NULL; + lq_crypto_ops.des_dma_malloc = NULL; + lq_crypto_ops.dma_align = NULL; + lq_crypto_ops.dma_free = NULL; +#endif + + lq_crypto_ops.endian_swap = endian_swap; + lq_crypto_ops.input_swap = input_swap; + lq_crypto_ops.aes_chip_init = aes_chip_init; + lq_crypto_ops.des_chip_init = des_chip_init; + lq_crypto_ops.chip_init = chip_init; + + printk("lq_falcon_deu: driver loaded!\n"); + + lq_deu_init(); + + return 0; +} + +static int lq_crypto_remove(struct platform_device *pdev) +{ + lq_deu_exit(); + + return 0; +} + +static struct platform_driver lq_crypto = { + .probe = lq_crypto_probe, + .remove = lq_crypto_remove, + .driver = { + .owner = THIS_MODULE, + .name = "lq_falcon_deu" + } +}; + +static int __init lq_crypto_init(void) +{ + return platform_driver_register(&lq_crypto); +} +module_init(lq_crypto_init); + +static void __exit lq_crypto_exit(void) +{ + platform_driver_unregister(&lq_crypto); +} +module_exit(lq_crypto_exit); + +#endif --- /dev/null +++ b/drivers/crypto/lantiq/deu_falcon.h @@ -0,0 +1,281 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2010 Ralph Hempel + * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies + */ + +/** + \defgroup LQ_DEU LQ_DEU_DRIVERS + \ingroup API + \brief DEU driver module +*/ + +/** + \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS + \ingroup LQ_DEU + \brief Lantiq DEU definitions +*/ + +/** + \file deu_falcon.h + \brief DEU driver header file +*/ + + +#ifndef DEU_FALCON_H +#define DEU_FALCON_H + +#define HASH_START 0xbd008100 +#define AES_START 0xbd008000 + +#ifdef CONFIG_CRYPTO_DEV_DMA +# include "deu_dma.h" +# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \ + deu_dma_align(ptr, buffer, in_out, bytes) +# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ + deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes) +# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ + deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes) +# define BUFFER_IN 1 +# define BUFFER_OUT 0 +# define AES_ALGO 1 +# define DES_ALGO 0 +# define ALLOCATE_MEMORY(val, type) 1 +# define FREE_MEMORY(buff) +extern struct lq_deu_device lq_deu[1]; +#endif /* CONFIG_CRYPTO_DEV_DMA */ + +/* SHA CONSTANTS */ +#define HASH_CON_VALUE 0x0700002C + +#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input) +#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input) +#define DELAY_PERIOD 10 +#define FIND_DEU_CHIP_VERSION chip_version() + +#define WAIT_AES_DMA_READY() \ + do { \ + int i; \ + volatile struct deu_dma *dma = \ + (struct deu_dma *) LQ_DEU_DMA_CON; \ + volatile struct deu_aes *aes = \ + (volatile struct deu_aes *) AES_START; \ + for (i = 0; i < 10; i++) \ + udelay(DELAY_PERIOD); \ + while (dma->ctrl.BSY) {}; \ + while (aes->ctrl.BUS) {}; \ + } while (0) + +#define WAIT_DES_DMA_READY() \ + do { \ + int i; \ + volatile struct deu_dma *dma = \ + (struct deu_dma *) LQ_DEU_DMA_CON; \ + volatile struct deu_des *des = \ + (struct deu_des *) DES_3DES_START; \ + for (i = 0; i < 10; i++) \ + udelay(DELAY_PERIOD); \ + while (dma->ctrl.BSY) {}; \ + while (des->ctrl.BUS) {}; \ + } while (0) + +#define AES_DMA_MISC_CONFIG() \ + do { \ + volatile struct deu_aes *aes = \ + (volatile struct deu_aes *) AES_START; \ + aes->ctrl.KRE = 1; \ + aes->ctrl.GO = 1; \ + } while(0) + +#define SHA_HASH_INIT \ + do { \ + volatile struct deu_hash *hash = \ + (struct deu_hash *) HASH_START; \ + hash->ctrl.SM = 1; \ + hash->ctrl.ALGO = 0; \ + hash->ctrl.INIT = 1; \ + } while(0) + +/* DEU Common Structures for Falcon*/ + +struct deu_clk_ctrl { + u32 Res:26; + u32 FSOE:1; + u32 SBWE:1; + u32 EDIS:1; + u32 SPEN:1; + u32 DISS:1; + u32 DISR:1; +}; + +struct deu_des { + struct deu_des_ctrl { /* 10h */ + u32 KRE:1; + u32 reserved1:5; + u32 GO:1; + u32 STP:1; + u32 Res2:6; + u32 NDC:1; + u32 ENDI:1; + u32 Res3:2; + u32 F:3; + u32 O:3; + u32 BUS:1; + u32 DAU:1; + u32 ARS:1; + u32 SM:1; + u32 E_D:1; + u32 M:3; + } ctrl; + + u32 IHR; /* 14h */ + u32 ILR; /* 18h */ + u32 K1HR; /* 1c */ + u32 K1LR; + u32 K2HR; + u32 K2LR; + u32 K3HR; + u32 K3LR; /* 30h */ + u32 IVHR; /* 34h */ + u32 IVLR; /* 38 */ + u32 OHR; /* 3c */ + u32 OLR; /* 40 */ +}; + +struct deu_aes { + struct deu_aes_ctrl { + u32 KRE:1; + u32 reserved1:4; + u32 PNK:1; + u32 GO:1; + u32 STP:1; + u32 reserved2:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved3:2; + u32 F:3; /* fbs */ + u32 O:3; /* om */ + u32 BUS:1; /* bsy */ + u32 DAU:1; + u32 ARS:1; + u32 SM:1; + u32 E_D:1; + u32 KV:1; + u32 K:2; /* KL */ + } ctrl; + + u32 ID3R; /* 80h */ + u32 ID2R; /* 84h */ + u32 ID1R; /* 88h */ + u32 ID0R; /* 8Ch */ + u32 K7R; /* 90h */ + u32 K6R; /* 94h */ + u32 K5R; /* 98h */ + u32 K4R; /* 9Ch */ + u32 K3R; /* A0h */ + u32 K2R; /* A4h */ + u32 K1R; /* A8h */ + u32 K0R; /* ACh */ + u32 IV3R; /* B0h */ + u32 IV2R; /* B4h */ + u32 IV1R; /* B8h */ + u32 IV0R; /* BCh */ + u32 OD3R; /* D4h */ + u32 OD2R; /* D8h */ + u32 OD1R; /* DCh */ + u32 OD0R; /* E0h */ +}; + +struct deu_arc4 { + struct arc4_controlr { + u32 KRE:1; + u32 KLEN:4; + u32 KSAE:1; + u32 GO:1; + u32 STP:1; + u32 reserved1:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved2:8; + u32 BUS:1; /* bsy */ + u32 reserved3:1; + u32 ARS:1; + u32 SM:1; + u32 reserved4:4; + } ctrl; + + u32 K3R; /* 104h */ + u32 K2R; /* 108h */ + u32 K1R; /* 10Ch */ + u32 K0R; /* 110h */ + u32 IDLEN; /* 114h */ + u32 ID3R; /* 118h */ + u32 ID2R; /* 11Ch */ + u32 ID1R; /* 120h */ + u32 ID0R; /* 124h */ + u32 OD3R; /* 128h */ + u32 OD2R; /* 12Ch */ + u32 OD1R; /* 130h */ + u32 OD0R; /* 134h */ +}; + +struct deu_hash { + struct deu_hash_ctrl { + u32 reserved1:5; + u32 KHS:1; + u32 GO:1; + u32 INIT:1; + u32 reserved2:6; + u32 NDC:1; + u32 ENDI:1; + u32 reserved3:7; + u32 DGRY:1; + u32 BSY:1; + u32 reserved4:1; + u32 IRCL:1; + u32 SM:1; + u32 KYUE:1; + u32 HMEN:1; + u32 SSEN:1; + u32 ALGO:1; + } ctrl; + + u32 MR; /* B4h */ + u32 D1R; /* B8h */ + u32 D2R; /* BCh */ + u32 D3R; /* C0h */ + u32 D4R; /* C4h */ + u32 D5R; /* C8h */ + u32 dummy; /* CCh */ + u32 KIDX; /* D0h */ + u32 KEY; /* D4h */ + u32 DBN; /* D8h */ +}; + +struct deu_dma { + struct deu_dma_ctrl { + u32 reserved1:22; + u32 BS:2; + u32 BSY:1; + u32 reserved2:1; + u32 ALGO:2; + u32 RXCLS:2; + u32 reserved3:1; + u32 EN:1; + } ctrl; +}; + +#endif /* DEU_FALCON_H */ --- a/arch/mips/lantiq/xway/devices.h +++ b/arch/mips/lantiq/xway/devices.h @@ -22,5 +22,6 @@ extern void __init lq_register_ethernet(struct lq_eth_data *eth); extern void __init lq_register_asc(int port); extern void __init lq_register_gpio_buttons(struct gpio_button *buttons, int cnt); +extern void __init lq_register_crypto(const char *name); #endif --- a/arch/mips/lantiq/xway/mach-easy50712.c +++ b/arch/mips/lantiq/xway/mach-easy50712.c @@ -74,6 +74,7 @@ lq_register_wdt(); lq_register_pci(&lq_pci_data); lq_register_ethernet(&lq_eth_data); + lq_register_crypto("lq_danube_deu"); } MIPS_MACHINE(LANTIQ_MACH_EASY50712, --- a/arch/mips/lantiq/xway/mach-easy50812.c +++ b/arch/mips/lantiq/xway/mach-easy50812.c @@ -73,6 +73,7 @@ lq_register_wdt(); lq_register_pci(&lq_pci_data); lq_register_ethernet(&lq_eth_data); + lq_register_crypto("lq_ar9_deu"); } MIPS_MACHINE(LANTIQ_MACH_EASY50812,