refresh 2.6.33 patches, add more mach support, add crypto support, tbd. mach/board detection

SVN-Revision: 21159
This commit is contained in:
Ralph Hempel 2010-04-25 16:20:16 +00:00
parent e226157e65
commit 1aea70229e
26 changed files with 5058 additions and 12 deletions

View file

@ -13,8 +13,8 @@ FEATURES:=squashfs jffs2 atm
SUBTARGETS:=danube #ar9
#LINUX_VERSION:=2.6.30.10
LINUX_VERSION:=2.6.32.10
#LINUX_VERSION:=2.6.33.2
#LINUX_VERSION:=2.6.32.10
LINUX_VERSION:=2.6.33.2
CFLAGS=-Os -pipe -mips32r2 -mtune=mips32r2 -funit-at-a-time

View file

@ -98,12 +98,15 @@ CONFIG_HZ=250
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
CONFIG_IFXMIPS=y
# CONFIG_IFXMIPS_AR9 is not set
CONFIG_IFXMIPS_ARCAYDIAN_BRNBOOT=y
# CONFIG_IFXMIPS_ASE is not set
CONFIG_IFXMIPS_COMPAT=y
CONFIG_IFXMIPS_DANUBE=y
CONFIG_IFXMIPS_MII0=y
# CONFIG_IFXMIPS_PROM_ASC0 is not set
CONFIG_IFXMIPS_PROM_ASC1=y
# CONFIG_IFXMIPS_VR9 is not set
CONFIG_IFXMIPS_WDT=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_INLINE_READ_LOCK is not set
@ -135,13 +138,12 @@ CONFIG_INLINE_WRITE_UNLOCK=y
CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
CONFIG_IRQ_CPU=y
# CONFIG_ISDN_CAPI is not set
# CONFIG_ISDN_DRV_GIGASET is not set
# CONFIG_ISDN_I4L is not set
CONFIG_KALLSYMS=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_IFXMIPS=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_LZMA_COMPRESS=y
CONFIG_LZMA_DECOMPRESS=y
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set

View file

@ -10,6 +10,18 @@ choice
bool "Danube/Twinpass"
select SOC_DANUBE
config IFXMIPS_ASE
bool "Amazon-SE"
select SOC_ASE
config IFXMIPS_AR9
bool "AR9"
select SOC_AR9
config IFXMIPS_VR9
bool "VR9"
select SOC_VR9
endchoice
source "arch/mips/ifxmips/danube/Kconfig"
@ -32,6 +44,60 @@ config SOC_DANUBE
select SWAP_IO_SPACE
select MIPS_MACHINE
config SOC_ASE
bool
select DMA_NONCOHERENT
select IRQ_CPU
select CEVT_R4K
select CSRC_R4K
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
select HAVE_STD_PC_SERIAL_PORT
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_MULTITHREADING
select SYS_HAS_EARLY_PRINTK
select HW_HAS_PCI
select ARCH_REQUIRE_GPIOLIB
select SWAP_IO_SPACE
select MIPS_MACHINE
config SOC_AR9
bool
select DMA_NONCOHERENT
select IRQ_CPU
select CEVT_R4K
select CSRC_R4K
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
select HAVE_STD_PC_SERIAL_PORT
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_MULTITHREADING
select SYS_HAS_EARLY_PRINTK
select HW_HAS_PCI
select ARCH_REQUIRE_GPIOLIB
select SWAP_IO_SPACE
select MIPS_MACHINE
config SOC_VR9
bool
select DMA_NONCOHERENT
select IRQ_CPU
select CEVT_R4K
select CSRC_R4K
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
select HAVE_STD_PC_SERIAL_PORT
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_MULTITHREADING
select SYS_HAS_EARLY_PRINTK
select HW_HAS_PCI
select ARCH_REQUIRE_GPIOLIB
select SWAP_IO_SPACE
select MIPS_MACHINE
if EARLY_PRINTK
menu "Infineon SoC settings"

View file

@ -4,6 +4,7 @@
#include <linux/etherdevice.h>
#include <asm/bootinfo.h>
#include <machine.h>
#include <ifxmips.h>
#include <ifxmips_prom.h>
@ -65,8 +66,12 @@ out:
}
__setup("ethaddr", ifxmips_set_ethaddr);
void __init
prom_init(void)
static void __init prom_detect_machtype(void)
{
mips_machtype = IFXMIPS_MACH_EASY50712;
}
static void __init prom_init_cmdline(void)
{
int argc = fw_arg0;
char **argv = (char **) fw_arg1;
@ -129,3 +134,10 @@ prom_init(void)
add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
}
void __init
prom_init(void)
{
prom_detect_machtype();
prom_init_cmdline();
}

View file

@ -1,3 +1,5 @@
obj-y := dma-core.o irq.o ebu.o setup.o devices.o cgu.o
obj-$(CONFIG_IFXMIPS_ARCAYDIAN_BRNBOOT) += arcaydian.o
obj-$(CONFIG_DANUBE_MACH_ARV452) += mach-arv452.o
obj-$(CONFIG_DANUBE_MACH_EASY50712) += mach-easy50712.o
obj-$(CONFIG_DANUBE_MACH_EASY4010) += mach-easy4010.o

View file

