add ltq-deu

SVN-Revision: 34689
This commit is contained in:
John Crispin 2012-12-15 02:00:05 +00:00
parent 65d9ff5054
commit c2e2323e1d
25 changed files with 21263 additions and 0 deletions

View file

@ -0,0 +1,49 @@
# Copyright (C) 2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=ltq-deu
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/ltq-deu-$(BUILD_VARIANT)
PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
include $(INCLUDE_DIR)/package.mk
define KernelPackage/ltq-deu-template
SECTION:=sys
CATEGORY:=Kernel modules
SUBMENU:=Cryptographic API modules
TITLE:=deu driver for $(1)
URL:=http://www.lantiq.com/
VARIANT:=$(1)
DEPENDS:=@TARGET_lantiq_xway
FILES:=$(PKG_BUILD_DIR)/ltq_deu_$(1).ko $(PKG_BUILD_DIR)/ltq_deu_testmgr.ko
AUTOLOAD:=$(call AutoLoad,52,ltq_deu_$(1))
endef
KernelPackage/ltq-deu-danube=$(call KernelPackage/ltq-deu-template,danube)
KernelPackage/ltq-deu-ar9=$(call KernelPackage/ltq-deu-template,ar9)
KernelPackage/ltq-deu-vr9=$(call KernelPackage/ltq-deu-template,vr9)
define Build/Prepare
$(INSTALL_DIR) $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)
endef
define Build/Configure
endef
define Build/Compile
cd $(LINUX_DIR); \
ARCH=mips CROSS_COMPILE="$(KERNEL_CROSS)" \
$(MAKE) BUILD_VARIANT=$(BUILD_VARIANT) M=$(PKG_BUILD_DIR) V=1 modules
endef
$(eval $(call KernelPackage,ltq-deu-danube))
$(eval $(call KernelPackage,ltq-deu-ar9))
$(eval $(call KernelPackage,ltq-deu-vr9))

View file

@ -0,0 +1,26 @@
ifeq ($(BUILD_VARIANT),danube)
CFLAGS_MODULE =-DCONFIG_DANUBE -DCONFIG_CRYPTO_DEV_DEU -DCONFIG_CRYPTO_DEV_SPEED_TEST -DCONFIG_CRYPTO_DEV_DES \
-DCONFIG_CRYPTO_DEV_AES -DCONFIG_CRYPTO_DEV_SHA1 -DCONFIG_CRYPTO_DEV_MD5
obj-m = ltq_deu_danube.o
ltq_deu_danube-objs = ifxmips_deu.o ifxmips_deu_danube.o ifxmips_des.o ifxmips_aes.o ifxmips_sha1.o ifxmips_md5.o
endif
ifeq ($(BUILD_VARIANT),ar9)
CFLAGS_MODULE = -DCONFIG_AR9 -DCONFIG_CRYPTO_DEV_DEU -DCONFIG_CRYPTO_DEV_SPEED_TEST -DCONFIG_CRYPTO_DEV_DES \
-DCONFIG_CRYPTO_DEV_AES -DCONFIG_CRYPTO_DEV_SHA1 -DCONFIG_CRYPTO_DEV_MD5 -DCONFIG_CRYPTO_DEV_ARC4 \
-DCONFIG_CRYPTO_DEV_SHA1_HMAC -DCONFIG_CRYPTO_DEV_MD5_HMAC
obj-m = ltq_deu_ar9.o
ltq_deu_ar9-objs = ifxmips_deu.o ifxmips_deu_ar9.o ifxmips_des.o ifxmips_aes.o ifxmips_arc4.o \
ifxmips_sha1.o ifxmips_md5.o ifxmips_sha1_hmac.o ifxmips_md5_hmac.o
endif
ifeq ($(BUILD_VARIANT),vr9)
CFLAGS_MODULE = -DCONFIG_VR9 -DCONFIG_CRYPTO_DEV_DEU -DCONFIG_CRYPTO_DEV_SPEED_TEST -DCONFIG_CRYPTO_DEV_DES \
-DCONFIG_CRYPTO_DEV_AES -DCONFIG_CRYPTO_DEV_SHA1 -DCONFIG_CRYPTO_DEV_MD5 -DCONFIG_CRYPTO_DEV_ARC4 \
-DCONFIG_CRYPTO_DEV_SHA1_HMAC -DCONFIG_CRYPTO_DEV_MD5_HMAC
obj-m = ltq_deu_vr9.o
ltq_deu_vr9-objs = ifxmips_deu.o ifxmips_deu_vr9.o ifxmips_des.o ifxmips_aes.o ifxmips_arc4.o \
ifxmips_sha1.o ifxmips_md5.o ifxmips_sha1_hmac.o ifxmips_md5_hmac.o
endif
obj-m += ltq_deu_testmgr.o

View file

