6198 lines
162 KiB
Diff
6198 lines
162 KiB
Diff
--- a/drivers/crypto/Kconfig
|
|
+++ b/drivers/crypto/Kconfig
|
|
@@ -252,4 +252,75 @@
|
|
OMAP processors have AES module accelerator. Select this if you
|
|
want to use the OMAP module for AES algorithms.
|
|
|
|
+config CRYPTO_DEV_LANTIQ
|
|
+ tristate "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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <linux/version.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/delay.h>
|
|
+#include <asm/byteorder.h>
|
|
+#include <crypto/algapi.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <linux/version.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <crypto/algapi.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <asm/byteorder.h>
|
|
+#include <linux/delay.h>
|
|
+
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <linux/version.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/delay.h>
|
|
+#include <asm/byteorder.h>
|
|
+#include <crypto/algapi.h>
|
|
+
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <linux/version.h>
|
|
+#if defined(CONFIG_MODVERSIONS)
|
|
+#define MODVERSIONS
|
|
+#include <linux/modversions.h>
|
|
+#endif
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/proc_fs.h>
|
|
+#include <linux/fs.h> /* Stuff about file systems that we need */
|
|
+#include <asm/byteorder.h>
|
|
+
|
|
+#if 0
|
|
+#ifdef CONFIG_SOC_LANTIQ_XWAY
|
|
+# include <lq_pmu.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <ralph.hempel@lantiq.com>
|
|
+ * Copyright (C) 2009 Mohammad Firdaus
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <asm/io.h> /* dma_cache_inv */
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <ralph.hempel@lantiq.com>
|
|
+ * Copyright (C) 2009 Mohammad Firdaus
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <asm/io.h> /* dma_cache_inv */
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/delay.h>
|
|
+#include <asm/io.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mm.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <asm/scatterlist.h>
|
|
+#include <asm/byteorder.h>
|
|
+#include <linux/skbuff.h>
|
|
+#include <linux/netdevice.h>
|
|
+
|
|
+#include <asm/ifx/irq.h>
|
|
+#include <asm/ifx/ifx_dma_core.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <crypto/internal/hash.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/types.h>
|
|
+#include <asm/byteorder.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <crypto/internal/hash.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/types.h>
|
|
+#include <asm/byteorder.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <crypto/internal/hash.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mm.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/cryptohash.h>
|
|
+#include <crypto/sha.h>
|
|
+#include <linux/types.h>
|
|
+#include <asm/scatterlist.h>
|
|
+#include <asm/byteorder.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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 <crypto/internal/hash.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mm.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/cryptohash.h>
|
|
+#include <linux/types.h>
|
|
+#include <asm/scatterlist.h>
|
|
+#include <asm/byteorder.h>
|
|
+#include <linux/delay.h>
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * Copyright (C) 2009 Mohammad Firdaus
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/errno.h>
|
|
+#include <asm/io.h> /* dma_cache_inv */
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+#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 <falcon/gpon_reg_base.h>
|
|
+#include <falcon/sys1_reg.h>
|
|
+#include <falcon/status_reg.h>
|
|
+#include <falcon/sysctrl.h>
|
|
+
|
|
+#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 <ralph.hempel@lantiq.com>
|
|
+ * 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
|
|
@@ -24,5 +24,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,
|