@ -75,7 +75,7 @@ static struct resource danube_ethernet_resources =
static struct platform_device danube_ethernet =
{
.name = "danube_ethernet",
.name = "ifxmips_mii0",
.resource = &danube_ethernet_resources,
.num_resources = 1,
.dev = {

View file

@ -167,4 +167,4 @@ arv452_init(void)
MIPS_MACHINE(IFXMIPS_MACH_ARV452,
"ARV452",
"Airties WAV-281, Arcor A800",
arv452_init);
arv452_init);

View file

@ -0,0 +1,79 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/gpio.h>
#include <linux/gpio_buttons.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <machine.h>
#include <ifxmips_prom.h>
#include "devices.h"
extern unsigned char ifxmips_ethaddr[6];
#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition easy4010_partitions[] =
{
{
.name = "uboot",
.offset = 0x0,
.size = 0x40000,
},
{
.name = "uboot_env",
.offset = 0x40000,
.size = 0x10000,
},
{
.name = "kernel",
.offset = 0x0,
.size = 0x0,
},
{
.name = "rootfs",
.offset = 0x0,
.size = 0x0,
}
};
#endif
static struct physmap_flash_data easy4010_flash_data = {
#ifdef CONFIG_MTD_PARTITIONS
.nr_parts = ARRAY_SIZE(easy4010_partitions),
.parts = easy4010_partitions,
#endif
};
static struct gpio_led easy4010_leds[] = {
{ .name = "ifx:green:test0", .gpio = 0,},
{ .name = "ifx:green:test1", .gpio = 1,},
{ .name = "ifx:green:test2", .gpio = 2,},
{ .name = "ifx:green:test3", .gpio = 3,},
};
static void __init
easy4010_init(void)
{
ifxmips_register_gpio();
ifxmips_register_gpio_dev();
ifxmips_register_mtd(&easy4010_flash_data);
ifxmips_register_leds(easy4010_leds, ARRAY_SIZE(easy4010_leds));
ifxmips_register_wdt();
danube_register_ethernet(ifxmips_ethaddr);
danube_register_usb();
}
MIPS_MACHINE(IFXMIPS_MACH_EASY4010,
"EASY4010",
"Lantiq Twinpass Eval Board",
easy4010_init);

View file

@ -0,0 +1,80 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/gpio.h>
#include <linux/gpio_buttons.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <machine.h>
#include <ifxmips_prom.h>
#include "devices.h"
extern unsigned char ifxmips_ethaddr[6];
#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition easy50712_partitions[] =
{
{
.name = "uboot",
.offset = 0x0,
.size = 0x40000,
},
{
.name = "uboot_env",
.offset = 0x40000,
.size = 0x10000,
},
{
.name = "kernel",
.offset = 0x0,
.size = 0x0,
},
{
.name = "rootfs",
.offset = 0x0,
.size = 0x0,
}
};
#endif
static struct physmap_flash_data easy50712_flash_data = {
#ifdef CONFIG_MTD_PARTITIONS
.nr_parts = ARRAY_SIZE(easy50712_partitions),
.parts = easy50712_partitions,
#endif
};
static struct gpio_led easy50712_leds[] = {
{ .name = "ifx:green:test0", .gpio = 0,},
{ .name = "ifx:green:test1", .gpio = 1,},
{ .name = "ifx:green:test2", .gpio = 2,},
{ .name = "ifx:green:test3", .gpio = 3,},
};
static void __init
easy50712_init(void)
{
ifxmips_register_gpio();
//printk("ifxmips_register_gpio_dev\n");
//ifxmips_register_gpio_dev();
ifxmips_register_mtd(&easy50712_flash_data);
ifxmips_register_leds(easy50712_leds, ARRAY_SIZE(easy50712_leds));
ifxmips_register_wdt();
danube_register_ethernet(ifxmips_ethaddr);
danube_register_usb();
}
MIPS_MACHINE(IFXMIPS_MACH_EASY50712,
"EASY50712",
"Lantiq Eval Board",
easy50712_init);

View file

@ -1,11 +1,21 @@
#include <asm/mips_machine.h>
enum ramips_mach_type {
enum ifxmips_mach_type {
IFXMIPS_MACH_GENERIC,
/* Danube based machines */
IFXMIPS_MACH_EASY50712, /* danube evalkit */
/* Danube/Twinpass based machines */
IFXMIPS_MACH_EASY50712, /* Danube evalkit */
IFXMIPS_MACH_EASY4010, /* Twinpass evalkit */
IFXMIPS_MACH_ARV4519, /* Airties WAV-221 */
IFXMIPS_MACH_ARV452, /* Airties WAV-281, Arcor EasyboxA800 */
/* ASE based machines */
IFXMIPS_MACH_EASY50601, /* ASE wave board */
/* AR9 based machines */
IFXMIPS_MACH_EASY50822, /* AR9 eval board */
/* VR9 based machines */
IFXMIPS_MACH_EASY80920, /* VRX200 eval board */
};

View file

@ -0,0 +1,9 @@
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS) += ifxmips_deu.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS) += ifxmips_deu_danube.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS_DES) += ifxmips_des.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS_AES) += ifxmips_aes.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS_ARC4) += ifxmips_arc4.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS_SHA1) += ifxmips_sha1.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS_SHA1_HMAC) += ifxmips_sha1_hmac.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS_MD5) += ifxmips_mda5.o
obj-$(CONFIG_CRYPTO_DEV_IFXMIPS_MDA5_HMAC) += ifxmips_mda5_hmac.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,388 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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>
#include "ifxmips_deu.h"
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
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
/*
* \brief arc4 private structure
*/
struct arc4_ctx {
int key_length;
u8 buf[120];
};
extern int disable_deudma;
/*! \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 AES hardware
\param ctx_arg crypto algo context
\param out_arg output bytestream
\param in_arg input bytestream
\param iv_arg initialization vector
\param nbytes length of bytestream
\param encdec 1 for encrypt; 0 for decrypt
\param mode operation mode such as ebc, cbc, ctr
*/
static void _deu_arc4 (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode)
{
volatile struct arc4_t *arc4 = (struct arc4_t *) ARC4_START;
int i = 0;
ulong flag;
#if 1 // need to handle nbytes not multiple of 16
volatile u32 tmp_array32[4];
volatile u8 *tmp_ptr8;
int remaining_bytes, j;
#endif
CRTCL_SECT_START;
arc4->IDLEN = nbytes;
#if 1
while (i < nbytes) {
arc4->ID3R = *((u32 *) in_arg + (i>>2) + 0);
arc4->ID2R = *((u32 *) in_arg + (i>>2) + 1);
arc4->ID1R = *((u32 *) in_arg + (i>>2) + 2);
arc4->ID0R = *((u32 *) in_arg + (i>>2) + 3);
arc4->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
//#ifndef CONFIG_CRYPTO_DEV_VR9_DMA
*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);
#else //dma
*AMAZONS_ARC4_CON = ( (1<<31) | ((key_len - 1)<<27) | (1<<26) | (3<<16) | (1<<4) );
//NDC=1,ENDI=1,GO=0,KSAE=1,SM=1
arc4->K3R = *((u32 *) in_key + 0);
arc4->K2R = *((u32 *) in_key + 1);
arc4->K1R = *((u32 *) in_key + 2);
arc4->K0R = *((u32 *) in_key + 3);
#if 0
arc4->K3R = endian_swap(*((u32 *) in_key + 0));
arc4->K2R = endian_swap(*((u32 *) in_key + 1));
arc4->K1R = endian_swap(*((u32 *) in_key + 2));
arc4->K0R = endian_swap(*((u32 *) in_key + 3));
#endif
#endif
#if 0 // arc4 is a ugly state machine, KSAE can only be set once per session
ctx->key_length = key_len;
memcpy ((u8 *) (ctx->buf), in_key, key_len);
#endif
return 0;
}
/*! \fn static void _deu_arc4_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
\ingroup 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, CRYPTO_TFM_MODE_ECB);
}
/*
* \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;
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.\n", 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);
}
#endif

View file

@ -0,0 +1,59 @@
#ifndef IFXMIPS_ARC4_H
#define IFXMIPS_ARC4_H
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx deu driver file
*/
/*!
\defgroup IFX_DEU_DEFINITIONS IFX_DEU_DRIVERS
\ingroup IFX_DEU
\brief ifx deu definitions
*/
/*!
\file ifxmips_arc4.h
\brief ARC4 DEU header driver file
*/
#define ARC4_START IFX_ARC4_CON
#ifdef CONFIG_CRYPTO_DEV_ARC4_AR9
#include "ifxmips_deu_structs_ar9.h"
#endif
#ifdef CONFIG_CRYPTO_DEV_DMA_AR9
#include "ifxmips_deu_structs_ar9.h"
#endif
#ifdef CONFIG_CRYPTO_DEV_ARC4_VR9
#include "ifxmips_deu_structs_vr9.h"
#endif
#ifdef CONFIG_CRYPTO_DEV_DMA_VR9
#include "ifxmips_deu_structs_vr9.h"
#include <asm/ifx/irq.h>
#endif
#endif /* IFXMIPS_ARC4_H */

View file