@ -0,0 +1,904 @@
/******************************************************************************
**
** FILE NAME : ifxmips_aes.c
** PROJECT : IFX UEIP
** MODULES : DEU Module
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver for AES Algorithm
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx DEU driver module
*/
/*!
\file ifxmips_aes.c
\ingroup IFX_DEU
\brief AES Encryption Driver main file
*/
/*!
\defgroup IFX_AES_FUNCTIONS IFX_AES_FUNCTIONS
\ingroup IFX_DEU
\brief IFX AES driver Functions
*/
/* Project Header Files */
#if defined(CONFIG_MODVERSIONS)
#define MODVERSIONS
#include <linux/modeversions>
#endif
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/fs.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 "ifxmips_deu.h"
#if defined(CONFIG_DANUBE)
#include "ifxmips_deu_danube.h"
extern int ifx_danube_pre_1_4;
#elif defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Unkown platform"
#endif
/* DMA related header and variables */
spinlock_t aes_lock;
#define CRTCL_SECT_INIT spin_lock_init(&aes_lock)
#define CRTCL_SECT_START spin_lock_irqsave(&aes_lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&aes_lock, flag)
/* Definition of constants */
#define AES_START IFX_AES_CON
#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)
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif /* CRYPTO_DEBUG */
/* Function decleration */
int aes_chip_init(void);
u32 endian_swap(u32 input);
u32 input_swap(u32 input);
u32* memory_alignment(const u8 *arg, u32 *buff_alloc, int in_out, int nbytes);
void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
int aes_memory_allocate(int value);
int des_memory_allocate(int value);
void memory_release(u32 *addr);
extern void ifx_deu_aes (void *ctx_arg, uint8_t *out_arg, const uint8_t *in_arg,
uint8_t *iv_arg, size_t nbytes, int encdec, int mode);
/* End of function decleration */
struct aes_ctx {
int key_length;
u32 buf[AES_MAX_KEY_SIZE];
u8 nonce[CTR_RFC3686_NONCE_SIZE];
};
extern int disable_deudma;
extern int disable_multiblock;
/*! \fn int aes_set_key (struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len)
* \ingroup IFX_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
*/
int aes_set_key (struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
unsigned long *flags = (unsigned long *) &tfm->crt_flags;
//printk("set_key in %s\n", __FILE__);
//aes_chip_init();
if (key_len != 16 && key_len != 24 && key_len != 32) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
ctx->key_length = key_len;
DPRINTF(0, "ctx @%p, key_len %d, ctx->key_length %d\n", ctx, key_len, ctx->key_length);
memcpy ((u8 *) (ctx->buf), in_key, key_len);
return 0;
}
/*! \fn void ifx_deu_aes (void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode)
* \ingroup IFX_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
*
*/
void ifx_deu_aes (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, size_t nbytes, int encdec, int mode)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
volatile struct aes_t *aes = (volatile struct aes_t *) AES_START;
struct aes_ctx *ctx = (struct aes_ctx *)ctx_arg;
u32 *in_key = ctx->buf;
unsigned long flag;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
int key_len = ctx->key_length;
int i = 0;
int byte_cnt = nbytes;
CRTCL_SECT_START;
/* 128, 192 or 256 bit key length */
aes->controlr.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 {
printk (KERN_ERR "[%s %s %d]: Invalid key_len : %d\n", __FILE__, __func__, __LINE__, key_len);
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->controlr.PNK = 1;
aes->controlr.E_D = !encdec; //encryption
aes->controlr.O = mode; //0 ECB 1 CBC 2 OFB 3 CFB 4 CTR
//aes->controlr.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));
};
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));
aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 3)); /* start crypto */
while (aes->controlr.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;
}
//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 IFX_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
*/
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);
unsigned long *flags = (unsigned long *)&tfm->crt_flags;
//printk("ctr_rfc3686_aes_set_key in %s\n", __FILE__);
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 ifx_deu_aes (void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
* \ingroup IFX_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
*/
//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 // not even defined
//but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR
/*! \fn void ifx_deu_aes_ecb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_aes_ecb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, NULL, nbytes, encdec, 0);
}
/*! \fn void ifx_deu_aes_cbc (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_aes_cbc (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, iv, nbytes, encdec, 1);
}
/*! \fn void ifx_deu_aes_ofb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_aes_ofb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, iv, nbytes, encdec, 2);
}
/*! \fn void ifx_deu_aes_cfb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_aes_cfb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, iv, nbytes, encdec, 3);
}
/*! \fn void ifx_deu_aes_ctr (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_aes_ctr (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_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 IFX_AES_FUNCTIONS
* \brief encrypt AES_BLOCK_SIZE of data
* \param tfm linux crypto algo transform
* \param out output bytestream
* \param in input bytestream
*/
void aes_encrypt (struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
ifx_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 IFX_AES_FUNCTIONS
* \brief decrypt AES_BLOCK_SIZE of data
* \param tfm linux crypto algo transform
* \param out output bytestream
* \param in input bytestream
*/
void aes_decrypt (struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
ifx_deu_aes (ctx, out, in, NULL, AES_BLOCK_SIZE,
CRYPTO_DIR_DECRYPT, 0);
}
/*
* \brief AES function mappings
*/
struct crypto_alg ifxdeu_aes_alg = {
.cra_name = "aes",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 IFX_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
*/
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);
ifx_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 IFX_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
*/
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);
ifx_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
*/
struct crypto_alg ifxdeu_ecb_aes_alg = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 IFX_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
*/
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);
ifx_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 IFX_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
*/
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);
ifx_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
*/
struct crypto_alg ifxdeu_cbc_aes_alg = {
.cra_name = "cbc(aes)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 IFX_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
*/
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);
ifx_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 IFX_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
*/
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);
ifx_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
*/
struct crypto_alg ifxdeu_ctr_basic_aes_alg = {
.cra_name = "ctr(aes)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 IFX_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
*/
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);
ifx_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 IFX_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
*/
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);
ifx_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
*/
struct crypto_alg ifxdeu_ctr_rfc3686_aes_alg = {
.cra_name = "rfc3686(ctr(aes))",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 __init ifxdeu_init_aes (void)
* \ingroup IFX_AES_FUNCTIONS
* \brief function to initialize AES driver
* \return ret
*/
int __init ifxdeu_init_aes (void)
{
int ret = -ENOSYS;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
if (!disable_multiblock) {
ifxdeu_aes_alg.cra_u.cipher.cia_max_nbytes = AES_BLOCK_SIZE; //(size_t)-1;
ifxdeu_aes_alg.cra_u.cipher.cia_req_align = 16;
ifxdeu_aes_alg.cra_u.cipher.cia_ecb = ifx_deu_aes_ecb;
ifxdeu_aes_alg.cra_u.cipher.cia_cbc = ifx_deu_aes_cbc;
ifxdeu_aes_alg.cra_u.cipher.cia_cfb = ifx_deu_aes_cfb;
ifxdeu_aes_alg.cra_u.cipher.cia_ofb = ifx_deu_aes_ofb;
}
#endif
if ((ret = crypto_register_alg(&ifxdeu_aes_alg)))
goto aes_err;
if ((ret = crypto_register_alg(&ifxdeu_ecb_aes_alg)))
goto ecb_aes_err;
if ((ret = crypto_register_alg(&ifxdeu_cbc_aes_alg)))
goto cbc_aes_err;
if ((ret = crypto_register_alg(&ifxdeu_ctr_basic_aes_alg)))
goto ctr_basic_aes_err;
if ((ret = crypto_register_alg(&ifxdeu_ctr_rfc3686_aes_alg)))
goto ctr_rfc3686_aes_err;
aes_chip_init ();
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU AES initialized%s%s.\n", disable_multiblock ? "" : " (multiblock)", disable_deudma ? "" : " (DMA)");
return ret;
ctr_rfc3686_aes_err:
crypto_unregister_alg(&ifxdeu_ctr_rfc3686_aes_alg);
printk (KERN_ERR "IFX ctr_rfc3686_aes initialization failed!\n");
return ret;
ctr_basic_aes_err:
crypto_unregister_alg(&ifxdeu_ctr_basic_aes_alg);
printk (KERN_ERR "IFX ctr_basic_aes initialization failed!\n");
return ret;
cbc_aes_err:
crypto_unregister_alg(&ifxdeu_cbc_aes_alg);
printk (KERN_ERR "IFX cbc_aes initialization failed!\n");
return ret;
ecb_aes_err:
crypto_unregister_alg(&ifxdeu_ecb_aes_alg);
printk (KERN_ERR "IFX aes initialization failed!\n");
return ret;
aes_err:
printk(KERN_ERR "IFX DEU AES initialization failed!\n");
return ret;
}
/*! \fn void __exit ifxdeu_fini_aes (void)
* \ingroup IFX_AES_FUNCTIONS
* \brief unregister aes driver
*/
void __exit ifxdeu_fini_aes (void)
{
crypto_unregister_alg (&ifxdeu_aes_alg);
crypto_unregister_alg (&ifxdeu_ecb_aes_alg);
crypto_unregister_alg (&ifxdeu_cbc_aes_alg);
crypto_unregister_alg (&ifxdeu_ctr_basic_aes_alg);
crypto_unregister_alg (&ifxdeu_ctr_rfc3686_aes_alg);
}

View file

@ -0,0 +1,389 @@
/******************************************************************************
**
** FILE NAME : ifxmips_arc4.c
** PROJECT : IFX UEIP
** MODULES : DEU Module
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver for ARC4 Algorithm
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08 Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_arc4.c
\ingroup IFX_DEU
\brief ARC4 encryption DEU driver file
*/
/*!
\defgroup IFX_ARC4_FUNCTIONS IFX_ARC4_FUNCTIONS
\ingroup IFX_DEU
\brief IFX deu driver functions
*/
/* Project header */
#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>
/* Board specific header files */
#ifdef CONFIG_AR9
#include "ifxmips_deu_ar9.h"
#endif
#ifdef CONFIG_VR9
#include "ifxmips_deu_vr9.h"
#endif
static spinlock_t lock;
#define CRTCL_SECT_INIT spin_lock_init(&lock)
#define CRTCL_SECT_START spin_lock_irqsave(&lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag)
/* 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
#define ARC4_START IFX_ARC4_CON
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
/*
* \brief arc4 private structure
*/
struct arc4_ctx {
int key_length;
u8 buf[120];
};
extern int disable_deudma;
extern int disable_multiblock;
/*! \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 IFX_ARC4_FUNCTIONS
\brief main interface to ARC4 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 arc4_t *arc4 = (struct arc4_t *) ARC4_START;
int i = 0;
unsigned long 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->controlr.GO = 1;
while (arc4->controlr.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 IFX_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 IFX_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 arc4_t *arc4 = (struct arc4_t *) ARC4_START;
u32 *in_key = (u32 *)inkey;
// must program all bits at one go?!!!
//#if 1
*IFX_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);
#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 IFX_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 IFX_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, 0);
}
/*
* \brief ARC4 function mappings
*/
static struct crypto_alg ifxdeu_arc4_alg = {
.cra_name = "arc4",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 IFX_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 IFX_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 ifxdeu_ecb_arc4_alg = {
.cra_name = "ecb(arc4)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 __init ifxdeu_init_arc4(void)
\ingroup IFX_ARC4_FUNCTIONS
\brief initialize arc4 driver
*/
int __init ifxdeu_init_arc4(void)
{
int ret = -ENOSYS;
if ((ret = crypto_register_alg(&ifxdeu_arc4_alg)))
goto arc4_err;
if ((ret = crypto_register_alg(&ifxdeu_ecb_arc4_alg)))
goto ecb_arc4_err;
arc4_chip_init ();
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU ARC4 initialized%s%s.\n", disable_multiblock ? "" : " (multiblock)", disable_deudma ? "" : " (DMA)");
return ret;
arc4_err:
crypto_unregister_alg(&ifxdeu_arc4_alg);
printk(KERN_ERR "IFX arc4 initialization failed!\n");
return ret;
ecb_arc4_err:
crypto_unregister_alg(&ifxdeu_ecb_arc4_alg);
printk (KERN_ERR "IFX ecb_arc4 initialization failed!\n");
return ret;
}
/*! \fn void __exit ifxdeu_fini_arc4(void)
\ingroup IFX_ARC4_FUNCTIONS
\brief unregister arc4 driver
*/
void __exit ifxdeu_fini_arc4(void)
{
crypto_unregister_alg (&ifxdeu_arc4_alg);
crypto_unregister_alg (&ifxdeu_ecb_arc4_alg);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,954 @@
/******************************************************************************
**
** FILE NAME : ifxmips_async_des.c
** PROJECT : IFX UEIP
** MODULES : DEU Module
**
** DATE : October 11, 2010
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver for DES Algorithm
** COPYRIGHT : Copyright (c) 2010
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
** 11, Oct 2010 Mohammad Firdaus Kernel Port incl. Async. Ablkcipher mode
** 21,March 2011 Mohammad Firdaus Changes for Kernel 2.6.32 and IPSec integration
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx DEU driver module
*/
/*!
\file ifxmips_async_des.c
\ingroup IFX_DEU
\brief DES Encryption Driver main file
*/
/*!
\defgroup IFX_DES_FUNCTIONS IFX_DES_FUNCTIONS
\ingroup IFX_DEU
\brief IFX DES driver Functions
*/
#include <linux/wait.h>
#include <linux/crypto.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <crypto/ctr.h>
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/scatterwalk.h>
#include <asm/ifx/ifx_regs.h>
#include <asm/ifx/ifx_types.h>
#include <asm/ifx/common_routines.h>
#include <asm/ifx/irq.h>
#include <asm/ifx/ifx_pmu.h>
#include <asm/ifx/ifx_gpio.h>
#include <asm/kmap_types.h>
#include "ifxmips_deu.h"
#if defined(CONFIG_DANUBE)
#include "ifxmips_deu_danube.h"
extern int ifx_danube_pre_1_4;
#elif defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Unkown platform"
#endif
/* DMA specific header and variables */
spinlock_t des_lock;
#define CRTCL_SECT_INIT spin_lock_init(&des_lock)
#define CRTCL_SECT_START spin_lock_irqsave(&des_lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&des_lock, flag)
/* Preprocessor declerations */
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
//#define DES_3DES_START IFX_DES_CON
#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
/* Function Declaration to prevent warning messages */
void des_chip_init (void);
u32 endian_swap(u32 input);
u32 input_swap(u32 input);
int aes_memory_allocate(int value);
int des_memory_allocate(int value);
void memory_release(u32 *buffer);
u32* memory_alignment(const u8 *arg, u32 *buff_alloc, int in_out, int nbytes);
void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
static int lq_deu_des_core (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode);
struct des_ctx {
int controlr_M;
int key_length;
u8 iv[DES_BLOCK_SIZE];
u32 expkey[DES3_EDE_EXPKEY_WORDS];
};
static int disable_multiblock = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
module_param(disable_multiblock, int, 0);
#else
MODULE_PARM_DESC(disable_multiblock, "Disable encryption of whole multiblock buffers");
#endif
static int disable_deudma = 1;
struct des_container {
u8 *iv;
u8 *dst_buf;
u8 *src_buf;
int mode;
int encdec;
int complete;
int flag;
u32 bytes_processed;
u32 nbytes;
struct ablkcipher_request arequest;
};
des_priv_t *des_queue;
extern deu_drv_priv_t deu_dma_priv;
void hexdump1(unsigned char *buf, unsigned int len)
{
print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
16, 1,
buf, len, false);
}
/*! \fn int lq_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen)
* \ingroup IFX_DES_FUNCTIONS
* \brief sets DES key
* \param tfm linux crypto algo transform
* \param key input key
* \param keylen key length
*/
static int lq_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
unsigned int keylen)
{
struct des_ctx *dctx = crypto_ablkcipher_ctx(tfm);
//printk("setkey in %s\n", __FILE__);
dctx->controlr_M = 0; // des
dctx->key_length = keylen;
memcpy ((u8 *) (dctx->expkey), key, keylen);
return 0;
}
/*! \fn int lq_des3_ede_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen)
* \ingroup IFX_DES_FUNCTIONS
* \brief sets DES key
* \param tfm linux crypto algo transform
* \param key input key
* \param keylen key length
*/
static int lq_des3_ede_setkey(struct crypto_ablkcipher *tfm, const u8 *in_key,
unsigned int keylen)
{
struct des_ctx *dctx = crypto_ablkcipher_ctx(tfm);
//printk("setkey in %s\n", __FILE__);
dctx->controlr_M = keylen/8 + 1; // des
dctx->key_length = keylen;
memcpy ((u8 *) (dctx->expkey), in_key, keylen);
return 0;
}
/*! \fn void ifx_deu_des_core(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
* \ingroup IFX_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 int lq_deu_des_core (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode)
{
volatile struct des_t *des = (struct des_t *) DES_3DES_START;
struct des_ctx *dctx = ctx_arg;
u32 *key = dctx->expkey;
unsigned long flag;
int i = 0;
int nblocks = 0;
CRTCL_SECT_START;
des->controlr.M = dctx->controlr_M;
if (dctx->controlr_M == 0) // des
{
des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0));
des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1));
}
else {
/* Hardware Section */
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 -EINVAL;
}
}
des->controlr.E_D = !encdec; //encryption
des->controlr.O = mode; //0 ECB 1 CBC 2 OFB 3 CFB 4 CTR hexdump(prin,sizeof(*des));
if (mode > 0) {
des->IVHR = DEU_ENDIAN_SWAP(*(u32 *) iv_arg);
des->IVLR = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 1));
};
/* memory alignment issue */
dword_mem_aligned_in = (u32 *) DEU_DWORD_REORDERING(in_arg, des_buff_in, BUFFER_IN, nbytes);
deu_priv->deu_rx_buf = (u32 *) out_arg;
deu_priv->deu_rx_len = nbytes;
dma->controlr.ALGO = 0; //DES
des->controlr.DAU = 0;
dma->controlr.BS = 0;
dma->controlr.EN = 1;
while (des->controlr.BUS) {
};
wlen = dma_device_write (dma_device, (u8 *) dword_mem_aligned_in, nbytes, NULL);
if (wlen != nbytes) {
dma->controlr.EN = 0;
CRTCL_SECT_END;
printk (KERN_ERR "[%s %s %d]: dma_device_write fail!\n", __FILE__, __func__, __LINE__);
return -EINVAL;
}
/* Prepare Rx buf length used in dma psuedo interrupt */
outcopy = (u32 *) DEU_DWORD_REORDERING(out_arg, des_buff_out, BUFFER_OUT, nbytes);
deu_priv->outcopy = outcopy;
deu_priv->event_src = DES_ASYNC_EVENT;
if (mode > 0) {
*(u32 *) iv_arg = DEU_ENDIAN_SWAP(des->IVHR);
*((u32 *) iv_arg + 1) = DEU_ENDIAN_SWAP(des->IVLR);
};
CRTCL_SECT_END;
return -EINPROGRESS;
}
static int count_sgs(struct scatterlist *sl, unsigned int total_bytes)
{
int i = 0;
do {
total_bytes -= sl[i].length;
i++;
} while (total_bytes > 0);
return i;
}
/* \fn static inline struct des_container *des_container_cast (
* struct scatterlist *dst)
* \ingroup IFX_DES_FUNCTIONS
* \brief Locate the structure des_container in memory.
* \param *areq Pointer to memory location where ablkcipher_request is located
* \return *des_cointainer The function pointer to des_container
*/
static inline struct des_container *des_container_cast(
struct ablkcipher_request *areq)
{
return container_of(areq, struct des_container, arequest);
}
/* \fn static void lq_sg_complete(struct des_container *des_con)
* \ingroup IFX_DES_FUNCTIONS
* \brief Free the used up memory after encryt/decrypt.
*/
static void lq_sg_complete(struct des_container *des_con)
{
unsigned long queue_flag;
spin_lock_irqsave(&des_queue->lock, queue_flag);
kfree(des_con);
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
}
/* \fn void lq_sg_init(struct scatterlist *src,
* struct scatterlist *dst)
* \ingroup IFX_DES_FUNCTIONS
* \brief Maps the scatterlists into a source/destination page.
* \param *src Pointer to the source scatterlist
* \param *dst Pointer to the destination scatterlist
*/
static void lq_sg_init(struct des_container *des_con, struct scatterlist *src,
struct scatterlist *dst)
{
struct page *dst_page, *src_page;
src_page = sg_virt(src);
des_con->src_buf = (char *) src_page;
dst_page = sg_virt(dst);
des_con->dst_buf = (char *) dst_page;
}
/* \fn static int process_next_packet(struct des_container *des_con, struct ablkcipher_request *areq,
* int state)
* \ingroup IFX_DES_FUNCTIONS
* \brief Process the next packet after dequeuing the packet from crypto queue
* \param *des_con Pointer to DES container structure
* \param *areq Pointer to ablkcipher_request container
* \param state State of the packet (scattered packet or new packet to be processed)
* \return -EINVAL: DEU failure, -EINPROGRESS: DEU encrypt/decrypt in progress, 1: no scatterlist left
*/
static int process_next_packet(struct des_container *des_con, struct ablkcipher_request *areq,
int state)
{
u8 *iv;
int mode, encdec, err = -EINVAL;
u32 remain, inc, chunk_size, nbytes;
struct scatterlist *src = NULL;
struct scatterlist *dst = NULL;
struct crypto_ablkcipher *cipher;
struct des_ctx *ctx;
unsigned long queue_flag;
spin_lock_irqsave(&des_queue->lock, queue_flag);
mode = des_con->mode;
encdec = des_con->encdec;
iv = des_con->iv;
if (state & PROCESS_SCATTER) {
src = scatterwalk_sg_next(areq->src);
dst = scatterwalk_sg_next(areq->dst);
if (!src || !dst) {
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
return 1;
}
}
else if (state & PROCESS_NEW_PACKET) {
src = areq->src;
dst = areq->dst;
}
remain = des_con->bytes_processed;
chunk_size = src->length;
//printk("debug ln: %d, func: %s, reqsize: %d, scattersize: %d\n",
// __LINE__, __func__, areq->nbytes, chunk_size);
if (remain > DEU_MAX_PACKET_SIZE)
inc = DEU_MAX_PACKET_SIZE;
else if(remain > chunk_size)
inc = chunk_size;
else
inc = remain;
remain -= inc;
des_con->nbytes = inc;
if (state & PROCESS_SCATTER) {
des_con->src_buf += des_con->nbytes;
des_con->dst_buf += des_con->nbytes;
}
lq_sg_init(des_con, src, dst);
nbytes = des_con->nbytes;
cipher = crypto_ablkcipher_reqtfm(areq);
ctx = crypto_ablkcipher_ctx(cipher);
if (des_queue->hw_status == DES_IDLE) {
des_queue->hw_status = DES_STARTED;
}
des_con->bytes_processed -= des_con->nbytes;
err = ablkcipher_enqueue_request(&des_queue->list, &des_con->arequest);
if (err == -EBUSY) {
printk("Failed to enqueue request, ln: %d, err: %d\n",
__LINE__, err);
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
return -EINVAL;
}
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
err = lq_deu_des_core(ctx, des_con->dst_buf, des_con->src_buf, iv, nbytes, encdec, mode);
return err;
}
/* \fn static void process_queue(unsigned long data)
* \ingroup IFX_DES_FUNCTIONS
* \brief Process next packet in queue
* \param data not used
* \return
*/
static void process_queue(unsigned long data)
{
DEU_WAKEUP_EVENT(deu_dma_priv.deu_thread_wait, DES_ASYNC_EVENT,
deu_dma_priv.des_event_flags);
}
/* \fn static int des_crypto_thread (void *data)
* \ingroup IFX_DES_FUNCTIONS
* \brief DES thread that handles crypto requests from upper layer & DMA
* \param *data Not used
* \return -EINVAL: DEU failure, -EBUSY: DEU HW busy, 0: exit thread
*/
static int des_crypto_thread(void *data)
{
struct des_container *des_con = NULL;
struct ablkcipher_request *areq = NULL;
int err;
unsigned long queue_flag;
daemonize("lq_des_thread");
while (1)
{
DEU_WAIT_EVENT(deu_dma_priv.deu_thread_wait, DES_ASYNC_EVENT,
deu_dma_priv.des_event_flags);
spin_lock_irqsave(&des_queue->lock, queue_flag);
/* wait to prevent starting a crypto session before
* exiting the dma interrupt thread.
*/
if (des_queue->hw_status == DES_STARTED) {
areq = ablkcipher_dequeue_request(&des_queue->list);
des_con = des_container_cast(areq);
des_queue->hw_status = DES_BUSY;
}
else if (des_queue->hw_status == DES_IDLE) {
areq = ablkcipher_dequeue_request(&des_queue->list);
des_con = des_container_cast(areq);
des_queue->hw_status = DES_STARTED;
}
else if (des_queue->hw_status == DES_BUSY) {
areq = ablkcipher_dequeue_request(&des_queue->list);
des_con = des_container_cast(areq);
}
else if (des_queue->hw_status == DES_COMPLETED) {
areq->base.complete(&areq->base, 0);
lq_sg_complete(des_con);
des_queue->hw_status = DES_IDLE;
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
return 0;
}
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
if ((des_con->bytes_processed == 0)) {
goto des_done;
}
if (!des_con) {
goto des_done;
}
if (des_con->flag & PROCESS_NEW_PACKET) {
des_con->flag = PROCESS_SCATTER;
err = process_next_packet(des_con, areq, PROCESS_NEW_PACKET);
}
else
err = process_next_packet(des_con, areq, PROCESS_SCATTER);
if (err == -EINVAL) {
areq->base.complete(&areq->base, err);
lq_sg_complete(des_con);
printk("src/dst returned -EINVAL in func: %s\n", __func__);
}
else if (err > 0) {
printk("src/dst returned zero in func: %s\n", __func__);
goto des_done;
}
continue;
des_done:
//printk("debug line - %d, func: %s, qlen: %d\n", __LINE__, __func__, des_queue->list.qlen);
areq->base.complete(&areq->base, 0);
lq_sg_complete(des_con);
spin_lock_irqsave(&des_queue->lock, queue_flag);
if (des_queue->list.qlen > 0) {
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
tasklet_schedule(&des_queue->des_task);
}
else {
des_queue->hw_status = DES_IDLE;
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
}
} // while(1)
return 0;
}
/* \fn static int lq_des_queue_mgr(struct des_ctx *ctx, struct ablkcipher_request *areq,
u8 *iv, int encdec, int mode)
* \ingroup IFX_DES_FUNCTIONS
* \brief starts the process of queuing DEU requests
* \param *ctx crypto algo contax
* \param *areq Pointer to the balkcipher requests
* \param *iv Pointer to intput vector location
* \param dir Encrypt/Decrypt
* \mode The mode DES algo is running
* \return 0 if success
*/
static int lq_queue_mgr(struct des_ctx *ctx, struct ablkcipher_request *areq,
u8 *iv, int encdec, int mode)
{
int err = -EINVAL;
unsigned long queue_flag;
struct scatterlist *src = areq->src;
struct scatterlist *dst = areq->dst;
struct des_container *des_con = NULL;
u32 remain, inc, nbytes = areq->nbytes;
u32 chunk_bytes = src->length;
des_con = (struct des_container *)kmalloc(sizeof(struct des_container),
GFP_KERNEL);
if (!(des_con)) {
printk("Cannot allocate memory for AES container, fn %s, ln %d\n",
__func__, __LINE__);
return -ENOMEM;
}
/* DES encrypt/decrypt mode */
if (mode == 5) {
nbytes = DES_BLOCK_SIZE;
chunk_bytes = DES_BLOCK_SIZE;
mode = 0;
}
des_con->bytes_processed = nbytes;
des_con->arequest = (*areq);
remain = nbytes;
//printk("debug - Line: %d, func: %s, reqsize: %d, scattersize: %d\n",
// __LINE__, __func__, nbytes, chunk_bytes);
if (remain > DEU_MAX_PACKET_SIZE)
inc = DEU_MAX_PACKET_SIZE;
else if(remain > chunk_bytes)
inc = chunk_bytes;
else
inc = remain;
remain -= inc;
lq_sg_init(des_con, src, dst);
if (remain <= 0 ) {
des_con->complete = 1;
}
else
des_con->complete = 0;
des_con->nbytes = inc;
des_con->iv = iv;
des_con->mode = mode;
des_con->encdec = encdec;
spin_lock_irqsave(&des_queue->lock, queue_flag);
if (des_queue->hw_status == DES_STARTED || des_queue->hw_status == DES_BUSY ||
des_queue->list.qlen > 0) {
des_con->flag = PROCESS_NEW_PACKET;
err = ablkcipher_enqueue_request(&des_queue->list, &des_con->arequest);
if (err == -EBUSY) {
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
printk("Fail to enqueue ablkcipher request ln: %d, err: %d\n",
__LINE__, err);
return err;
}
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
return -EINPROGRESS;
}
else if (des_queue->hw_status == DES_IDLE) {
des_queue->hw_status = DES_STARTED;
}
des_con->flag = PROCESS_SCATTER;
des_con->bytes_processed -= des_con->nbytes;
err = ablkcipher_enqueue_request(&des_queue->list, &des_con->arequest);
if (err == -EBUSY) {
printk("Fail to enqueue ablkcipher request ln: %d, err: %d\n",
__LINE__, err);
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
return err;
}
spin_unlock_irqrestore(&des_queue->lock, queue_flag);
return lq_deu_des_core(ctx, des_con->dst_buf, des_con->src_buf, iv, inc, encdec, mode);
}
/* \fn static int lq_des_encrypt(struct ablkcipher_request *areq)
* \ingroup IFX_DES_FUNCTIONS
* \brief Decrypt function for DES algo
* \param *areq Pointer to ablkcipher request in memory
* \return 0 is success, -EINPROGRESS if encryting, EINVAL if failure
*/
static int lq_des_encrypt(struct ablkcipher_request *areq)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct des_ctx *ctx = crypto_ablkcipher_ctx(cipher);
return lq_queue_mgr(ctx, areq, NULL, CRYPTO_DIR_ENCRYPT, 5);
}
/* \fn static int lq_des_decrypt(struct ablkcipher_request *areq)
* \ingroup IFX_DES_FUNCTIONS
* \brief Decrypt function for DES algo
* \param *areq Pointer to ablkcipher request in memory
* \return 0 is success, -EINPROGRESS if encryting, EINVAL if failure
*/
static int lq_des_decrypt(struct ablkcipher_request *areq)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct des_ctx *ctx = crypto_ablkcipher_ctx(cipher);
return lq_queue_mgr(ctx, areq, NULL, CRYPTO_DIR_DECRYPT, 5);
}
/* \fn static int lq_ecb_des_encrypt(struct ablkcipher_request *areq)
* \ingroup IFX_DES_FUNCTIONS
* \brief Decrypt function for DES algo
* \param *areq Pointer to ablkcipher request in memory
* \return 0 is success, -EINPROGRESS if encryting, EINVAL if failure
*/
static int lq_ecb_des_encrypt(struct ablkcipher_request *areq)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct des_ctx *ctx = crypto_ablkcipher_ctx(cipher);
return lq_queue_mgr(ctx, areq, areq->info, CRYPTO_DIR_ENCRYPT, 0);
}
/* \fn static int lq_ecb_des_decrypt(struct ablkcipher_request *areq)
* \ingroup IFX_DES_FUNCTIONS
* \brief Decrypt function for DES algo
* \param *areq Pointer to ablkcipher request in memory
* \return 0 is success, -EINPROGRESS if encryting, EINVAL if failure
*/
static int lq_ecb_des_decrypt(struct ablkcipher_request *areq)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct des_ctx *ctx = crypto_ablkcipher_ctx(cipher);
return lq_queue_mgr(ctx, areq, areq->info, CRYPTO_DIR_DECRYPT, 0);
}
/* \fn static int lq_cbc_ecb_des_encrypt(struct ablkcipher_request *areq)
* \ingroup IFX_DES_FUNCTIONS
* \brief Decrypt function for DES algo
* \param *areq Pointer to ablkcipher request in memory
* \return 0 is success, -EINPROGRESS if encryting, EINVAL if failure
*/
static int lq_cbc_des_encrypt(struct ablkcipher_request *areq)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct des_ctx *ctx = crypto_ablkcipher_ctx(cipher);
return lq_queue_mgr(ctx, areq, areq->info, CRYPTO_DIR_ENCRYPT, 1);
}
/* \fn static int lq_cbc_des_decrypt(struct ablkcipher_request *areq)
* \ingroup IFX_DES_FUNCTIONS
* \brief Decrypt function for DES algo
* \param *areq Pointer to ablkcipher request in memory
* \return 0 is success, -EINPROGRESS if encryting, EINVAL if failure
*/
static int lq_cbc_des_decrypt(struct ablkcipher_request *areq)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct des_ctx *ctx = crypto_ablkcipher_ctx(cipher);
return lq_queue_mgr(ctx, areq, areq->info, CRYPTO_DIR_DECRYPT, 1);
}
struct lq_des_alg {
struct crypto_alg alg;
};
/* DES Supported algo array */
static struct lq_des_alg des_drivers_alg [] = {
{
.alg = {
.cra_name = "des",
.cra_driver_name = "lqdeu-des",
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct des_ctx),
.cra_type = &crypto_ablkcipher_type,
.cra_priority = 300,
.cra_module = THIS_MODULE,
.cra_ablkcipher = {
.setkey = lq_des_setkey,
.encrypt = lq_des_encrypt,
.decrypt = lq_des_decrypt,
.geniv = "eseqiv",
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
.ivsize = DES_BLOCK_SIZE,
}
}
},{
.alg = {
.cra_name = "ecb(des)",
.cra_driver_name = "lqdeu-ecb(des)",
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct des_ctx),
.cra_type = &crypto_ablkcipher_type,
.cra_priority = 300,
.cra_module = THIS_MODULE,
.cra_ablkcipher = {
.setkey = lq_des_setkey,
.encrypt = lq_ecb_des_encrypt,
.decrypt = lq_ecb_des_decrypt,
.geniv = "eseqiv",
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
.ivsize = DES_BLOCK_SIZE,
}
}
},{
.alg = {
.cra_name = "cbc(des)",
.cra_driver_name = "lqdeu-cbc(des)",
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct des_ctx),
.cra_type = &crypto_ablkcipher_type,
.cra_priority = 300,
.cra_module = THIS_MODULE,
.cra_ablkcipher = {
.setkey = lq_des_setkey,
.encrypt = lq_cbc_des_encrypt,
.decrypt = lq_cbc_des_decrypt,
.geniv = "eseqiv",
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
}
}
},{
.alg = {
.cra_name = "des3_ede",
.cra_driver_name = "lqdeu-des3_ede",
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct des_ctx),
.cra_type = &crypto_ablkcipher_type,
.cra_priority = 300,
.cra_module = THIS_MODULE,
.cra_ablkcipher = {
.setkey = lq_des3_ede_setkey,
.encrypt = lq_des_encrypt,
.decrypt = lq_des_decrypt,
.geniv = "eseqiv",
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
.ivsize = DES_BLOCK_SIZE,
}
}
},{
.alg = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "lqdeu-ecb(des3_ede)",
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct des_ctx),
.cra_type = &crypto_ablkcipher_type,
.cra_priority = 300,
.cra_module = THIS_MODULE,
.cra_ablkcipher = {
.setkey = lq_des3_ede_setkey,
.encrypt = lq_ecb_des_encrypt,
.decrypt = lq_ecb_des_decrypt,
.geniv = "eseqiv",
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
}
}
},{
.alg = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "lqdeu-cbc(des3_ede)",
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct des_ctx),
.cra_type = &crypto_ablkcipher_type,
.cra_priority = 300,
.cra_module = THIS_MODULE,
.cra_ablkcipher = {
.setkey = lq_des3_ede_setkey,
.encrypt = lq_cbc_des_encrypt,
.decrypt = lq_cbc_des_decrypt,
.geniv = "eseqiv",
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
}
}
}
};
/*! \fn int __init lqdeu_async_des_init (void)
* \ingroup IFX_DES_FUNCTIONS
* \brief initialize des driver
*/
int __init lqdeu_async_des_init (void)
{
int i, j, ret = -EINVAL;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
if (!disable_multiblock) {
ifxdeu_des_alg.cra_u.cipher.cia_max_nbytes = DES_BLOCK_SIZE; //(size_t)-1;
ifxdeu_des_alg.cra_u.cipher.cia_req_align = 16;
ifxdeu_des_alg.cra_u.cipher.cia_ecb = ifx_deu_des_ecb;
ifxdeu_des_alg.cra_u.cipher.cia_cbc = ifx_deu_des_cbc;
ifxdeu_des_alg.cra_u.cipher.cia_cfb = ifx_deu_des_cfb;
ifxdeu_des_alg.cra_u.cipher.cia_ofb = ifx_deu_des_ofb;
}
#endif
for (i = 0; i < ARRAY_SIZE(des_drivers_alg); i++) {
ret = crypto_register_alg(&des_drivers_alg[i].alg);
//printk("driver: %s\n", des_drivers_alg[i].alg.cra_name);
if (ret)
goto des_err;
}
des_chip_init();
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU DES initialized%s%s.\n", disable_multiblock ? "" : " (multiblock)", disable_deudma ? "" : " (DMA)");
return ret;
des_err:
for (j = 0; j < i; j++)
crypto_unregister_alg(&des_drivers_alg[i].alg);
printk(KERN_ERR "Lantiq %s driver initialization failed!\n", (char *)&des_drivers_alg[i].alg.cra_driver_name);
return ret;
cbc_des3_ede_err:
for (i = 0; i < ARRAY_SIZE(des_drivers_alg); i++) {
if (!strcmp((char *)&des_drivers_alg[i].alg.cra_name, "cbc(des3_ede)"))
crypto_unregister_alg(&des_drivers_alg[i].alg);
}
printk(KERN_ERR "Lantiq %s driver initialization failed!\n", (char *)&des_drivers_alg[i].alg.cra_driver_name);
return ret;
}
/*! \fn void __exit lqdeu_fini_async_des (void)
* \ingroup IFX_DES_FUNCTIONS
* \brief unregister des driver
*/
void __exit lqdeu_fini_async_des (void)
{
int i;
for (i = 0; i < ARRAY_SIZE(des_drivers_alg); i++)
crypto_unregister_alg(&des_drivers_alg[i].alg);
des_queue->hw_status = DES_COMPLETED;
DEU_WAKEUP_EVENT(deu_dma_priv.deu_thread_wait, DES_ASYNC_EVENT,
deu_dma_priv.des_event_flags);
kfree(des_queue);
}