@ -0,0 +1,893 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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"
/* DMA specific header and variables */
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
#include "ifxmips_deu_dma.h"
#include <asm/ifx/irq.h>
#include <asm/ifx/ifx_dma_core.h>
extern _ifx_deu_device ifx_deu[1];
extern u32 *des_buff_in;
extern u32 *des_buff_out;
#ifndef CONFIG_CRYPTO_DEV_IFXMIPS_POLL_DMA
#define CONFIG_CRYPTO_DEV_IFXMIPS_POLL_DMA
#endif /* CONFIG_CRYPTO_DEV_IFXMIPS_POLL_DMA */
#endif /* CONFIG_CRYPTO_DEV_IFXMIPS_DMA */
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 declarations */
#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);
#ifndef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
void ifx_deu_des (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode);
#else
void ifx_deu_des_core (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode);
#endif /* CONFIG_CRYPTO_DEV_IFXMIPS_DMA */
struct des_ctx {
int controlr_M;
int key_length;
u8 iv[DES_BLOCK_SIZE];
u32 expkey[DES3_EDE_EXPKEY_WORDS];
};
extern int disable_deudma;
/*! \fn int des_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
* \ingroup IFX_DES_FUNCTIONS
* \brief sets DES key
* \param tfm linux crypto algo transform
* \param key input key
* \param key_len key length
*/
int des_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int key_len)
{
struct des_ctx *ctx = crypto_tfm_ctx(tfm);
DPRINTF(0, "ctx @%p, key_len %d %d\n", ctx, key_len);
ctx->controlr_M = 0; /* des */
ctx->key_length = key_len;
memcpy ((u8 *) (ctx->expkey), key, key_len);
return 0;
}
#ifndef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
/*! \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)
#else
/*! \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
*/
void ifx_deu_des_core (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode)
#endif
{
volatile struct des_t *des = (struct des_t *) DES_3DES_START;
struct des_ctx *dctx = ctx_arg;
u32 *key = dctx->expkey;
ulong flag;
#ifndef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
int i = 0;
int nblocks = 0;
#else
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON;
struct dma_device_info *dma_device = ifx_deu[0].dma_device;
//deu_drv_priv_t *deu_priv = (deu_drv_priv_t *)dma_device->priv;
int wlen = 0;
u32 *outcopy = NULL;
u32 *dword_mem_aligned_in = NULL;
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_POLL_DMA
u32 timeout = 0;
u32 *out_dma = NULL;
#endif
#endif
DPRINTF(0, "ctx @%p, mode %d, encdec %d\n", dctx, mode, encdec);
CRTCL_SECT_START;
des->controlr.E_D = !encdec; /* encryption */
des->controlr.O = mode; /* 0 ECB, 1 CBC, 2 OFB, 3 CFB, 4 CTR */
des->controlr.SM = 1; /* start after writing input register */
des->controlr.DAU = 0; /* Disable Automatic Update of init vector */
des->controlr.ARS = 1; /* Autostart Select - write to IHR */
des->controlr.M = dctx->controlr_M;
/* write keys */
if (dctx->controlr_M == 0) {
/* DES mode */
des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0));
des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1));
#ifdef CRYPTO_DEBUG
printk ("key1: %x\n", (*((u32 *) key + 0)));
printk ("key2: %x\n", (*((u32 *) key + 1)));
#endif
} else {
/* 3DES mode (EDE-x) */
switch (dctx->key_length) {
case 24:
des->K3HR = DEU_ENDIAN_SWAP(*((u32 *) key + 4));
des->K3LR = DEU_ENDIAN_SWAP(*((u32 *) key + 5));
/* no break; */
case 16:
des->K2HR = DEU_ENDIAN_SWAP(*((u32 *) key + 2));
des->K2LR = DEU_ENDIAN_SWAP(*((u32 *) key + 3));
/* no break; */
case 8:
des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0));
des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1));
break;
default:
CRTCL_SECT_END;
return;
}
}
/* write init vector (not required for ECB mode) */
if (mode > 0) {
des->IVHR = DEU_ENDIAN_SWAP(*(u32 *) iv_arg);
des->IVLR = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 1));
}
#ifndef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
nblocks = nbytes / 4;
for (i = 0; i < nblocks; i += 2) {
/* wait for busy bit to clear */
/*--- Workaround ----------------------------------------------------
do a dummy read to the busy flag because it is not raised early
enough in CFB/OFB 3DES modes */
#ifdef CRYPTO_DEBUG
printk ("ihr: %x\n", (*((u32 *) in_arg + i)));
printk ("ilr: %x\n", (*((u32 *) in_arg + 1 + i)));
#endif
des->IHR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + i));
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;
#ifdef CRYPTO_DEBUG
printk ("ohr: %x\n", (*((u32 *) out_arg + i)));
printk ("olr: %x\n", (*((u32 *) out_arg + 1 + i)));
#endif
}
#else /* dma mode */
/* Prepare Rx buf length used in dma psuedo interrupt */
//deu_priv->deu_rx_buf = out_arg;
//deu_priv->deu_rx_len = nbytes;
/* memory alignment issue */
dword_mem_aligned_in = (u32 *) DEU_DWORD_REORDERING(in_arg, des_buff_in, BUFFER_IN, nbytes);
dma->controlr.ALGO = 0; //DES
des->controlr.DAU = 0;
dma->controlr.BS = 0;
dma->controlr.EN = 1;
while (des->controlr.BUS) {
// wait for AES to be ready
};
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;
}
WAIT_DES_DMA_READY();
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_POLL_DMA
outcopy = (u32 *) DEU_DWORD_REORDERING(out_arg, des_buff_out, BUFFER_OUT, nbytes);
// polling DMA rx channel
while ((dma_device_read (dma_device, (u8 **) &out_dma, NULL)) == 0) {
timeout++;
if (timeout >= 333000) {
dma->controlr.EN = 0;
CRTCL_SECT_END;
printk (KERN_ERR "[%s %s %d]: timeout!!\n", __FILE__, __func__, __LINE__);
return; // -EINVAL;
}
}
WAIT_DES_DMA_READY();
DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes);
#else
CRTCL_SECT_END; /* Sleep and wait for Rx finished */
DEU_WAIT_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, deu_priv->deu_event_flags);
CRTCL_SECT_START;
#endif
#endif /* dma mode */
if (mode > 0) {
*(u32 *) iv_arg = DEU_ENDIAN_SWAP(des->IVHR);
*((u32 *) iv_arg + 1) = DEU_ENDIAN_SWAP(des->IVLR);
};
CRTCL_SECT_END;
}
//definitions from linux/include/crypto.h:
//#define CRYPTO_TFM_MODE_ECB 0x00000001
//#define CRYPTO_TFM_MODE_CBC 0x00000002
//#define CRYPTO_TFM_MODE_CFB 0x00000004
//#define CRYPTO_TFM_MODE_CTR 0x00000008
//#define CRYPTO_TFM_MODE_OFB 0x00000010 // 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
*/
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
void ifx_deu_des (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, u32 nbytes, int encdec, int mode)
{
u32 remain = nbytes;
u32 inc;
DPRINTF(0, "\n");
while (remain > 0)
{
if (remain >= DEU_MAX_PACKET_SIZE)
{
inc = DEU_MAX_PACKET_SIZE;
}
else
{
inc = remain;
}
remain -= inc;
ifx_deu_des_core(ctx_arg, out_arg, in_arg, iv_arg, inc, encdec, mode);
out_arg += inc;
in_arg += inc;
}
}
#endif
/*! \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)
{
DPRINTF(0, "ctx @%p\n", ctx);
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)
{
DPRINTF(0, "ctx @%p\n", ctx);
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)
{
DPRINTF(0, "ctx @%p\n", ctx);
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)
{
DPRINTF(0, "ctx @%p\n", ctx);
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)
{
DPRINTF(0, "ctx @%p\n", ctx);
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);
DPRINTF(0, "ctx @%p\n", ctx);
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);
DPRINTF(0, "ctx @%p\n", ctx);
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 key_len)
{
struct des_ctx *ctx = crypto_tfm_ctx(tfm);
DPRINTF(0, "ctx @%p, key_len %d\n", ctx, key_len);
ctx->controlr_M = key_len / 8 + 1; // 3DES EDE1 / EDE2 / EDE3 Mode
ctx->key_length = key_len;
memcpy ((u8 *) (ctx->expkey), key, key_len);
return 0;
}
/*
* \brief DES function mappings
*/
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;
DPRINTF(0, "ctx @%p\n", ctx);
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
nbytes -= (nbytes % DES_BLOCK_SIZE);
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(0, "ctx @%p\n", ctx);
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
nbytes -= (nbytes % DES_BLOCK_SIZE);
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(0, "ctx @%p\n", ctx);
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
u8 *iv = walk.iv;
//printk("iv = %08x\n", *(u32 *)iv);
nbytes -= (nbytes % DES_BLOCK_SIZE);
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(0, "ctx @%p\n", ctx);
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = walk.nbytes)) {
u8 *iv = walk.iv;
//printk("iv = %08x\n", *(u32 *)iv);
nbytes -= (nbytes % DES_BLOCK_SIZE);
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 = 0;
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;
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
if (ALLOCATE_MEMORY(BUFFER_IN, DES_ALGO) < 0) {
printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", __FILE__, __func__, __LINE__);
goto cbc_des3_ede_err;
}
if (ALLOCATE_MEMORY(BUFFER_OUT, DES_ALGO) < 0) {
printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", __FILE__, __func__, __LINE__);
goto cbc_des3_ede_err;
}
#endif
printk (KERN_NOTICE "IFX DEU DES initialized %s.\n", 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);
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
FREE_MEMORY(des_buff_in);
FREE_MEMORY(des_buff_out);
#endif /* CONFIG_CRYPTO_DEV_IFXMIPS_DMA_DANUBE */
}