View file

@ -0,0 +1,768 @@
/******************************************************************************
**
** FILE NAME : ifxmips_des.c
** PROJECT : IFX UEIP
** MODULES : DEU Module
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver for DES Algorithm
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08 Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver
*/
/*!
\file ifxmips_des.c
\ingroup IFX_DEU
\brief DES encryption DEU driver file
*/
/*!
\defgroup IFX_DES_FUNCTIONS IFX_DES_FUNCTIONS
\ingroup IFX_DEU
\brief IFX DES Encryption functions
*/
/* Project Header Files */
#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 "ifxmips_deu.h"
#if defined(CONFIG_DANUBE)
#include "ifxmips_deu_danube.h"
extern int ifx_danube_pre_1_4;
#elif defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Unkown platform"
#endif
/* DMA specific header and variables */
#if 0
#define CRTCL_SECT_INIT
#define CRTCL_SECT_START
#define CRTCL_SECT_END
#else
spinlock_t des_lock;
#define CRTCL_SECT_INIT spin_lock_init(&des_lock)
#define CRTCL_SECT_START spin_lock_irqsave(&des_lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&des_lock, flag)
#endif
/* Preprocessor declerations */
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
#define DES_3DES_START IFX_DES_CON
#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
/* Function Declaration to prevent warning messages */
void des_chip_init (void);
u32 endian_swap(u32 input);
u32 input_swap(u32 input);
int aes_memory_allocate(int value);
int des_memory_allocate(int value);
void memory_release(u32 *buffer);
u32* memory_alignment(const u8 *arg, u32 *buff_alloc, int in_out, int nbytes);
void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void ifx_deu_des (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode);
struct des_ctx {
int controlr_M;
int key_length;
u8 iv[DES_BLOCK_SIZE];
u32 expkey[DES3_EDE_EXPKEY_WORDS];
};
extern int disable_multiblock;
extern int disable_deudma;
/*! \fn int des_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
* \ingroup IFX_DES_FUNCTIONS
* \brief sets DES key
* \param tfm linux crypto algo transform
* \param key input key
* \param keylen key length
*/
int des_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen)
{
struct des_ctx *dctx = crypto_tfm_ctx(tfm);
//printk("setkey in %s\n", __FILE__);
dctx->controlr_M = 0; // des
dctx->key_length = keylen;
memcpy ((u8 *) (dctx->expkey), key, keylen);
return 0;
}
/*! \fn void ifx_deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
* \ingroup IFX_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
*/
void ifx_deu_des (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode)
{
volatile struct des_t *des = (struct des_t *) DES_3DES_START;
struct des_ctx *dctx = ctx_arg;
u32 *key = dctx->expkey;
unsigned long flag;
int i = 0;
int nblocks = 0;
CRTCL_SECT_START;
des->controlr.M = dctx->controlr_M;
if (dctx->controlr_M == 0) // des
{
des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0));
des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1));
}
else {
/* Hardware Section */
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;
}
}
des->controlr.E_D = !encdec; //encryption
des->controlr.O = mode; //0 ECB 1 CBC 2 OFB 3 CFB 4 CTR hexdump(prin,sizeof(*des));
if (mode > 0) {
des->IVHR = DEU_ENDIAN_SWAP(*(u32 *) iv_arg);
des->IVLR = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 1));
};
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));
des->ILR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + 1 + i)); /* start crypto */
while (des->controlr.BUS) {
// this will not take long
}
*((u32 *) out_arg + 0 + i) = des->OHR;
*((u32 *) out_arg + 1 + i) = des->OLR;
}
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 // not even defined
//but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR
/*! \fn void ifx_deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
* \ingroup IFX_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
*/
/*! \fn void ifx_deu_des_ecb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_des_ecb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_des (ctx, dst, src, NULL, nbytes, encdec, 0);
}
/*! \fn void ifx_deu_des_cbc (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_des_cbc (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_des (ctx, dst, src, iv, nbytes, encdec, 1);
}
/*! \fn void ifx_deu_des_ofb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_des_ofb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_des (ctx, dst, src, iv, nbytes, encdec, 2);
}
/*! \fn void ifx_deu_des_cfb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
\ingroup IFX_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
*/
void ifx_deu_des_cfb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_des (ctx, dst, src, iv, nbytes, encdec, 3);
}
/*! \fn void ifx_deu_des_ctr (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_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
*/
void ifx_deu_des_ctr (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_des (ctx, dst, src, iv, nbytes, encdec, 4);
}
/*! \fn void des_encrypt (struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
* \ingroup IFX_DES_FUNCTIONS
* \brief encrypt DES_BLOCK_SIZE of data
* \param tfm linux crypto algo transform
* \param out output bytestream
* \param in input bytestream
*/
void des_encrypt (struct crypto_tfm *tfm, uint8_t * out, const uint8_t * in)
{
struct des_ctx *ctx = crypto_tfm_ctx(tfm);
ifx_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 IFX_DES_FUNCTIONS
* \brief encrypt DES_BLOCK_SIZE of data
* \param tfm linux crypto algo transform
* \param out output bytestream
* \param in input bytestream
*/
void des_decrypt (struct crypto_tfm *tfm, uint8_t * out, const uint8_t * in)
{
struct des_ctx *ctx = crypto_tfm_ctx(tfm);
ifx_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 IFX_DES_FUNCTIONS
* \brief sets 3DES key
* \param tfm linux crypto algo transform
* \param key input key
* \param keylen key length
*/
int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen)
{
struct des_ctx *dctx = crypto_tfm_ctx(tfm);
//printk("setkey in %s\n", __FILE__);
dctx->controlr_M = keylen / 8 + 1; // 3DES EDE1 / EDE2 / EDE3 Mode
dctx->key_length = keylen;
memcpy ((u8 *) (dctx->expkey), key, keylen);
return 0;
}
/*
* \brief DES function mappings
*/
struct crypto_alg ifxdeu_des_alg = {
.cra_name = "des",
.cra_driver_name = "ifxdeu-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(ifxdeu_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
*/
struct crypto_alg ifxdeu_des3_ede_alg = {
.cra_name = "des3_ede",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 IFX_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
*/
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;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
nbytes -= (nbytes % DES_BLOCK_SIZE);
ifx_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 IFX_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
*/
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(1, "\n");
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
nbytes -= (nbytes % DES_BLOCK_SIZE);
ifx_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
*/
struct crypto_alg ifxdeu_ecb_des_alg = {
.cra_name = "ecb(des)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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
*/
struct crypto_alg ifxdeu_ecb_des3_ede_alg = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 IFX_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
*/
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(1, "\n");
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
u8 *iv = walk.iv;
nbytes -= (nbytes % DES_BLOCK_SIZE);
ifx_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 IFX_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
*/
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(1, "\n");
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
u8 *iv = walk.iv;
nbytes -= (nbytes % DES_BLOCK_SIZE);
ifx_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
*/
struct crypto_alg ifxdeu_cbc_des_alg = {
.cra_name = "cbc(des)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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
*/
struct crypto_alg ifxdeu_cbc_des3_ede_alg = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "ifxdeu-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(ifxdeu_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 __init ifxdeu_init_des (void)
* \ingroup IFX_DES_FUNCTIONS
* \brief initialize des driver
*/
int __init ifxdeu_init_des (void)
{
int ret = -ENOSYS;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
if (!disable_multiblock) {
ifxdeu_des_alg.cra_u.cipher.cia_max_nbytes = DES_BLOCK_SIZE; //(size_t)-1;
ifxdeu_des_alg.cra_u.cipher.cia_req_align = 16;
ifxdeu_des_alg.cra_u.cipher.cia_ecb = ifx_deu_des_ecb;
ifxdeu_des_alg.cra_u.cipher.cia_cbc = ifx_deu_des_cbc;
ifxdeu_des_alg.cra_u.cipher.cia_cfb = ifx_deu_des_cfb;
ifxdeu_des_alg.cra_u.cipher.cia_ofb = ifx_deu_des_ofb;
}
#endif
ret = crypto_register_alg(&ifxdeu_des_alg);
if (ret < 0)
goto des_err;
ret = crypto_register_alg(&ifxdeu_ecb_des_alg);
if (ret < 0)
goto ecb_des_err;
ret = crypto_register_alg(&ifxdeu_cbc_des_alg);
if (ret < 0)
goto cbc_des_err;
ret = crypto_register_alg(&ifxdeu_des3_ede_alg);
if (ret < 0)
goto des3_ede_err;
ret = crypto_register_alg(&ifxdeu_ecb_des3_ede_alg);
if (ret < 0)
goto ecb_des3_ede_err;
ret = crypto_register_alg(&ifxdeu_cbc_des3_ede_alg);
if (ret < 0)
goto cbc_des3_ede_err;
des_chip_init();
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU DES initialized%s%s.\n", disable_multiblock ? "" : " (multiblock)", disable_deudma ? "" : " (DMA)");
return ret;
des_err:
crypto_unregister_alg(&ifxdeu_des_alg);
printk(KERN_ERR "IFX des initialization failed!\n");
return ret;
ecb_des_err:
crypto_unregister_alg(&ifxdeu_ecb_des_alg);
printk (KERN_ERR "IFX ecb_des initialization failed!\n");
return ret;
cbc_des_err:
crypto_unregister_alg(&ifxdeu_cbc_des_alg);
printk (KERN_ERR "IFX cbc_des initialization failed!\n");
return ret;
des3_ede_err:
crypto_unregister_alg(&ifxdeu_des3_ede_alg);
printk(KERN_ERR "IFX des3_ede initialization failed!\n");
return ret;
ecb_des3_ede_err:
crypto_unregister_alg(&ifxdeu_ecb_des3_ede_alg);
printk (KERN_ERR "IFX ecb_des3_ede initialization failed!\n");
return ret;
cbc_des3_ede_err:
crypto_unregister_alg(&ifxdeu_cbc_des3_ede_alg);
printk (KERN_ERR "IFX cbc_des3_ede initialization failed!\n");
return ret;
}
/*! \fn void __exit ifxdeu_fini_des (void)
* \ingroup IFX_DES_FUNCTIONS
* \brief unregister des driver
*/
void __exit ifxdeu_fini_des (void)
{
crypto_unregister_alg (&ifxdeu_des_alg);
crypto_unregister_alg (&ifxdeu_ecb_des_alg);
crypto_unregister_alg (&ifxdeu_cbc_des_alg);
crypto_unregister_alg (&ifxdeu_des3_ede_alg);
crypto_unregister_alg (&ifxdeu_ecb_des3_ede_alg);
crypto_unregister_alg (&ifxdeu_cbc_des3_ede_alg);
}

View file

@ -0,0 +1,210 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for Danube
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_deu.c
\ingroup IFX_DEU
\brief main deu driver file
*/
/*!
\defgroup IFX_DEU_FUNCTIONS IFX_DEU_FUNCTIONS
\ingroup IFX_DEU
\brief IFX DEU functions
*/
/* Project header */
#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/platform_device.h>
#include <linux/fs.h> /* Stuff about file systems that we need */
#include <asm/byteorder.h>
#include "ifxmips_deu.h"
#include <lantiq_soc.h>
#if defined(CONFIG_DANUBE)
#include "ifxmips_deu_danube.h"
#elif defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Platform unknown!"
#endif /* CONFIG_xxxx */
int disable_deudma = 1;
void chip_version(void);
/*! \fn static int __init deu_init (void)
* \ingroup IFX_DEU_FUNCTIONS
* \brief link all modules that have been selected in kernel config for ifx hw crypto support
* \return ret
*/
static int __devinit ltq_deu_probe(struct platform_device *pdev)
{
int ret = -ENOSYS;
START_DEU_POWER;
#define IFX_DEU_DRV_VERSION "2.0.0"
printk(KERN_INFO "Infineon Technologies DEU driver version %s \n", IFX_DEU_DRV_VERSION);
FIND_DEU_CHIP_VERSION;
#if defined(CONFIG_CRYPTO_DEV_DES)
if ((ret = ifxdeu_init_des ())) {
printk (KERN_ERR "IFX DES initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_AES)
if ((ret = ifxdeu_init_aes ())) {
printk (KERN_ERR "IFX AES initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_ARC4)
if ((ret = ifxdeu_init_arc4 ())) {
printk (KERN_ERR "IFX ARC4 initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_SHA1)
if ((ret = ifxdeu_init_sha1 ())) {
printk (KERN_ERR "IFX SHA1 initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_MD5)
if ((ret = ifxdeu_init_md5 ())) {
printk (KERN_ERR "IFX MD5 initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_SHA1_HMAC)
if ((ret = ifxdeu_init_sha1_hmac ())) {
printk (KERN_ERR "IFX SHA1_HMAC initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_MD5_HMAC)
if ((ret = ifxdeu_init_md5_hmac ())) {
printk (KERN_ERR "IFX MD5_HMAC initialization failed!\n");
}
#endif
return ret;
}
/*! \fn static void __exit deu_fini (void)
* \ingroup IFX_DEU_FUNCTIONS
* \brief remove the loaded crypto algorithms
*/
static int __devexit ltq_deu_remove(struct platform_device *pdev)
{
//#ifdef CONFIG_CRYPTO_DEV_PWR_SAVE_MODE
#if defined(CONFIG_CRYPTO_DEV_DES)
ifxdeu_fini_des ();
#endif
#if defined(CONFIG_CRYPTO_DEV_AES)
ifxdeu_fini_aes ();
#endif
#if defined(CONFIG_CRYPTO_DEV_ARC4)
ifxdeu_fini_arc4 ();
#endif
#if defined(CONFIG_CRYPTO_DEV_SHA1)
ifxdeu_fini_sha1 ();
#endif
#if defined(CONFIG_CRYPTO_DEV_MD5)
ifxdeu_fini_md5 ();
#endif
#if defined(CONFIG_CRYPTO_DEV_SHA1_HMAC)
ifxdeu_fini_sha1_hmac ();
#endif
#if defined(CONFIG_CRYPTO_DEV_MD5_HMAC)
ifxdeu_fini_md5_hmac ();
#endif
printk("DEU has exited successfully\n");
return 0;
}
int disable_multiblock = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
module_param(disable_multiblock,int,0);
#else
//MODULE_PARM (disable_multiblock, "i");
MODULE_PARM_DESC (disable_multiblock,
"Disable encryption of whole multiblock buffers.");
#endif
static const struct of_device_id ltq_deu_match[] = {
#ifdef CONFIG_DANUBE
{ .compatible = "lantiq,deu-danube"},
#elif defined CONFIG_AR9
{ .compatible = "lantiq,deu-arx100"},
#elif defined CONFIG_VR9
{ .compatible = "lantiq,deu-xrx200"},
#endif
{},
};
MODULE_DEVICE_TABLE(of, ltq_deu_match);
static struct platform_driver ltq_deu_driver = {
.probe = ltq_deu_probe,
.remove = __devexit_p(ltq_deu_remove),
.driver = {
.name = "deu",
.owner = THIS_MODULE,
.of_match_table = ltq_deu_match,
},
};
module_platform_driver(ltq_deu_driver);
MODULE_DESCRIPTION ("Infineon DEU crypto engine support.");
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("Mohammad Firdaus");

View file

@ -0,0 +1,232 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu.h
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_deu.h
\brief main deu driver header file
*/
/*!
\defgroup IFX_DEU_DEFINITIONS IFX_DEU_DEFINITIONS
\ingroup IFX_DEU
\brief ifx deu definitions
*/
#ifndef IFXMIPS_DEU_H
#define IFXMIPS_DEU_H
#include <crypto/algapi.h>
#include <linux/interrupt.h>
#define IFXDEU_ALIGNMENT 16
#define IFX_DEU_BASE_ADDR (KSEG1 | 0x1E103100)
#define IFX_DEU_CLK ((volatile u32 *)(IFX_DEU_BASE_ADDR + 0x0000))
#define IFX_DES_CON ((volatile u32 *)(IFX_DEU_BASE_ADDR + 0x0010))
#define IFX_AES_CON ((volatile u32 *)(IFX_DEU_BASE_ADDR + 0x0050))
#define IFX_HASH_CON ((volatile u32 *)(IFX_DEU_BASE_ADDR + 0x00B0))
#define IFX_ARC4_CON ((volatile u32 *)(IFX_DEU_BASE_ADDR + 0x0100))
#define PFX "ifxdeu: "
#define CLC_START IFX_DEU_CLK
#define IFXDEU_CRA_PRIORITY 300
#define IFXDEU_COMPOSITE_PRIORITY 400
//#define KSEG1 0xA0000000
#define IFX_PMU_ENABLE 1
#define IFX_PMU_DISABLE 0
#define CRYPTO_DIR_ENCRYPT 1
#define CRYPTO_DIR_DECRYPT 0
#define AES_IDLE 0
#define AES_BUSY 1
#define AES_STARTED 2
#define AES_COMPLETED 3
#define DES_IDLE 0
#define DES_BUSY 1
#define DES_STARTED 2
#define DES_COMPLETED 3
#define PROCESS_SCATTER 1
#define PROCESS_NEW_PACKET 2
#define PMU_DEU BIT(20)
#define START_DEU_POWER \
do { \
volatile struct clc_controlr_t *clc = (struct clc_controlr_t *) CLC_START; \
ltq_pmu_enable(PMU_DEU); \
clc->FSOE = 0; \
clc->SBWE = 0; \
clc->SPEN = 0; \
clc->SBWE = 0; \
clc->DISS = 0; \
clc->DISR = 0; \
} while(0)
#define STOP_DEU_POWER \
do { \
volatile struct clc_controlr_t *clc = (struct clc_controlr_t *) CLC_START; \
ltq_pmu_disable(PMU_DEU); \
clc->FSOE = 1; \
clc->SBWE = 1; \
clc->SPEN = 1; \
clc->SBWE = 1; \
clc->DISS = 1; \
clc->DISR = 1; \
} while (0)
/*
* Not used anymore in UEIP (use IFX_DES_CON, IFX_AES_CON, etc instead)
* #define DEU_BASE (KSEG1+0x1E103100)
* #define DES_CON (DEU_BASE+0x10)
* #define AES_CON (DEU_BASE+0x50)
* #define HASH_CON (DEU_BASE+0xB0)
* #define DMA_CON (DEU_BASE+0xEC)
* #define INT_CON (DEU_BASE+0xF4)
* #define ARC4_CON (DEU_BASE+0x100)
*/
int __init ifxdeu_init_des (void);
int __init ifxdeu_init_aes (void);
int __init ifxdeu_init_arc4 (void);
int __init ifxdeu_init_sha1 (void);
int __init ifxdeu_init_md5 (void);
int __init ifxdeu_init_sha1_hmac (void);
int __init ifxdeu_init_md5_hmac (void);
int __init lqdeu_async_aes_init(void);
int __init lqdeu_async_des_init(void);
void __exit ifxdeu_fini_des (void);
void __exit ifxdeu_fini_aes (void);
void __exit ifxdeu_fini_arc4 (void);
void __exit ifxdeu_fini_sha1 (void);
void __exit ifxdeu_fini_md5 (void);
void __exit ifxdeu_fini_sha1_hmac (void);
void __exit ifxdeu_fini_md5_hmac (void);
void __exit ifxdeu_fini_dma(void);
void __exit lqdeu_fini_async_aes(void);
void __exit lqdeu_fini_async_des(void);
void __exit deu_fini (void);
int deu_dma_init (void);
#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)
typedef struct deu_drv_priv {
wait_queue_head_t deu_thread_wait;
#define DEU_EVENT 1
#define DES_ASYNC_EVENT 2
#define AES_ASYNC_EVENT 3
volatile long des_event_flags;
volatile long aes_event_flags;
volatile long deu_event_flags;
int event_src;
u32 *deu_rx_buf;
u32 *outcopy;
u32 deu_rx_len;
struct aes_priv *aes_dataptr;
struct des_priv *des_dataptr;
}deu_drv_priv_t;
/**
* struct aes_priv_t - ASYNC AES
* @lock: spinlock lock
* @lock_flag: flag for spinlock activities
* @list: crypto queue API list
* @hw_status: DEU hw status flag
* @aes_wait_flag: flag for sleep queue
* @aes_wait_queue: queue attributes for aes
* @bytes_processed: number of bytes to process by DEU
* @aes_pid: pid number for AES thread
* @aes_sync: atomic wait sync for AES
*
*/
typedef struct {
spinlock_t lock;
struct crypto_queue list;
unsigned int hw_status;
volatile long aes_wait_flag;
wait_queue_head_t aes_wait_queue;
pid_t aes_pid;
struct tasklet_struct aes_task;
} aes_priv_t;
/**
* struct des_priv_t - ASYNC DES
* @lock: spinlock lock
* @list: crypto queue API list
* @hw_status: DEU hw status flag
* @des_wait_flag: flag for sleep queue
* @des_wait_queue: queue attributes for des
* @des_pid: pid number for DES thread
* @des_sync: atomic wait sync for DES
*
*/
typedef struct {
spinlock_t lock;
struct crypto_queue list;
unsigned int hw_status;
volatile long des_wait_flag;
wait_queue_head_t des_wait_queue;
pid_t des_pid;
struct tasklet_struct des_task;
} des_priv_t;
#endif /* IFXMIPS_DEU_H */

View file

@ -0,0 +1,135 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_ar9.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for AR9
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_deu_ar9.c
\brief ifx deu board specific driver file for ar9
*/
/*!
\defgroup BOARD_SPECIFIC_FUNCTIONS IFX_BOARD_SPECIFIC_FUNCTIONS
\ingroup IFX_DEU
\brief board specific functions
*/
/* Project header files */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/io.h> //dma_cache_inv
#include "ifxmips_deu_dma.h"
#include "ifxmips_deu_ar9.h"
/* Function decleration */
void aes_chip_init (void);
void des_chip_init (void);
int deu_dma_init (void);
u32 endian_swap(u32 input);
u32* memory_alignment(const u8 *arg, u32 *buff_alloc, int in_out, int nbytes);
void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void deu_dma_priv_init(void);
void __exit ifxdeu_fini_dma(void);
#define DES_3DES_START IFX_DES_CON
#define AES_START IFX_AES_CON
#define CLC_START IFX_DEU_CLK
/* Variables */
u8 *g_dma_page_ptr = NULL;
u8 *g_dma_block = NULL;
u8 *g_dma_block2 = NULL;
deu_drv_priv_t deu_dma_priv;
/*! \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
*/
u32 endian_swap(u32 input)
{
return input;
}
/*! \fn u32 input_swap(u32 input)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief Not used
* \return input
*/
u32 input_swap(u32 input)
{
return input;
}
/*! \fn void aes_chip_init (void)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief initialize AES hardware
*/
void aes_chip_init (void)
{
volatile struct aes_t *aes = (struct aes_t *) AES_START;
aes->controlr.SM = 1;
aes->controlr.ARS = 1;
}
/*! \fn void des_chip_init (void)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief initialize DES hardware
*/
void des_chip_init (void)
{
volatile struct des_t *des = (struct des_t *) DES_3DES_START;
// start crypto engine with write to ILR
des->controlr.SM = 1;
asm("sync");
des->controlr.ARS = 1;
}
/*! \fn void chip_version(void)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief not used!
*/
void chip_version(void)
{
return;
}

View file

@ -0,0 +1,299 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_ar9.h
** PROJECT : IFX UEIP
** MODULES : DEU Module for AR9
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief deu driver module
*/
/*!
\defgroup IFX_DEU_DEFINITIONS IFX_DEU_DEFINITIONS
\ingroup IFX_DEU
\brief ifx deu definitions
*/
/*!
\file ifxmips_deu_ar9.h
\brief deu driver header file
*/
#ifndef IFXMIPS_DEU_AR9_H
#define IFXMIPS_DEU_AR9_H
/* Project Header Files */
#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 <linux/module.h>
#include <linux/mm.h>
#include <asm/scatterlist.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include "ifxmips_deu.h"
/* SHA CONSTANTS */
#define HASH_CON_VALUE 0x0700002C
#define INPUT_ENDIAN_SWAP(input) input_swap(input)
#define DEU_ENDIAN_SWAP(input) endian_swap(input)
#define DELAY_PERIOD 10
#define FIND_DEU_CHIP_VERSION chip_version()
#define CLC_START IFX_DEU_CLK
#define AES_INIT 0
#define DES_INIT 1
#define ARC4_INIT 2
#define SHA1_INIT 3
#define MD5_INIT 4
#define SHA1_HMAC_INIT 5
#define MD5_HMAC_INIT 6
#define AES_START IFX_AES_CON
#define DES_3DES_START IFX_DES_CON
#define WAIT_AES_DMA_READY() \
do { \
int i; \
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON; \
volatile struct aes_t *aes = (volatile struct aes_t *) AES_START; \
for (i = 0; i < 10; i++) \
udelay(DELAY_PERIOD); \
while (dma->controlr.BSY) {}; \
while (aes->controlr.BUS) {}; \
} while (0)
#define WAIT_DES_DMA_READY() \
do { \
int i; \
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON; \
volatile struct des_t *des = (struct des_t *) DES_3DES_START; \
for (i = 0; i < 10; i++) \
udelay(DELAY_PERIOD); \
while (dma->controlr.BSY) {}; \
while (des->controlr.BUS) {}; \
} while (0)
#define AES_DMA_MISC_CONFIG() \
do { \
volatile struct aes_t *aes = (volatile struct aes_t *) AES_START; \
aes->controlr.KRE = 1; \
aes->controlr.GO = 1; \
} while(0)
#define SHA_HASH_INIT \
do { \
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START; \
hash->controlr.SM = 1; \
hash->controlr.ALGO = 0; \
hash->controlr.INIT = 1; \
} while(0)
/* DEU Common Structures for AR9*/
struct clc_controlr_t {
u32 Res:26;
u32 FSOE:1;
u32 SBWE:1;
u32 EDIS:1;
u32 SPEN:1;
u32 DISS:1;
u32 DISR:1;
};
struct des_t {
struct des_controlr { //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;
} controlr;
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 aes_t {
struct aes_controlr {
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
} controlr;
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 arc4_t {
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;
} controlr;
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_t {
struct hash_controlr {
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;
} controlr;
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_t {
struct dma_controlr {
u32 reserved1:22;
u32 BS:2;
u32 BSY:1;
u32 reserved2:1;
u32 ALGO:2;
u32 RXCLS:2;
u32 reserved3:1;
u32 EN:1;
} controlr;
};
#endif /* IFXMIPS_DEU_AR9_H */

View file

@ -0,0 +1,168 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_danube.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for Danube
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief deu driver module
*/
/*!
\file ifxmips_deu_danube.c
\ingroup IFX_DEU
\brief board specific deu driver file for danube
*/
/*!
\defgroup BOARD_SPECIFIC_FUNCTIONS IFX_BOARD_SPECIFIC_FUNCTIONS
\ingroup IFX_DEU
\brief board specific deu functions
*/
/* Project header files */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/io.h> //dma_cache_inv
#include "ifxmips_deu_dma.h"
#include "ifxmips_deu_danube.h"
/* Function Declerations */
int aes_memory_allocate(int value);
int des_memory_allocate(int value);
void memory_release(u32 *addr);
int aes_chip_init (void);
void des_chip_init (void);
int deu_dma_init (void);
u32 endian_swap(u32 input);
u32* memory_alignment(const u8 *arg, u32 *buff_alloc, int in_out, int nbytes);
void dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void chip_version(void);
void deu_dma_priv_init(void);
void __exit ifxdeu_fini_dma(void);
#define DES_3DES_START IFX_DES_CON
#define AES_START IFX_AES_CON
#define CLC_START IFX_DEU_CLK
/* Variables definition */
int ifx_danube_pre_1_4;
u8 *g_dma_page_ptr = NULL;
u8 *g_dma_block = NULL;
u8 *g_dma_block2 = NULL;
deu_drv_priv_t deu_dma_priv;
/*! \fn u32 endian_swap(u32 input)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief function is not used
* \param input Data input to be swapped
* \return input
*/
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
*/
u32 input_swap(u32 input)
{
if (!ifx_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
*/
int aes_chip_init (void)
{
volatile struct aes_t *aes = (struct aes_t *) AES_START;
//start crypto engine with write to ILR
aes->controlr.SM = 1;
aes->controlr.ARS = 1;
return 0;
}
/*! \fn void des_chip_init (void)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief initialize DES hardware
*/
void des_chip_init (void)
{
volatile struct des_t *des = (struct des_t *) DES_3DES_START;
// start crypto engine with write to ILR
des->controlr.SM = 1;
des->controlr.ARS = 1;
}
/*! \fn void chip_version (void)
* \ingroup IFX_DES_FUNCTIONS
* \brief To find the version of the chip by looking at the chip ID
* \param ifx_danube_pre_1_4 (sets to 1 if Chip is Danube less than v1.4)
*/
#define IFX_MPS (KSEG1 | 0x1F107000)
#define IFX_MPS_CHIPID ((volatile u32*)(IFX_MPS + 0x0344))
void chip_version(void)
{
/* DANUBE PRE 1.4 SOFTWARE FIX */
int chip_id = 0;
chip_id = *IFX_MPS_CHIPID;
chip_id >>= 28;
if (chip_id >= 4) {
ifx_danube_pre_1_4 = 0;
printk("Danube Chip ver. 1.4 detected. \n");
}
else {
ifx_danube_pre_1_4 = 1;
printk("Danube Chip ver. 1.3 or below detected. \n");
}
return;
}

View file

@ -0,0 +1,250 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_danube.h
** PROJECT : IFX UEIP
** MODULES : DEU Module for Danube
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief deu driver module
*/
/*!
\file ifxmips_deu_danube.h
\brief board specific driver header file for danube
*/
/*!
\defgroup BOARD_SPECIFIC_FUNCTIONS IFX_BOARD_SPECIFIC_FUNCTIONS
\ingroup IFX_DEU
\brief board specific deu header files
*/
#ifndef IFXMIPS_DEU_DANUBE_H
#define IFXMIPS_DEU_DANUBE_H
/* Project Header Files */
#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 <linux/module.h>
#include <linux/mm.h>
#include <asm/scatterlist.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include "ifxmips_deu.h"
#define INPUT_ENDIAN_SWAP(input) input_swap(input)
#define DEU_ENDIAN_SWAP(input) endian_swap(input)
#define FIND_DEU_CHIP_VERSION chip_version()
#define AES_DMA_MISC_CONFIG()
#define CLC_START IFX_DEU_CLK
#define AES_START IFX_AES_CON
#define DES_3DES_START IFX_DES_CON
#define AES_INIT 0
#define DES_INIT 1
#define SHA1_INIT 2
#define MD5_INIT 3
#define WAIT_AES_DMA_READY() \
do { \
int i; \
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON; \
volatile struct aes_t *aes = (volatile struct aes_t *) AES_START; \
for (i = 0; i < 10; i++) \
udelay(DELAY_PERIOD); \
while (dma->controlr.BSY) {}; \
while (aes->controlr.BUS) {}; \
} while (0)
#define WAIT_DES_DMA_READY() \
do { \
int i; \
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON; \
volatile struct des_t *des = (struct des_t *) DES_3DES_START; \
for (i = 0; i < 10; i++) \
udelay(DELAY_PERIOD); \
while (dma->controlr.BSY) {}; \
while (des->controlr.BUS) {}; \
} while (0)
#define SHA_HASH_INIT \
do { \
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START; \
hash->controlr.SM = 1; \
hash->controlr.ALGO = 0; \
hash->controlr.INIT = 1; \
} while(0)
/* DEU STRUCTURES */
struct clc_controlr_t {
u32 Res:26;
u32 FSOE:1;
u32 SBWE:1;
u32 EDIS:1;
u32 SPEN:1;
u32 DISS:1;
u32 DISR:1;
};
struct des_t {
struct des_controlr { //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;
} controlr;
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 aes_t {
struct aes_controlr {
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
} controlr;
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_t {
struct hash_controlr {
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;
} controlr;
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_t {
struct dma_controlr {
u32 reserved1:22;
u32 BS:2;
u32 BSY:1;
u32 reserved2:1;
u32 ALGO:2;
u32 RXCLS:2;
u32 reserved3:1;
u32 EN:1;
} controlr;
};
#endif /* IFXMIPS_DEU_DANUBE_H */

View file

@ -0,0 +1,42 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_dma.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for Danube
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08 Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup IFX_API
\brief ifx deu driver module
*/
/*!
\file ifxmips_deu_dma.c
\ingroup IFX_DEU
\brief DMA deu driver file
*/
/*!
\defgroup IFX_DMA_FUNCTIONS IFX_DMA_FUNCTIONS
\ingroup IFX_DEU
\brief deu-dma driver functions
*/
/* Project header files */

View file

@ -0,0 +1,69 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_dma.h
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\addtogroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_deu_dma.h
\ingroup IFX_DEU
\brief DMA deu driver header file
*/
#ifndef IFXMIPS_DEU_DMA_H
#define IFXMIPS_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>
// must match the size of memory block allocated for g_dma_block and g_dma_block2
#define DEU_MAX_PACKET_SIZE (PAGE_SIZE >> 1)
typedef struct ifx_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;
} _ifx_deu_device;
extern _ifx_deu_device ifx_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 */

View file

@ -0,0 +1,144 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_vr9.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for VR9
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief deu driver module
*/
/*!
\file ifxmips_deu_vr9.c
\ingroup IFX_DEU
\brief board specific deu driver file for vr9
*/
/*!
\defgroup BOARD_SPECIFIC_FUNCTIONS IFX_BOARD_SPECIFIC_FUNCTIONS
\ingroup IFX_DEU
\brief board specific deu driver functions
*/
/* Project header files */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/io.h> //dma_cache_inv
#include "ifxmips_deu_dma.h"
#include "ifxmips_deu_vr9.h"
/* Function decleration */
void aes_chip_init (void);
void des_chip_init (void);
int deu_dma_init (void);
void deu_dma_priv_init(void);
u32 endian_swap(u32 input);
u32* memory_alignment(const u8 *arg, u32 *buff_alloc, int in_out, int nbytes);
void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void __exit ifxdeu_fini_dma(void);
#define DES_3DES_START IFX_DES_CON
#define AES_START IFX_AES_CON
/* Variables */
u8 *g_dma_page_ptr = NULL;
u8 *g_dma_block = NULL;
u8 *g_dma_block2 = NULL;
deu_drv_priv_t deu_dma_priv;
/*! \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
*/
u32 endian_swap(u32 input)
{
return input;
}
/*! \fn u32 input_swap(u32 input)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief Not used
* \return input
*/
u32 input_swap(u32 input)
{
return input;
}
/*! \fn void aes_chip_init (void)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief initialize AES hardware
*/
void aes_chip_init (void)
{
volatile struct aes_t *aes = (struct aes_t *) AES_START;
// start crypto engine with write to ILR
aes->controlr.SM = 1;
aes->controlr.NDC = 0;
asm("sync");
aes->controlr.ENDI = 1;
asm("sync");
aes->controlr.ARS = 0;
}
/*! \fn void des_chip_init (void)
* \ingroup IFX_AES_FUNCTIONS
* \brief initialize DES hardware
*/
void des_chip_init (void)
{
volatile struct des_t *des = (struct des_t *) DES_3DES_START;
// start crypto engine with write to ILR
des->controlr.SM = 1;
des->controlr.NDC = 1;
asm("sync");
des->controlr.ENDI = 1;
asm("sync");
des->controlr.ARS = 0;
}
/*! \fn void chip_version(void)
* \ingroup IFX_DES_FUNCTIONS
* \brief function not used in VR9
*/
void chip_version(void)
{
return;
}

View file

@ -0,0 +1,324 @@
/******************************************************************************
**
** FILE NAME : ifxmips_deu_vr9.h
** PROJECT : IFX UEIP
** MODULES : DEU Module for VR9
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief deu driver module
*/
/*!
\file ifxmips_deu_vr9.h
\ingroup IFX_DEU
\brief board specific deu driver header file for vr9
*/
/*!
\defgroup IFX_DEU_DEFINITIONS IFX_DEU_DEFINITIONS
\brief deu driver header file
*/
#ifndef IFXMIPS_DEU_VR9_H
#define IFXMIPS_DEU_VR9_H
/* Project Header Files */
#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 <linux/module.h>
#include <linux/mm.h>
#include <asm/scatterlist.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include "ifxmips_deu.h"
#define AES_INIT 1
#define DES_INIT 2
#define ARC4_INIT 3
#define SHA1_INIT 4
#define MD5_INIT 5
#define SHA1_HMAC_INIT 6
#define MD5_HMAC_INIT 7
#define AES_START IFX_AES_CON
#define DES_3DES_START IFX_DES_CON
#if 0
#define AES_IDLE 0
#define AES_BUSY 1
#define AES_STARTED 2
#define AES_COMPLETED 3
#define DES_IDLE 0
#define DES_BUSY 1
#define DES_STARTED 2
#define DES_COMPLETED 3
#endif
/* SHA1 CONSTANT */
#define HASH_CON_VALUE 0x0701002C
#define INPUT_ENDIAN_SWAP(input) input_swap(input)
#define DEU_ENDIAN_SWAP(input) endian_swap(input)
#define FIND_DEU_CHIP_VERSION chip_version()
#if defined (CONFIG_AR10)
#define DELAY_PERIOD 30
#else
#define DELAY_PERIOD 10
#endif
#define WAIT_AES_DMA_READY() \
do { \
int i; \
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON; \
volatile struct aes_t *aes = (volatile struct aes_t *) AES_START; \
for (i = 0; i < 10; i++) \
udelay(DELAY_PERIOD); \
while (dma->controlr.BSY) {}; \
while (aes->controlr.BUS) {}; \
} while (0)
#define WAIT_DES_DMA_READY() \
do { \
int i; \
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON; \
volatile struct des_t *des = (struct des_t *) DES_3DES_START; \
for (i = 0; i < 10; i++) \
udelay(DELAY_PERIOD); \
while (dma->controlr.BSY) {}; \
while (des->controlr.BUS) {}; \
} while (0)
#define AES_DMA_MISC_CONFIG() \
do { \
volatile struct aes_t *aes = (volatile struct aes_t *) AES_START; \
aes->controlr.KRE = 1; \
aes->controlr.GO = 1; \
} while(0)
#define SHA_HASH_INIT \
do { \
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START; \
hash->controlr.ENDI = 1; \
hash->controlr.SM = 1; \
hash->controlr.ALGO = 0; \
hash->controlr.INIT = 1; \
} while(0)
#define MD5_HASH_INIT \
do { \
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START; \
hash->controlr.ENDI = 1; \
hash->controlr.SM = 1; \
hash->controlr.ALGO = 1; \
hash->controlr.INIT = 1; \
} while(0)
/* DEU Common Structures for AR9*/
struct clc_controlr_t {
u32 Res:26;
u32 FSOE:1;
u32 SBWE:1;
u32 EDIS:1;
u32 SPEN:1;
u32 DISS:1;
u32 DISR:1;
};
struct des_t {
struct des_controlr { //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;
} controlr;
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 aes_t {
struct aes_controlr {
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
} controlr;
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 arc4_t {
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;
} controlr;
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_t {
struct hash_controlr {
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;
} controlr;
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_t {
struct dma_controlr {
u32 reserved1:22;
u32 BS:2;
u32 BSY:1;
u32 reserved2:1;
u32 ALGO:2;
u32 RXCLS:2;
u32 reserved3:1;
u32 EN:1;
} controlr;
};
#endif /* IFXMIPS_DEU_VR9_H */

View file

@ -0,0 +1,310 @@
/******************************************************************************
**
** FILE NAME : ifxmips_md5.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for UEIP
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_md5.c
\ingroup IFX_DEU
\brief MD5 encryption deu driver file
*/
/*!
\defgroup IFX_MD5_FUNCTIONS IFX_MD5_FUNCTIONS
\ingroup IFX_DEU
\brief ifx deu MD5 functions
*/
/*Project header files */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/crypto.h>
#include <linux/types.h>
#include <crypto/internal/hash.h>
#include <asm/byteorder.h>
/* Project header */
#if defined(CONFIG_DANUBE)
#include "ifxmips_deu_danube.h"
#elif defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Plaform Unknwon!"
#endif
#define MD5_DIGEST_SIZE 16
#define MD5_HMAC_BLOCK_SIZE 64
#define MD5_BLOCK_WORDS 16
#define MD5_HASH_WORDS 4
#define HASH_START IFX_HASH_CON
static spinlock_t lock;
#define CRTCL_SECT_INIT spin_lock_init(&lock)
#define CRTCL_SECT_START spin_lock_irqsave(&lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag)
//#define CRYPTO_DEBUG
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
struct md5_ctx {
int started;
u32 hash[MD5_HASH_WORDS];
u32 block[MD5_BLOCK_WORDS];
u64 byte_count;
};
extern int disable_deudma;
/*! \fn static u32 endian_swap(u32 input)
* \ingroup IFX_MD5_FUNCTIONS
* \brief perform dword level endian swap
* \param input value of dword that requires to be swapped
*/
static u32 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 IFX_MD5_FUNCTIONS
* \brief main interface to md5 hardware
* \param hash current hash value
* \param in 64-byte block of input
*/
static void md5_transform(struct md5_ctx *mctx, u32 *hash, u32 const *in)
{
int i;
volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START;
unsigned long flag;
CRTCL_SECT_START;
if (mctx->started) {
hashs->D1R = endian_swap(*((u32 *) hash + 0));
hashs->D2R = endian_swap(*((u32 *) hash + 1));
hashs->D3R = endian_swap(*((u32 *) hash + 2));
hashs->D4R = endian_swap(*((u32 *) hash + 3));
}
for (i = 0; i < 16; i++) {
hashs->MR = endian_swap(in[i]);
// printk("in[%d]: %08x\n", i, endian_swap(in[i]));
};
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
*((u32 *) hash + 0) = endian_swap (hashs->D1R);
*((u32 *) hash + 1) = endian_swap (hashs->D2R);
*((u32 *) hash + 2) = endian_swap (hashs->D3R);
*((u32 *) hash + 3) = endian_swap (hashs->D4R);
mctx->started = 1;
CRTCL_SECT_END;
}
/*! \fn static inline void md5_transform_helper(struct md5_ctx *ctx)
* \ingroup IFX_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, ctx->hash, ctx->block);
}
/*! \fn static void md5_init(struct crypto_tfm *tfm)
* \ingroup IFX_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_t *hash = (struct deu_hash_t *) HASH_START;
hash->controlr.ENDI = 0;
hash->controlr.SM = 1;
hash->controlr.ALGO = 1; // 1 = md5 0 = sha1
hash->controlr.INIT = 1; // Initialize the hash operation by writing a '1' to the INIT bit.
mctx->byte_count = 0;
mctx->started = 0;
return 0;
}
/*! \fn static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
* \ingroup IFX_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 IFX_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_t *hashs = (struct deu_hash_t *) 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] = endian_swap(mctx->byte_count << 3);
mctx->block[15] = 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, mctx->hash, mctx->block);
CRTCL_SECT_START;
*((u32 *) out + 0) = endian_swap (hashs->D1R);
*((u32 *) out + 1) = endian_swap (hashs->D2R);
*((u32 *) out + 2) = endian_swap (hashs->D3R);
*((u32 *) out + 3) = endian_swap (hashs->D4R);
CRTCL_SECT_END;
// Wipe context
memset(mctx, 0, sizeof(*mctx));
return 0;
}
/*
* \brief MD5 function mappings
*/
static struct shash_alg ifxdeu_md5_alg = {
.digestsize = MD5_DIGEST_SIZE,
.init = md5_init,
.update = md5_update,
.final = md5_final,
.descsize = sizeof(struct md5_ctx),
.base = {
.cra_name = "md5",
.cra_driver_name= "ifxdeu-md5",
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_module = THIS_MODULE,
}
};
/*! \fn int __init ifxdeu_init_md5 (void)
* \ingroup IFX_MD5_FUNCTIONS
* \brief initialize md5 driver
*/
int __init ifxdeu_init_md5 (void)
{
int ret = -ENOSYS;
if ((ret = crypto_register_shash(&ifxdeu_md5_alg)))
goto md5_err;
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU MD5 initialized%s.\n", disable_deudma ? "" : " (DMA)");
return ret;
md5_err:
printk(KERN_ERR "IFX DEU MD5 initialization failed!\n");
return ret;
}
/*! \fn void __exit ifxdeu_fini_md5 (void)
* \ingroup IFX_MD5_FUNCTIONS
* \brief unregister md5 driver
*/
void __exit ifxdeu_fini_md5 (void)
{
crypto_unregister_shash(&ifxdeu_md5_alg);
}

View file

@ -0,0 +1,386 @@
/******************************************************************************
**
** FILE NAME : ifxmips_md5_hmac.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for UEIP
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
** 21,March 2011 Mohammad Firdaus Changes for Kernel 2.6.32 and IPSec integration
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_md5_hmac.c
\ingroup IFX_DEU
\brief MD5-HMAC encryption deu driver file
*/
/*!
\defgroup IFX_MD5_HMAC_FUNCTIONS IFX_MD5_HMAC_FUNCTIONS
\ingroup IFX_DEU
\brief ifx md5-hmac driver functions
*/
/* Project Header files */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/crypto.h>
#include <linux/types.h>
#include <crypto/internal/hash.h>
#include <asm/byteorder.h>
#if defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Plaform Unknwon!"
#endif
#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
#define HASH_START IFX_HASH_CON
static spinlock_t lock;
#define CRTCL_SECT_INIT spin_lock_init(&lock)
#define CRTCL_SECT_START spin_lock_irqsave(&lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag)
//#define CRYPTO_DEBUG
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
#define MAX_HASH_KEYLEN 64
struct md5_hmac_ctx {
u8 key[MAX_HASH_KEYLEN];
u32 hash[MD5_HASH_WORDS];
u32 block[MD5_BLOCK_WORDS];
u64 byte_count;
u32 dbn;
unsigned int keylen;
};
static u32 temp[MD5_HMAC_DBN_TEMP_SIZE];
extern int disable_deudma;
/*! \fn static u32 endian_swap(u32 input)
* \ingroup IFX_MD5_HMAC_FUNCTIONS
* \brief perform dword level endian swap
* \param input value of dword that requires to be swapped
*/
static u32 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 IFX_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 = crypto_shash_ctx(desc->tfm);
memcpy(&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 IFX_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)
{
struct md5_hmac_ctx *mctx = crypto_shash_ctx(tfm);
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START;
//printk("copying keys to context with length %d\n", keylen);
if (keylen > MAX_HASH_KEYLEN) {
printk("Key length more than what DEU hash can handle\n");
return -EINVAL;
}
hash->KIDX |= 0x80000000; // reset all 16 words of the key to '0'
memcpy(&mctx->key, key, keylen);
mctx->keylen = keylen;
return 0;
}
/*! \fn int md5_hmac_setkey_hw(const u8 *key, unsigned int keylen)
* \ingroup IFX_MD5_HMAC_FUNCTIONS
* \brief sets md5 hmac key into the hardware registers
* \param key input key
* \param keylen key length greater than 64 bytes IS NOT SUPPORTED
*/
static int md5_hmac_setkey_hw(const u8 *key, unsigned int keylen)
{
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START;
unsigned long flag;
int i, j;
u32 *in_key = (u32 *)key;
//printk("\nsetkey keylen: %d\n key: ", keylen);
CRTCL_SECT_START;
j = 0;
for (i = 0; i < keylen; i+=4)
{
hash->KIDX = j;
asm("sync");
hash->KEY = *((u32 *) in_key + j);
asm("sync");
j++;
}
CRTCL_SECT_END;
return 0;
}
/*! \fn void md5_hmac_init(struct crypto_tfm *tfm)
* \ingroup IFX_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 = crypto_shash_ctx(desc->tfm);
mctx->dbn = 0; //dbn workaround
md5_hmac_setkey_hw(mctx->key, mctx->keylen);
return 0;
}
EXPORT_SYMBOL(md5_hmac_init);
/*! \fn void md5_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
* \ingroup IFX_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 = crypto_shash_ctx(desc->tfm);
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;
}
EXPORT_SYMBOL(md5_hmac_update);
/*! \fn void md5_hmac_final(struct crypto_tfm *tfm, u8 *out)
* \ingroup IFX_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 = crypto_shash_ctx(desc->tfm);
const unsigned int offset = mctx->byte_count & 0x3f;
char *p = (char *)mctx->block + offset;
int padding = 56 - (offset + 1);
volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START;
unsigned long flag;
int i = 0;
int dbn;
u32 *in = &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);
mctx->block[14] = endian_swap((mctx->byte_count + 64) << 3); // need to add 512 bit of the IPAD operation
mctx->block[15] = 0x00000000;
md5_hmac_transform(desc, mctx->block);
CRTCL_SECT_START;
//printk("\ndbn = %d\n", mctx->dbn);
hashs->DBN = mctx->dbn;
asm("sync");
*IFX_HASH_CON = 0x0703002D; //khs, go, init, ndc, endi, kyue, hmen, md5
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
for (dbn = 0; dbn < mctx->dbn; dbn++)
{
for (i = 0; i < 16; i++) {
hashs->MR = in[i];
};
hashs->controlr.GO = 1;
asm("sync");
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
in += 16;
}
#if 1
//wait for digest ready
while (! hashs->controlr.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;
/* reset the context after we finish with the hash */
mctx->byte_count = 0;
memset(&mctx->hash[0], 0, sizeof(MD5_HASH_WORDS));
memset(&mctx->block[0], 0, sizeof(MD5_BLOCK_WORDS));
memset(&temp[0], 0, MD5_HMAC_DBN_TEMP_SIZE);
CRTCL_SECT_END;
return 0;
}
EXPORT_SYMBOL(md5_hmac_final);
/*
* \brief MD5_HMAC function mappings
*/
static struct shash_alg ifxdeu_md5_hmac_alg = {
.digestsize = MD5_DIGEST_SIZE,
.init = md5_hmac_init,
.update = md5_hmac_update,
.final = md5_hmac_final,
.setkey = md5_hmac_setkey,
.descsize = sizeof(struct md5_hmac_ctx),
.base = {
.cra_name = "hmac(md5)",
.cra_driver_name= "ifxdeu-md5_hmac",
.cra_ctxsize = sizeof(struct md5_hmac_ctx),
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_module = THIS_MODULE,
}
};
/*! \fn int __init ifxdeu_init_md5_hmac (void)
* \ingroup IFX_MD5_HMAC_FUNCTIONS
* \brief initialize md5 hmac driver
*/
int __init ifxdeu_init_md5_hmac (void)
{
int ret = -ENOSYS;
if ((ret = crypto_register_shash(&ifxdeu_md5_hmac_alg)))
goto md5_hmac_err;
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU MD5_HMAC initialized%s.\n", disable_deudma ? "" : " (DMA)");
return ret;
md5_hmac_err:
printk(KERN_ERR "IFX DEU MD5_HMAC initialization failed!\n");
return ret;
}
/** \fn void __exit ifxdeu_fini_md5_hmac (void)
* \ingroup IFX_MD5_HMAC_FUNCTIONS
* \brief unregister md5 hmac driver
*/
void __exit ifxdeu_fini_md5_hmac (void)
{
crypto_unregister_shash(&ifxdeu_md5_hmac_alg);
}

View file

@ -0,0 +1,301 @@
/******************************************************************************
**
** FILE NAME : ifxmips_sha1.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for Danube
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_sha1.c
\ingroup IFX_DEU
\brief SHA1 encryption deu driver file
*/
/*!
\defgroup IFX_SHA1_FUNCTIONS IFX_SHA1_FUNCTIONS
\ingroup IFX_DEU
\brief ifx deu sha1 functions
*/
/* Project header */
#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 <crypto/internal/hash.h>
#include <linux/types.h>
#include <asm/scatterlist.h>
#include <asm/byteorder.h>
#if defined(CONFIG_DANUBE)
#include "ifxmips_deu_danube.h"
#elif defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Plaform Unknwon!"
#endif
#define SHA1_DIGEST_SIZE 20
#define SHA1_HMAC_BLOCK_SIZE 64
#define HASH_START IFX_HASH_CON
static spinlock_t lock;
#define CRTCL_SECT_INIT spin_lock_init(&lock)
#define CRTCL_SECT_START spin_lock_irqsave(&lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag)
//#define CRYPTO_DEBUG
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
/*
* \brief SHA1 private structure
*/
struct sha1_ctx {
int started;
u64 count;
u32 hash[5];
u32 state[5];
u8 buffer[64];
};
extern int disable_deudma;
/*! \fn static void sha1_transform (u32 *state, const u32 *in)
* \ingroup IFX_SHA1_FUNCTIONS
* \brief main interface to sha1 hardware
* \param state current state
* \param in 64-byte block of input
*/
static void sha1_transform (struct sha1_ctx *sctx, u32 *state, const u32 *in)
{
int i = 0;
volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START;
unsigned long flag;
CRTCL_SECT_START;
/* For context switching purposes, the previous hash output
* is loaded back into the output register
*/
if (sctx->started) {
hashs->D1R = *((u32 *) sctx->hash + 0);
hashs->D2R = *((u32 *) sctx->hash + 1);
hashs->D3R = *((u32 *) sctx->hash + 2);
hashs->D4R = *((u32 *) sctx->hash + 3);
hashs->D5R = *((u32 *) sctx->hash + 4);
}
for (i = 0; i < 16; i++) {
hashs->MR = in[i];
};
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
/* For context switching purposes, the output is saved into a
* context struct which can be used later on
*/
*((u32 *) sctx->hash + 0) = hashs->D1R;
*((u32 *) sctx->hash + 1) = hashs->D2R;
*((u32 *) sctx->hash + 2) = hashs->D3R;
*((u32 *) sctx->hash + 3) = hashs->D4R;
*((u32 *) sctx->hash + 4) = hashs->D5R;
sctx->started = 1;
CRTCL_SECT_END;
}
/*! \fn static void sha1_init(struct crypto_tfm *tfm)
* \ingroup IFX_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->started = 0;
sctx->count = 0;
return 0;
}
/*! \fn static void sha1_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
* \ingroup IFX_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, sctx->state, (const u32 *)sctx->buffer);
for (; i + 63 < len; i += 64) {
sha1_transform (sctx, 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 IFX_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_t *hashs = (struct deu_hash_t *) HASH_START;
unsigned long 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;
}
/*
* \brief SHA1 function mappings
*/
static struct shash_alg ifxdeu_sha1_alg = {
.digestsize = SHA1_DIGEST_SIZE,
.init = sha1_init,
.update = sha1_update,
.final = sha1_final,
.descsize = sizeof(struct sha1_ctx),
.statesize = sizeof(struct sha1_state),
.base = {
.cra_name = "sha1",
.cra_driver_name= "ifxdeu-sha1",
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
.cra_module = THIS_MODULE,
}
};
/*! \fn int __init ifxdeu_init_sha1 (void)
* \ingroup IFX_SHA1_FUNCTIONS
* \brief initialize sha1 driver
*/
int __init ifxdeu_init_sha1 (void)
{
int ret = -ENOSYS;
if ((ret = crypto_register_shash(&ifxdeu_sha1_alg)))
goto sha1_err;
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU SHA1 initialized%s.\n", disable_deudma ? "" : " (DMA)");
return ret;
sha1_err:
printk(KERN_ERR "IFX DEU SHA1 initialization failed!\n");
return ret;
}
/*! \fn void __exit ifxdeu_fini_sha1 (void)
* \ingroup IFX_SHA1_FUNCTIONS
* \brief unregister sha1 driver
*/
void __exit ifxdeu_fini_sha1 (void)
{
crypto_unregister_shash(&ifxdeu_sha1_alg);
}

View file

@ -0,0 +1,378 @@
/******************************************************************************
**
** FILE NAME : ifxmips_sha1_hmac.c
** PROJECT : IFX UEIP
** MODULES : DEU Module for UEIP
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
** 21,March 2011 Mohammad Firdaus Changes for Kernel 2.6.32 and IPSec integration
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver module
*/
/*!
\file ifxmips_sha1_hmac.c
\ingroup IFX_DEU
\brief SHA1-HMAC deu driver file
*/
/*!
\defgroup IFX_SHA1_HMAC_FUNCTIONS IFX_SHA1_HMAC_FUNCTIONS
\ingroup IFX_DEU
\brief ifx sha1 hmac functions
*/
/* Project header */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/crypto.h>
#include <linux/cryptohash.h>
#include <crypto/internal/hash.h>
#include <linux/types.h>
#include <asm/scatterlist.h>
#include <asm/byteorder.h>
#include <linux/delay.h>
#if defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Plaform Unknwon!"
#endif
#define SHA1_DIGEST_SIZE 20
#define SHA1_HMAC_BLOCK_SIZE 64
#define SHA1_HMAC_DBN_TEMP_SIZE 1024 // size in dword, needed for dbn workaround
#define HASH_START IFX_HASH_CON
#define SHA1_HMAC_MAX_KEYLEN 64
static spinlock_t lock;
#define CRTCL_SECT_INIT spin_lock_init(&lock)
#define CRTCL_SECT_START spin_lock_irqsave(&lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag)
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
struct sha1_hmac_ctx {
int keylen;
u8 buffer[SHA1_HMAC_BLOCK_SIZE];
u8 key[SHA1_HMAC_MAX_KEYLEN];
u32 state[5];
u32 dbn;
u64 count;
};
static u32 temp[SHA1_HMAC_DBN_TEMP_SIZE];
extern int disable_deudma;
/*! \fn static void sha1_hmac_transform(struct crypto_tfm *tfm, u32 const *in)
* \ingroup IFX_SHA1_HMAC_FUNCTIONS
* \brief save input block to context
* \param tfm linux crypto algo transform
* \param in 64-byte block of input
*/
static int sha1_hmac_transform(struct shash_desc *desc, u32 const *in)
{
struct sha1_hmac_ctx *sctx = crypto_shash_ctx(desc->tfm);
memcpy(&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");
}
return 0;
}
/*! \fn int sha1_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
* \ingroup IFX_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)
{
struct sha1_hmac_ctx *sctx = crypto_shash_ctx(tfm);
volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START;
if (keylen > SHA1_HMAC_MAX_KEYLEN) {
printk("Key length exceeds maximum key length\n");
return -EINVAL;
}
//printk("Setting keys of len: %d\n", keylen);
hashs->KIDX |= 0x80000000; //reset keys back to 0
memcpy(&sctx->key, key, keylen);
sctx->keylen = keylen;
return 0;
}
/*! \fn int sha1_hmac_setkey_hw(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
* \ingroup IFX_SHA1_HMAC_FUNCTIONS
* \brief sets sha1 hmac key into hw registers
* \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_hw(const u8 *key, unsigned int keylen)
{
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START;
int i, j;
unsigned long flag;
u32 *in_key = (u32 *)key;
j = 0;
CRTCL_SECT_START;
for (i = 0; i < keylen; i+=4)
{
hash->KIDX = j;
asm("sync");
hash->KEY = *((u32 *) in_key + j);
j++;
}
CRTCL_SECT_END;
return 0;
}
/*! \fn void sha1_hmac_init(struct crypto_tfm *tfm)
* \ingroup IFX_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 = crypto_shash_ctx(desc->tfm);
//printk("debug ln: %d, fn: %s\n", __LINE__, __func__);
sctx->dbn = 0; //dbn workaround
sha1_hmac_setkey_hw(sctx->key, sctx->keylen);
return 0;
}
/*! \fn static void sha1_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
* \ingroup IFX_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 = crypto_shash_ctx(desc->tfm);
unsigned int i, j;
j = (sctx->count >> 3) & 0x3f;
sctx->count += len << 3;
// printk("sctx->count = %d\n", sctx->count);
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 IFX_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);
struct sha1_hmac_ctx *sctx = crypto_shash_ctx(desc->tfm);
u32 index, padlen;
u64 t;
u8 bits[8] = { 0, };
static const u8 padding[64] = { 0x80, };
volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START;
unsigned long flag;
int i = 0;
int dbn;
u32 *in = &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
*IFX_HASH_CON = HASH_CON_VALUE;
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
for (dbn = 0; dbn < sctx->dbn; dbn++)
{
for (i = 0; i < 16; i++) {
hashs->MR = in[i];
};
hashs->controlr.GO = 1;
asm("sync");
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
in += 16;
}
#if 1
//wait for digest ready
while (! hashs->controlr.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;
memset(&sctx->buffer[0], 0, SHA1_HMAC_BLOCK_SIZE);
sctx->count = 0;
//printk("debug ln: %d, fn: %s\n", __LINE__, __func__);
CRTCL_SECT_END;
return 0;
}
/*
* \brief SHA1-HMAC function mappings
*/
static struct shash_alg ifxdeu_sha1_hmac_alg = {
.digestsize = SHA1_DIGEST_SIZE,
.init = sha1_hmac_init,
.update = sha1_hmac_update,
.final = sha1_hmac_final,
.setkey = sha1_hmac_setkey,
.descsize = sizeof(struct sha1_hmac_ctx),
.base = {
.cra_name = "hmac(sha1)",
.cra_driver_name= "ifxdeu-sha1_hmac",
.cra_ctxsize = sizeof(struct sha1_hmac_ctx),
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
.cra_module = THIS_MODULE,
}
};
/*! \fn int __init ifxdeu_init_sha1_hmac (void)
* \ingroup IFX_SHA1_HMAC_FUNCTIONS
* \brief initialize sha1 hmac driver
*/
int __init ifxdeu_init_sha1_hmac (void)
{
int ret = -ENOSYS;
if ((ret = crypto_register_shash(&ifxdeu_sha1_hmac_alg)))
goto sha1_err;
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU SHA1_HMAC initialized%s.\n", disable_deudma ? "" : " (DMA)");
return ret;
sha1_err:
printk(KERN_ERR "IFX DEU SHA1_HMAC initialization failed!\n");
return ret;
}
/*! \fn void __exit ifxdeu_fini_sha1_hmac (void)
* \ingroup IFX_SHA1_HMAC_FUNCTIONS
* \brief unregister sha1 hmac driver
*/
void __exit ifxdeu_fini_sha1_hmac (void)
{
crypto_unregister_shash(&ifxdeu_sha1_hmac_alg);
}

View file

@ -0,0 +1,92 @@
/*
* Quick & dirty crypto testing module.
*
* This will only exist until we have a better testing mechanism
* (e.g. a char device).
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
* Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
* Copyright (c) 2007 Nokia Siemens Networks
*
* 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.
*
*/
#ifndef _IFXMIPS_CRYPTO_TCRYPT_H
#define _IFXMIPS_CRYPTO_TCRYPT_H
struct cipher_speed_template {
const char *key;
unsigned int klen;
};
struct hash_speed {
unsigned int blen; /* buffer length */
unsigned int plen; /* per-update length */
};
/*
* DES test vectors.
*/
#define DES3_SPEED_VECTORS 1
#define CRYPTO_ALG_TYPE_SPEED_TEST 0xB
static int alg_speed_test(const char *alg, const char *driver,
unsigned int sec,
struct cipher_speed_template *t,
unsigned int tcount, u8 *keysize);
static struct cipher_speed_template des3_speed_template[] = {
{
.key = "\x01\x23\x45\x67\x89\xab\xcd\xef"
"\x55\x55\x55\x55\x55\x55\x55\x55"
"\xfe\xdc\xba\x98\x76\x54\x32\x10",
.klen = 24,
}
};
/*
* Cipher speed tests
*/
static u8 speed_template_8[] = {8, 0};
static u8 speed_template_24[] = {24, 0};
static u8 speed_template_8_32[] = {8, 32, 0};
static u8 speed_template_16_32[] = {16, 32, 0};
static u8 speed_template_16_24_32[] = {16, 24, 32, 0};
static u8 speed_template_32_40_48[] = {32, 40, 48, 0};
static u8 speed_template_32_48_64[] = {32, 48, 64, 0};
/*
* Digest speed tests
*/
static struct hash_speed generic_hash_speed_template[] = {
{ .blen = 16, .plen = 16, },
{ .blen = 64, .plen = 16, },
{ .blen = 64, .plen = 64, },
{ .blen = 256, .plen = 16, },
{ .blen = 256, .plen = 64, },
{ .blen = 256, .plen = 256, },
{ .blen = 1024, .plen = 16, },
{ .blen = 1024, .plen = 256, },
{ .blen = 1024, .plen = 1024, },
{ .blen = 2048, .plen = 16, },
{ .blen = 2048, .plen = 256, },
{ .blen = 2048, .plen = 1024, },
{ .blen = 2048, .plen = 2048, },
{ .blen = 4096, .plen = 16, },
{ .blen = 4096, .plen = 256, },
{ .blen = 4096, .plen = 1024, },
{ .blen = 4096, .plen = 4096, },
{ .blen = 8192, .plen = 16, },
{ .blen = 8192, .plen = 256, },
{ .blen = 8192, .plen = 1024, },
{ .blen = 8192, .plen = 4096, },
{ .blen = 8192, .plen = 8192, },
/* End marker */
{ .blen = 0, .plen = 0, }
};
#endif /* _CRYPTO_TCRYPT_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,141 @@
/*
* Cryptographic API.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
* Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
*
* 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.
*
*/
#ifndef _CRYPTO_INTERNAL_H
#define _CRYPTO_INTERNAL_H
#include <crypto/algapi.h>
#include <linux/completion.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/fips.h>
/* Crypto notification events. */
enum {
CRYPTO_MSG_ALG_REQUEST,
CRYPTO_MSG_ALG_REGISTER,
CRYPTO_MSG_ALG_UNREGISTER,
CRYPTO_MSG_TMPL_REGISTER,
CRYPTO_MSG_TMPL_UNREGISTER,
};
struct crypto_instance;
struct crypto_template;
struct crypto_larval {
struct crypto_alg alg;
struct crypto_alg *adult;
struct completion completion;
u32 mask;
};
extern struct list_head crypto_alg_list;
extern struct rw_semaphore crypto_alg_sem;
extern struct blocking_notifier_head crypto_chain;
#ifdef CONFIG_PROC_FS
void __init crypto_init_proc(void);
void __exit crypto_exit_proc(void);
#else
static inline void crypto_init_proc(void)
{ }
static inline void crypto_exit_proc(void)
{ }
#endif
static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg)
{
return alg->cra_ctxsize;
}
static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg)
{
return alg->cra_ctxsize;
}
struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask);
struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
int crypto_init_cipher_ops(struct crypto_tfm *tfm);
int crypto_init_compress_ops(struct crypto_tfm *tfm);
void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
void crypto_exit_compress_ops(struct crypto_tfm *tfm);
struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask);
void crypto_larval_kill(struct crypto_alg *alg);
struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask);
void crypto_larval_error(const char *name, u32 type, u32 mask);
void crypto_alg_tested(const char *name, int err);
void crypto_shoot_alg(struct crypto_alg *alg);
struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
u32 mask);
void *crypto_create_tfm(struct crypto_alg *alg,
const struct crypto_type *frontend);
struct crypto_alg *crypto_find_alg(const char *alg_name,
const struct crypto_type *frontend,
u32 type, u32 mask);
void *crypto_alloc_tfm(const char *alg_name,
const struct crypto_type *frontend, u32 type, u32 mask);
int crypto_register_notifier(struct notifier_block *nb);
int crypto_unregister_notifier(struct notifier_block *nb);
int crypto_probing_notify(unsigned long val, void *v);
static inline void crypto_alg_put(struct crypto_alg *alg)
{
if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
alg->cra_destroy(alg);
}
static inline int crypto_tmpl_get(struct crypto_template *tmpl)
{
return try_module_get(tmpl->module);
}
static inline void crypto_tmpl_put(struct crypto_template *tmpl)
{
module_put(tmpl->module);
}
static inline int crypto_is_larval(struct crypto_alg *alg)
{
return alg->cra_flags & CRYPTO_ALG_LARVAL;
}
static inline int crypto_is_dead(struct crypto_alg *alg)
{
return alg->cra_flags & CRYPTO_ALG_DEAD;
}
static inline int crypto_is_moribund(struct crypto_alg *alg)
{
return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING);
}
static inline void crypto_notify(unsigned long val, void *v)
{
blocking_notifier_call_chain(&crypto_chain, val, v);
}
#endif /* _CRYPTO_INTERNAL_H */

File diff suppressed because it is too large Load diff