View file

@ -0,0 +1,190 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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/fs.h> /* Stuff about file systems that we need */
#include <asm/byteorder.h>
#include <ifxmips_pmu.h>
#include "ifxmips_deu.h"
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
int disable_deudma = 0;
#else
int disable_deudma = 1;
#endif /* CONFIG_CRYPTO_DEV_IFXMIPS_DMA */
#ifdef CRYPTO_DEBUG
char deu_debug_level = 3;
#endif
/*! \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 __init deu_init (void)
{
int ret = -ENOSYS;
u32 config;
volatile struct clc_controlr_t *clc = (struct clc_controlr_t *) IFX_DEU_CLK;
ifxmips_pmu_enable(1<<20);
printk(KERN_INFO "Lantiq crypto hardware driver version %s\n", IFX_DEU_DRV_VERSION);
chip_version();
clc->FSOE = 0;
clc->SBWE = 0;
clc->SPEN = 0;
clc->SBWE = 0;
clc->DISS = 0;
clc->DISR = 0;
config = *IFX_DEU_ID;
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
deu_dma_init ();
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_DES)
if(config & IFX_DEU_ID_DES) {
if ((ret = ifxdeu_init_des ())) {
printk (KERN_ERR "IFX DES initialization failed!\n");
}
} else {
printk (KERN_ERR "IFX DES not supported!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_AES)
if(config & IFX_DEU_ID_AES) {
if ((ret = ifxdeu_init_aes ())) {
printk (KERN_ERR "IFX AES initialization failed!\n");
}
} else {
printk (KERN_ERR "IFX AES not supported!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_ARC4)
if ((ret = ifxdeu_init_arc4 ())) {
printk (KERN_ERR "IFX ARC4 initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_SHA1)
if(config & IFX_DEU_ID_HASH) {
if ((ret = ifxdeu_init_sha1 ())) {
printk (KERN_ERR "IFX SHA1 initialization failed!\n");
}
} else {
printk (KERN_ERR "IFX SHA1 not supported!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_MD5)
if(config & IFX_DEU_ID_HASH) {
if ((ret = ifxdeu_init_md5 ())) {
printk (KERN_ERR "IFX MD5 initialization failed!\n");
}
} else {
printk (KERN_ERR "IFX MD5 not supported!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_SHA1_HMAC)
if ((ret = ifxdeu_init_sha1_hmac ())) {
printk (KERN_ERR "IFX SHA1_HMAC initialization failed!\n");
}
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_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 void __exit deu_fini (void)
{
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_DES)
ifxdeu_fini_des ();
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_AES)
ifxdeu_fini_aes ();
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_ARC4)
ifxdeu_fini_arc4 ();
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_SHA1)
ifxdeu_fini_sha1 ();
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_MD5)
ifxdeu_fini_md5 ();
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_SHA1_HMAC)
ifxdeu_fini_sha1_hmac ();
#endif
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_MD5_HMAC)
ifxdeu_fini_md5_hmac ();
#endif
printk("DEU has exited successfully\n");
#if defined(CONFIG_CRYPTO_DEV_IFXMIPS_DMA)
ifxdeu_fini_dma();
printk("DMA has deregistered successfully\n");
#endif
}
module_init (deu_init);
module_exit (deu_fini);
MODULE_DESCRIPTION ("Infineon crypto engine support.");
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("Mohammad Firdaus");

View file

@ -0,0 +1,144 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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
#define IFX_DEU_DRV_VERSION "1.0.1"
#include "ifxmips_deu_danube.h"
#define IFXDEU_ALIGNMENT 16
#define PFX "ifxdeu: "
#define IFXDEU_CRA_PRIORITY 300
#define IFXDEU_COMPOSITE_PRIORITY 400
#define IFX_DEU_BASE_ADDR (KSEG1 | 0x1E103100)
#define IFX_DEU_CLK ((volatile u32 *)(IFX_DEU_BASE_ADDR + 0x0000))
#define IFX_DEU_ID ((volatile u32 *)(IFX_DEU_BASE_ADDR + 0x0008))
#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 IFX_DEU_ID_REV 0x00001F
#define IFX_DEU_ID_ID 0x00FF00
#define IFX_DEU_ID_DMA 0x010000
#define IFX_DEU_ID_HASH 0x020000
#define IFX_DEU_ID_AES 0x040000
#define IFX_DEU_ID_3DES 0x080000
#define IFX_DEU_ID_DES 0x100000
#define CRYPTO_DIR_ENCRYPT 1
#define CRYPTO_DIR_DECRYPT 0
#undef CRYPTO_DEBUG
#ifdef CRYPTO_DEBUG
extern char deu_debug_level;
#define DPRINTF(level, format, args...) if (level < deu_debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif
#define IFX_MPS (KSEG1 | 0x1F107000)
#define IFX_MPS_CHIPID ((volatile u32*)(IFX_MPS + 0x0344))
#define IFX_MPS_CHIPID_VERSION_GET(value) (((value) >> 28) & 0xF)
#define IFX_MPS_CHIPID_VERSION_SET(value) (((value) & 0xF) << 28)
#define IFX_MPS_CHIPID_PARTNUM_GET(value) (((value) >> 12) & 0xFFFF)
#define IFX_MPS_CHIPID_PARTNUM_SET(value) (((value) & 0xFFFF) << 12)
#define IFX_MPS_CHIPID_MANID_GET(value) (((value) >> 1) & 0x7FF)
#define IFX_MPS_CHIPID_MANID_SET(value) (((value) & 0x7FF) << 1)
void chip_version(void);
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);
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);
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
volatile long deu_event_flags;
u8 *deu_rx_buf;
u32 deu_rx_len;
}deu_drv_priv_t;
#endif /* IFXMIPS_DEU_H */

View file

@ -0,0 +1,443 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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.h"
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
u32 *des_buff_in = NULL;
u32 *des_buff_out = NULL;
u32 *aes_buff_in = NULL;
u32 *aes_buff_out = NULL;
_ifx_deu_device ifx_deu[1];
#endif
/* 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 __exit ifxdeu_fini_dma(void);
#define DES_3DES_START IFX_DES_CON
#define AES_START IFX_AES_CON
/* Variables definition */
int ifx_danube_pre_1_4;
u8 *g_dma_page_ptr = NULL;
u8 *g_dma_block = NULL;
u8 *g_dma_block2 = NULL;
/*! \fn int deu_dma_init (void)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief Initialize DMA for DEU usage. DMA specific registers are
* intialized here, including a pointer to the device, memory
* space for the device and DEU-DMA descriptors
* \return -1 if fail, otherwise return 0
*/
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
int deu_dma_init (void)
{
struct dma_device_info *dma_device = NULL;
int i = 0;
volatile struct deu_dma_t *dma = (struct deu_dma_t *) IFX_DEU_DMA_CON;
struct dma_device_info *deu_dma_device_ptr;
// get one free page and share between g_dma_block and g_dma_block2
printk("PAGE_SIZE = %ld\n", PAGE_SIZE);
g_dma_page_ptr = (u8 *)__get_free_page(GFP_KERNEL); // need 16-byte alignment memory block
g_dma_block = g_dma_page_ptr; // need 16-byte alignment memory block
g_dma_block2 = (u8 *)(g_dma_page_ptr + (PAGE_SIZE >> 1)); // need 16-byte alignment memory block
deu_dma_device_ptr = dma_device_reserve ("DEU");
if (!deu_dma_device_ptr) {
printk ("DEU: reserve DMA fail!\n");
return -1;
}
ifx_deu[0].dma_device = deu_dma_device_ptr;
dma_device = deu_dma_device_ptr;
//dma_device->priv = &deu_dma_priv;
dma_device->buffer_alloc = &deu_dma_buffer_alloc;
dma_device->buffer_free = &deu_dma_buffer_free;
dma_device->intr_handler = &deu_dma_intr_handler;
dma_device->tx_endianness_mode = IFX_DMA_ENDIAN_TYPE3;
dma_device->rx_endianness_mode = IFX_DMA_ENDIAN_TYPE3;
dma_device->port_num = 1;
dma_device->tx_burst_len = 4;
dma_device->max_rx_chan_num = 1;
dma_device->max_tx_chan_num = 1;
dma_device->port_packet_drop_enable = 0;
for (i = 0; i < dma_device->max_rx_chan_num; i++) {
dma_device->rx_chan[i]->packet_size = DEU_MAX_PACKET_SIZE;
dma_device->rx_chan[i]->desc_len = 1;
dma_device->rx_chan[i]->control = IFX_DMA_CH_ON;
dma_device->rx_chan[i]->byte_offset = 0;
dma_device->rx_chan[i]->chan_poll_enable = 1;
}
for (i = 0; i < dma_device->max_tx_chan_num; i++) {
dma_device->tx_chan[i]->control = IFX_DMA_CH_ON;
dma_device->tx_chan[i]->desc_len = 1;
dma_device->tx_chan[i]->chan_poll_enable = 1;
}
dma_device->current_tx_chan = 0;
dma_device->current_rx_chan = 0;
dma_device_register (dma_device);
for (i = 0; i < dma_device->max_rx_chan_num; i++) {
(dma_device->rx_chan[i])->open (dma_device->rx_chan[i]);
}
dma->controlr.BS = 0;
dma->controlr.RXCLS = 0;
dma->controlr.EN = 1;
*IFX_DMA_PS = 1;
/* DANUBE PRE 1.4 SOFTWARE FIX */
if (ifx_danube_pre_1_4)
*IFX_DMA_PCTRL = 0x14;
else
*IFX_DMA_PCTRL = 0xF14;
return 0;
}
/*! \fn u32 *memory_alignment(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief A fix to align mis-aligned address for Danube version 1.3 chips which has
* memory alignment issues.
* \param arg Pointer to the input / output memory address
* \param buffer_alloc A pointer to the buffer
* \param in_buff Input (if == 1) or Output (if == 0) buffer
* \param nbytes Number of bytes of data
* \return returns arg: if address is aligned, buffer_alloc: if memory address is not aligned
*/
u32 *memory_alignment(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes)
{
if (ifx_danube_pre_1_4) {
/* for input buffer */
if(in_buff) {
if (((u32) arg) & 0xF) {
memcpy(buffer_alloc, arg, nbytes);
return (u32 *) buffer_alloc;
}
else
return (u32 *) arg;
}
else {
/* for output buffer */
if (((u32) arg) & 0x3)
return buffer_alloc;
else
return (u32 *) arg;
}
}
return (u32 *) arg;
}
/*! \fn void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief copy the DMA data to the memory address space for AES. The swaping of the 4 bytes
* is done only for Danube version 1.3 (FIX). Otherwise, it is a direct memory copy
* to out_arg pointer
* \param outcopy Pointer to the address to store swapped copy
* \param out_dma A pointer to the memory address that stores the DMA data
* \param out_arg The pointer to the memory address that needs to be copied to
* \param nbytes Number of bytes of data
*/
void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
{
int i = 0;
int x = 0;
/* DANUBE PRE 1.4 SOFTWARE FIX */
if (ifx_danube_pre_1_4) {
for (i = 0; i < (nbytes / 4); i++) {
x = i ^ 0x3;
outcopy[i] = out_dma[x];
}
if (((u32) out_arg) & 0x3) {
memcpy((u8 *)out_arg, outcopy, nbytes);
}
}
else
memcpy (out_arg, out_dma, nbytes);
}
/*! \fn void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief copy the DMA data to the memory address space for DES. The swaping of the 4 bytes
* is done only for Danube version 1.3 (FIX). Otherwise, it is a direct memory copy
* to out_arg pointer
*
* \param outcopy Pointer to the address to store swapped copy
* \param out_dma A pointer to the memory address that stores the DMA data
* \param out_arg The pointer to the memory address that needs to be copied to
* \param nbytes Number of bytes of data
*/
void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
{
int i = 0;
int x = 0;
/* DANUBE PRE 1.4 SOFTWARE FIX */
if (ifx_danube_pre_1_4) {
for (i = 0; i < (nbytes / 4); i++) {
x = i ^ 1;
outcopy[i] = out_dma[x];
}
if (((u32) out_arg) & 0x3) {
memcpy((u8 *)out_arg, outcopy, nbytes);
}
}
else
memcpy (out_arg, out_dma, nbytes);
}
/*! \fn int des_memory_allocate(int value)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief allocates memory to the necessary memory input/output buffer location, used during
* the DES algorithm DMA transfer (memory alignment issues)
* \param value value determinds whether the calling of the function is for a input buffer
* or for an output buffer memory allocation
*/
int des_memory_allocate(int value)
{
if (ifx_danube_pre_1_4) {
if (value == BUFFER_IN) {
des_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
if (!des_buff_in)
return -1;
else
return 0;
}
else {
des_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
if (!des_buff_out)
return -1;
else
return 0;
}
}
else
return 0;
}
/*! \fn int aes_memory_allocate(int value)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief allocates memory to the necessary memory input/output buffer location, used during
* the AES algorithm DMA transfer (memory alignment issues)
* \param value value determinds whether the calling of the function is for a input buffer
* or for an output buffer memory allocation
*/
int aes_memory_allocate(int value)
{
if (ifx_danube_pre_1_4) {
if (value == BUFFER_IN) {
aes_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
if (!aes_buff_in)
return -1;
else
return 0;
}
else {
aes_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
if (!aes_buff_out)
return -1;
else
return 0;
}
}
else
return 0;
}
/*! \fn void memory_release(u32 *addr)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief frees previously allocated memory
* \param addr memory address of the buffer that needs to be freed
*/
void memory_release(u32 *addr)
{
if (addr)
kfree(addr);
return;
}
/*! \fn __exit ifxdeu_fini_dma(void)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief unregister dma devices after exit
*/
void __exit ifxdeu_fini_dma(void)
{
if (g_dma_page_ptr)
free_page((u32) g_dma_page_ptr);
dma_device_release(ifx_deu[0].dma_device);
dma_device_unregister(ifx_deu[0].dma_device);
}
#endif /* CONFIG_CRYPTO_DEV_IFXMIPS_DMA */
/*! \fn u32 endian_swap(u32 input)
* \ingroup BOARD_SPECIFIC_FUNCTIONS
* \brief function is not used
* \param input Data input to be swapped
* \return input
*/
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;
#ifndef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
//start crypto engine with write to ILR
aes->controlr.SM = 1;
aes->controlr.ARS = 1;
#else
aes->controlr.SM = 1;
aes->controlr.ARS = 1; // 0 for dma
#endif
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;
#ifndef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
// start crypto engine with write to ILR
des->controlr.SM = 1;
des->controlr.ARS = 1;
#else
des->controlr.SM = 1;
des->controlr.ARS = 1; // 0 for dma
#endif
}
/*! \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)
*/
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,230 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies
*/
/*!
\defgroup 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
#ifdef CONFIG_CRYPTO_DEV_DMA
#define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) memory_alignment(ptr, buffer, in_out, bytes)
#define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) aes_dma_memory_copy(outcopy, out_dma, out_arg, nbytes)
#define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) des_dma_memory_copy(outcopy, out_dma, out_arg, nbytes)
#define BUFFER_IN 1
#define BUFFER_OUT 0
#define DELAY_PERIOD 9
#define AES_ALGO 1
#define DES_ALGO 0
#define FREE_MEMORY(buff) memory_release(buff)
#define ALLOCATE_MEMORY(val, type) type ? aes_memory_allocate(val) : des_memory_allocate(val)
#endif /* CONFIG_CRYPTO_DEV_DMA */
#define INPUT_ENDIAN_SWAP(input) input_swap(input)
#define DEU_ENDIAN_SWAP(input) endian_swap(input)
#define AES_DMA_MISC_CONFIG()
#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 {
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;
u32 ILR;
u32 K1HR;
u32 K1LR;
u32 K2HR;
u32 K2LR;
u32 K3HR;
u32 K3LR;
u32 IVHR;
u32 IVLR;
u32 OHR;
u32 OLR;
};
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,150 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "ifxmips_deu.h"
extern _ifx_deu_device ifx_deu[1];
extern spinlock_t ifx_deu_lock;
//extern deu_drv_priv_t deu_dma_priv;
/*! \fn int deu_dma_intr_handler (struct dma_device_info *dma_dev, int status)
* \ingroup IFX_DMA_FUNCTIONS
* \brief callback function for deu dma interrupt
* \param dma_dev dma device
* \param status not used
*/
int deu_dma_intr_handler (struct dma_device_info *dma_dev, int status)
{
#if 0
int len = 0;
while (len <= 20000) { len++; }
u8 *buf;
int len = 0;
deu_drv_priv_t *deu_priv = (deu_drv_priv_t *)dma_dev->priv;
//printk("status:%d \n",status);
switch(status) {
case RCV_INT:
len = dma_device_read(dma_dev, (u8 **)&buf, NULL);
if ( len != deu_priv->deu_rx_len) {
printk(KERN_ERR "%s packet length %d is not equal to expect %d\n",
__func__, len, deu_priv->deu_rx_len);
return -1;
}
memcpy(deu_priv->deu_rx_buf, buf, deu_priv->deu_rx_len);
/* Reset for next usage */
deu_priv->deu_rx_buf = NULL;
deu_priv->deu_rx_len = 0;
DEU_WAKEUP_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, deu_priv->deu_event_flags);
break;
case TX_BUF_FULL_INT:
// delay for buffer to be cleared
while (len <= 20000) { len++; }
break;
case TRANSMIT_CPT_INT:
break;
default:
break;
}
#endif
return 0;
}
extern u8 *g_dma_block;
extern u8 *g_dma_block2;
/*! \fn u8 *deu_dma_buffer_alloc (int len, int *byte_offset, void **opt)
* \ingroup IFX_DMA_FUNCTIONS
* \brief callback function for allocating buffers for dma receive descriptors
* \param len not used
* \param byte_offset dma byte offset
* \param *opt not used
*
*/
u8 *deu_dma_buffer_alloc (int len, int *byte_offset, void **opt)
{
u8 *swap = NULL;
// dma-core needs at least 2 blocks of memory
swap = g_dma_block;
g_dma_block = g_dma_block2;
g_dma_block2 = swap;
//dma_cache_wback_inv((unsigned long) g_dma_block, (PAGE_SIZE >> 1));
*byte_offset = 0;
return g_dma_block;
}
/*! \fn int deu_dma_buffer_free (u8 * dataptr, void *opt)
* \ingroup IFX_DMA_FUNCTIONS
* \brief callback function for freeing dma transmit descriptors
* \param dataptr data pointer to be freed
* \param opt not used
*/
int deu_dma_buffer_free (u8 *dataptr, void *opt)
{
#if 0
printk("Trying to free memory buffer\n");
if (dataptr == NULL && opt == NULL)
return 0;
else if (opt == NULL) {
kfree(dataptr);
return 1;
}
else if (dataptr == NULL) {
kfree(opt);
return 1;
}
else {
kfree(opt);
kfree(dataptr);
}
#endif
return 0;
}

View file

@ -0,0 +1,70 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\addtogroup 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,264 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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 <asm/byteorder.h>
#include "ifxmips_deu.h"
#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)
struct md5_ctx {
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(u32 *hash, u32 const *in)
{
int i;
volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START;
ulong flag;
CRTCL_SECT_START;
for (i = 0; i < 16; i++) {
hashs->MR = endian_swap(in[i]);
};
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
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->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 void md5_init(struct crypto_tfm *tfm)
{
struct md5_ctx *mctx = crypto_tfm_ctx(tfm);
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START;
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;
}
/*! \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 void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
{
struct md5_ctx *mctx = crypto_tfm_ctx(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;
}
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);
}
/*! \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 void md5_final(struct crypto_tfm *tfm, u8 *out)
{
struct md5_ctx *mctx = crypto_tfm_ctx(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;
u32 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->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));
}
/*
* \brief MD5 function mappings
*/
static struct crypto_alg ifxdeu_md5_alg = {
.cra_name = "md5",
.cra_driver_name = "ifxdeu-md5",
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct md5_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ifxdeu_md5_alg.cra_list),
.cra_u = { .digest = {
.dia_digestsize = MD5_DIGEST_SIZE,
.dia_init = md5_init,
.dia_update = md5_update,
.dia_final = md5_final } }
};
/*! \fn int __init ifxdeu_init_md5 (void)
* \ingroup IFX_MD5_FUNCTIONS
* \brief initialize md5 driver
*/
int __init ifxdeu_init_md5 (void)
{
int ret;
if ((ret = crypto_register_alg(&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_alg (&ifxdeu_md5_alg);
}

View file

@ -0,0 +1,307 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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 <asm/byteorder.h>
#include "ifxmips_deu.h"
#define MD5_DIGEST_SIZE 16
#define MD5_HMAC_BLOCK_SIZE 64
#define MD5_BLOCK_WORDS 16
#define MD5_HASH_WORDS 4
#define MD5_HMAC_DBN_TEMP_SIZE 1024 // size in dword, needed for dbn workaround
#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)
struct md5_hmac_ctx {
u32 hash[MD5_HASH_WORDS];
u32 block[MD5_BLOCK_WORDS];
u64 byte_count;
u32 dbn;
u32 temp[MD5_HMAC_DBN_TEMP_SIZE];
};
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 crypto_tfm *tfm, u32 const *in)
{
struct md5_hmac_ctx *mctx = crypto_tfm_ctx(tfm);
memcpy(&mctx->temp[mctx->dbn<<4], in, 64); //dbn workaround
mctx->dbn += 1;
if ( (mctx->dbn<<4) > MD5_HMAC_DBN_TEMP_SIZE )
{
printk("MD5_HMAC_DBN_TEMP_SIZE exceeded\n");
}
}
/*! \fn int md5_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
* \ingroup 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
*/
int md5_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
{
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START;
int i, j;
u32 *in_key = (u32 *)key;
hash->KIDX = 0x80000000; // reset all 16 words of the key to '0'
asm("sync");
j = 0;
for (i = 0; i < keylen; i+=4)
{
hash->KIDX = j;
asm("sync");
hash->KEY = *((u32 *) in_key + j);
j++;
}
return 0;
}
/*! \fn void md5_hmac_init(struct crypto_tfm *tfm)
* \ingroup IFX_MD5_HMAC_FUNCTIONS
* \brief initialize md5 hmac context
* \param tfm linux crypto algo transform
*/
void md5_hmac_init(struct crypto_tfm *tfm)
{
struct md5_hmac_ctx *mctx = crypto_tfm_ctx(tfm);
memset(mctx, 0, sizeof(struct md5_hmac_ctx));
mctx->dbn = 0; //dbn workaround
}
/*! \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
*/
void md5_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
{
struct md5_hmac_ctx *mctx = crypto_tfm_ctx(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;
}
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
data, avail);
md5_hmac_transform(tfm, mctx->block);
data += avail;
len -= avail;
while (len >= sizeof(mctx->block)) {
memcpy(mctx->block, data, sizeof(mctx->block));
md5_hmac_transform(tfm, mctx->block);
data += sizeof(mctx->block);
len -= sizeof(mctx->block);
}
memcpy(mctx->block, data, len);
}
/*! \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
*/
void md5_hmac_final(struct crypto_tfm *tfm, u8 *out)
{
struct md5_hmac_ctx *mctx = crypto_tfm_ctx(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;
u32 flag;
int i = 0;
int dbn;
u32 *in = &mctx->temp[0];
*p++ = 0x80;
if (padding < 0) {
memset(p, 0x00, padding + sizeof (u64));
md5_hmac_transform(tfm, 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(tfm, mctx->block);
CRTCL_SECT_START;
printk("dbn = %d\n", mctx->dbn);
hashs->DBN = mctx->dbn;
*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;
CRTCL_SECT_END;
}
/*
* \brief MD5_HMAC function mappings
*/
static struct crypto_alg ifxdeu_md5_hmac_alg = {
.cra_name = "hmac(md5)",
.cra_driver_name = "ifxdeu-md5_hmac",
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct md5_hmac_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ifxdeu_md5_hmac_alg.cra_list),
.cra_u = { .digest = {
.dia_digestsize = MD5_DIGEST_SIZE,
.dia_setkey = md5_hmac_setkey,
.dia_init = md5_hmac_init,
.dia_update = md5_hmac_update,
.dia_final = md5_hmac_final } }
};
/*! \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;
if ((ret = crypto_register_alg(&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_alg (&ifxdeu_md5_hmac_alg);
}

View file

@ -0,0 +1,244 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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 <linux/types.h>
#include <asm/scatterlist.h>
#include <asm/byteorder.h>
#include "ifxmips_deu.h"
#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)
/*
* \brief SHA1 private structure
*/
struct sha1_ctx {
u64 count;
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 (u32 *state, const u32 *in)
{
int i = 0;
volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START;
u32 flag;
CRTCL_SECT_START;
for (i = 0; i < 16; i++) {
hashs->MR = in[i];
};
//wait for processing
while (hashs->controlr.BSY) {
// this will not take long
}
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 void sha1_init(struct crypto_tfm *tfm)
{
struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
SHA_HASH_INIT;
sctx->count = 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 void sha1_update(struct crypto_tfm *tfm, const u8 *data,
unsigned int len)
{
struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
unsigned int i, j;
j = (sctx->count >> 3) & 0x3f;
sctx->count += len << 3;
if ((j + len) > 63) {
memcpy (&sctx->buffer[j], data, (i = 64 - j));
sha1_transform (sctx->state, (const u32 *)sctx->buffer);
for (; i + 63 < len; i += 64) {
sha1_transform (sctx->state, (const u32 *)&data[i]);
}
j = 0;
}
else
i = 0;
memcpy (&sctx->buffer[j], &data[i], len - i);
}
/*! \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 void sha1_final(struct crypto_tfm *tfm, u8 *out)
{
struct sha1_ctx *sctx = crypto_tfm_ctx(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;
ulong flag;
t = sctx->count;
bits[7] = 0xff & t;
t >>= 8;
bits[6] = 0xff & t;
t >>= 8;
bits[5] = 0xff & t;
t >>= 8;
bits[4] = 0xff & t;
t >>= 8;
bits[3] = 0xff & t;
t >>= 8;
bits[2] = 0xff & t;
t >>= 8;
bits[1] = 0xff & t;
t >>= 8;
bits[0] = 0xff & t;
/* Pad out to 56 mod 64 */
index = (sctx->count >> 3) & 0x3f;
padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
sha1_update (tfm, padding, padlen);
/* Append length */
sha1_update (tfm, 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);
}
/*
* \brief SHA1 function mappings
*/
struct crypto_alg ifxdeu_sha1_alg = {
.cra_name = "sha1",
.cra_driver_name= "ifxdeu-sha1",
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sha1_ctx),
.cra_module = THIS_MODULE,
.cra_alignmask = 3,
.cra_list = LIST_HEAD_INIT(ifxdeu_sha1_alg.cra_list),
.cra_u = { .digest = {
.dia_digestsize = SHA1_DIGEST_SIZE,
.dia_init = sha1_init,
.dia_update = sha1_update,
.dia_final = sha1_final } }
};
/*! \fn int __init ifxdeu_init_sha1 (void)
* \ingroup IFX_SHA1_FUNCTIONS
* \brief initialize sha1 driver
*/
int __init ifxdeu_init_sha1 (void)
{
int ret;
if ((ret = crypto_register_alg(&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_alg (&ifxdeu_sha1_alg);
}

View file

@ -0,0 +1,308 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
* Copyright (C) 2009 Mohammad Firdaus
*/
/*!
\defgroup 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 <linux/types.h>
#include <asm/scatterlist.h>
#include <asm/byteorder.h>
#include <linux/delay.h>
#include "ifxmips_deu.h"
#ifdef CONFIG_CRYPTO_DEV_IFXMIPS_SHA1_HMAC
#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
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)
struct sha1_hmac_ctx {
u64 count;
u32 state[5];
u8 buffer[64];
u32 dbn;
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 void sha1_hmac_transform(struct crypto_tfm *tfm, u32 const *in)
{
struct sha1_hmac_ctx *sctx = crypto_tfm_ctx(tfm);
memcpy(&sctx->temp[sctx->dbn<<4], in, 64); //dbn workaround
sctx->dbn += 1;
if ( (sctx->dbn<<4) > SHA1_HMAC_DBN_TEMP_SIZE )
{
printk("SHA1_HMAC_DBN_TEMP_SIZE exceeded\n");
}
}
/*! \fn int sha1_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
* \ingroup 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
*/
int sha1_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
{
volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START;
int i, j;
u32 *in_key = (u32 *)key;
hash->KIDX = 0x80000000; // reset all 16 words of the key to '0'
asm("sync");
j = 0;
for (i = 0; i < keylen; i+=4)
{
hash->KIDX = j;
asm("sync");
hash->KEY = *((u32 *) in_key + j);
j++;
}
return 0;
}
/*! \fn void sha1_hmac_init(struct crypto_tfm *tfm)
* \ingroup IFX_SHA1_HMAC_FUNCTIONS
* \brief initialize sha1 hmac context
* \param tfm linux crypto algo transform
*/
void sha1_hmac_init(struct crypto_tfm *tfm)
{
struct sha1_hmac_ctx *sctx = crypto_tfm_ctx(tfm);
memset(sctx, 0, sizeof(struct sha1_hmac_ctx));
sctx->dbn = 0; //dbn workaround
}
/*! \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 void sha1_hmac_update(struct crypto_tfm *tfm, const u8 *data,
unsigned int len)
{
struct sha1_hmac_ctx *sctx = crypto_tfm_ctx(tfm);
unsigned int i, j;
j = (sctx->count >> 3) & 0x3f;
sctx->count += len << 3;
//printk("sctx->count = %d\n", (sctx->count >> 3));
if ((j + len) > 63) {
memcpy (&sctx->buffer[j], data, (i = 64 - j));
sha1_hmac_transform (tfm, (const u32 *)sctx->buffer);
for (; i + 63 < len; i += 64) {
sha1_hmac_transform (tfm, (const u32 *)&data[i]);
}
j = 0;
}
else
i = 0;
memcpy (&sctx->buffer[j], &data[i], len - i);
}
/*! \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 void sha1_hmac_final(struct crypto_tfm *tfm, u8 *out)
{
struct sha1_hmac_ctx *sctx = crypto_tfm_ctx(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;
ulong flag;
int i = 0;
int dbn;
u32 *in = &sctx->temp[0];
t = sctx->count + 512; // need to add 512 bit of the IPAD operation
bits[7] = 0xff & t;
t >>= 8;
bits[6] = 0xff & t;
t >>= 8;
bits[5] = 0xff & t;
t >>= 8;
bits[4] = 0xff & t;
t >>= 8;
bits[3] = 0xff & t;
t >>= 8;
bits[2] = 0xff & t;
t >>= 8;
bits[1] = 0xff & t;
t >>= 8;
bits[0] = 0xff & t;
/* Pad out to 56 mod 64 */
index = (sctx->count >> 3) & 0x3f;
padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
sha1_hmac_update (tfm, padding, padlen);
/* Append length */
sha1_hmac_update (tfm, 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;
CRTCL_SECT_END;
}
/*
* \brief SHA1-HMAC function mappings
*/
struct crypto_alg ifxdeu_sha1_hmac_alg = {
.cra_name = "hmac(sha1)",
.cra_driver_name= "ifxdeu-sha1_hmac",
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sha1_hmac_ctx),
.cra_module = THIS_MODULE,
.cra_alignmask = 3,
.cra_list = LIST_HEAD_INIT(ifxdeu_sha1_hmac_alg.cra_list),
.cra_u = { .digest = {
.dia_digestsize = SHA1_DIGEST_SIZE,
.dia_setkey = sha1_hmac_setkey,
.dia_init = sha1_hmac_init,
.dia_update = sha1_hmac_update,
.dia_final = sha1_hmac_final } }
};
/*! \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;
if ((ret = crypto_register_alg(&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_alg (&ifxdeu_sha1_hmac_alg);
}
#endif

View file

@ -0,0 +1,76 @@
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -222,4 +222,66 @@ config CRYPTO_DEV_PPC4XX
help
This option allows you to have support for AMCC crypto acceleration.
+config CRYPTO_DEV_IFXMIPS
+ bool "Support for IFXMIPS crypto engine"
+ select CRYPTO_ALGAPI
+ default y
+ help
+ Will support IFXMIPS crypto hardware
+ If you are unsure, say M.
+
+menuconfig CRYPTO_DEV_IFXMIPS_DES
+ bool "IFXMIPS crypto hardware for DES algorithm"
+ depends on CRYPTO_DEV_IFXMIPS
+ select CRYPTO_BLKCIPHER
+ default y
+ help
+ Use crypto hardware for DES/3DES algorithm.
+ If unsure say N.
+
+menuconfig CRYPTO_DEV_IFXMIPS_AES
+ bool "IFXMIPS crypto hardware for AES algorithm"
+ depends on CRYPTO_DEV_IFXMIPS
+ select CRYPTO_BLKCIPHER
+ default y
+ help
+ Use crypto hardware for AES algorithm.
+ If unsure say N.
+
+menuconfig CRYPTO_DEV_IFXMIPS_ARC4
+ bool "IFXMIPS crypto hardware for ARC4 algorithm"
+ depends on (CRYPTO_DEV_IFXMIPS && !DANUBE)
+ select CRYPTO_BLKCIPHER
+ default y
+ help
+ Use crypto hardware for ARC4 algorithm.
+ If unsure say N.
+
+menuconfig CRYPTO_DEV_IFXMIPS_SHA1
+ bool "IFXMIPS crypto hardware for SHA1 algorithm"
+ depends on CRYPTO_DEV_IFXMIPS
+ select CRYPTO_BLKCIPHER
+ default y
+ help
+ Use crypto hardware for SHA1 algorithm.
+ If unsure say N.
+
+menuconfig CRYPTO_DEV_IFXMIPS_SHA1_HMAC
+ bool "IFXMIPS crypto hardware for SHA1_HMAC algorithm"
+ depends on (CRYPTO_DEV_IFXMIPS && !DANUBE)
+ select CRYPTO_BLKCIPHER
+ default y
+ help
+ Use crypto hardware for SHA1_HMAC algorithm.
+ If unsure say N.
+
+menuconfig CRYPTO_DEV_IFXMIPS_MD5_HMAC
+ bool "IFXMIPS crypto hardware for MD5_HMAC algorithms"
+ depends on (CRYPTO_DEV_IFXMIPS && !DANUBE)
+ select CRYPTO_BLKCIPHER
+ default y
+ help
+ Use crypto hardware for MD5_HMAC algorithm.
+ If unsure say N.
+
endif # CRYPTO_HW
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_c
obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
+obj-$(CONFIG_CRYPTO_DEV_IFXMIPS) += ifxmips/