1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2025-04-21 12:27:27 +03:00

[ifxmips]:

* bump kernel to 2.6.35.8
* merge arcadyn mach files
* fixes ar9
* adds hack for tapi drivers



git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23836 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
blogic
2010-11-03 19:02:27 +00:00
parent f0efddfaa0
commit 0a2b2965cd
223 changed files with 620 additions and 22746 deletions

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,197 @@
/*
* 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) 2006 infineon
* Copyright (C) 2007 John Crispin <blogic@openwrt.org>
*
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
#include <linux/errno.h>
#include <linux/leds.h>
#include <linux/delay.h>
#include <ifxmips.h>
#include <ifxmips_gpio.h>
#include <ifxmips_pmu.h>
#define DRVNAME "ifxmips_led"
/* might need to be changed depending on shift register used on the pcb */
#if 1
#define IFXMIPS_LED_CLK_EDGE IFXMIPS_LED_FALLING
#else
#define IFXMIPS_LED_CLK_EDGE IFXMIPS_LED_RISING
#endif
#define IFXMIPS_LED_SPEED IFXMIPS_LED_8HZ
#define IFXMIPS_LED_GPIO_PORT 0
#define IFXMIPS_MAX_LED 24
struct ifxmips_led {
struct led_classdev cdev;
u8 bit;
};
void ifxmips_led_set(unsigned int led)
{
led &= 0xffffff;
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CPU0) | led, IFXMIPS_LED_CPU0);
}
EXPORT_SYMBOL(ifxmips_led_set);
void ifxmips_led_clear(unsigned int led)
{
led = ~(led & 0xffffff);
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CPU0) & led, IFXMIPS_LED_CPU0);
}
EXPORT_SYMBOL(ifxmips_led_clear);
void ifxmips_led_blink_set(unsigned int led)
{
led &= 0xffffff;
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON0) | led, IFXMIPS_LED_CON0);
}
EXPORT_SYMBOL(ifxmips_led_blink_set);
void ifxmips_led_blink_clear(unsigned int led)
{
led = ~(led & 0xffffff);
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON0) & led, IFXMIPS_LED_CON0);
}
EXPORT_SYMBOL(ifxmips_led_blink_clear);
static void ifxmips_ledapi_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct ifxmips_led *led_dev =
container_of(led_cdev, struct ifxmips_led, cdev);
if (value)
ifxmips_led_set(1 << led_dev->bit);
else
ifxmips_led_clear(1 << led_dev->bit);
}
void ifxmips_led_setup_gpio(void)
{
int i = 0;
/* leds are controlled via a shift register
we need to setup pins SH,D,ST (4,5,6) to make it work */
for (i = 4; i < 7; i++) {
ifxmips_port_set_altsel0(IFXMIPS_LED_GPIO_PORT, i);
ifxmips_port_clear_altsel1(IFXMIPS_LED_GPIO_PORT, i);
ifxmips_port_set_dir_out(IFXMIPS_LED_GPIO_PORT, i);
ifxmips_port_set_open_drain(IFXMIPS_LED_GPIO_PORT, i);
}
}
static int ifxmips_led_probe(struct platform_device *dev)
{
int i = 0;
ifxmips_led_setup_gpio();
ifxmips_w32(0, IFXMIPS_LED_AR);
ifxmips_w32(0, IFXMIPS_LED_CPU0);
ifxmips_w32(0, IFXMIPS_LED_CPU1);
ifxmips_w32(LED_CON0_SWU, IFXMIPS_LED_CON0);
ifxmips_w32(0, IFXMIPS_LED_CON1);
/* setup the clock edge that the shift register is triggered on */
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON0) & ~IFXMIPS_LED_EDGE_MASK,
IFXMIPS_LED_CON0);
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON0) | IFXMIPS_LED_CLK_EDGE,
IFXMIPS_LED_CON0);
/* per default leds 15-0 are set */
ifxmips_w32(IFXMIPS_LED_GROUP1 | IFXMIPS_LED_GROUP0, IFXMIPS_LED_CON1);
/* leds are update periodically by the FPID */
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON1) & ~IFXMIPS_LED_UPD_MASK,
IFXMIPS_LED_CON1);
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON1) | IFXMIPS_LED_UPD_SRC_FPI,
IFXMIPS_LED_CON1);
/* set led update speed */
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON1) & ~IFXMIPS_LED_MASK,
IFXMIPS_LED_CON1);
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON1) | IFXMIPS_LED_SPEED,
IFXMIPS_LED_CON1);
/* adsl 0 and 1 leds are updated by the arc */
ifxmips_w32(ifxmips_r32(IFXMIPS_LED_CON0) | IFXMIPS_LED_ADSL_SRC,
IFXMIPS_LED_CON0);
/* per default, the leds are turned on */
ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_LED);
for (i = 0; i < IFXMIPS_MAX_LED; i++) {
struct ifxmips_led *tmp =
kzalloc(sizeof(struct ifxmips_led), GFP_KERNEL);
tmp->cdev.brightness_set = ifxmips_ledapi_set;
tmp->cdev.name = kmalloc(sizeof("ifxmips:led:00"), GFP_KERNEL);
sprintf((char *)tmp->cdev.name, "ifxmips:led:%02d", i);
tmp->cdev.default_trigger = NULL;
tmp->bit = i;
led_classdev_register(&dev->dev, &tmp->cdev);
}
return 0;
}
static int ifxmips_led_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver ifxmips_led_driver = {
.probe = ifxmips_led_probe,
.remove = ifxmips_led_remove,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
int __init ifxmips_led_init(void)
{
int ret = platform_driver_register(&ifxmips_led_driver);
if (ret)
printk(KERN_INFO
"ifxmips_led: Error registering platfom driver!");
return ret;
}
void __exit ifxmips_led_exit(void)
{
platform_driver_unregister(&ifxmips_led_driver);
}
module_init(ifxmips_led_init);
module_exit(ifxmips_led_exit);

View File

@@ -0,0 +1,282 @@
/*
* 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) 2004 Liu Peng Infineon IFAP DC COM CPE
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/cfi.h>
#include <linux/magic.h>
#include <linux/platform_device.h>
#include <ifxmips.h>
#include <ifxmips_prom.h>
#include <ifxmips_ebu.h>
#ifndef CONFIG_MTD_PARTITIONS
#error Please enable CONFIG_MTD_PARTITIONS
#endif
static struct map_info ifxmips_map = {
.name = "ifx-nor",
.bankwidth = 2,
.size = 0x400000,
};
static map_word ifxmips_read16(struct map_info *map, unsigned long adr)
{
unsigned long flags;
map_word temp;
spin_lock_irqsave(&ebu_lock, flags);
adr ^= 2;
temp.x[0] = *((__u16 *)(map->virt + adr));
spin_unlock_irqrestore(&ebu_lock, flags);
return temp;
}
static void ifxmips_write16(struct map_info *map, map_word d, unsigned long adr)
{
unsigned long flags;
spin_lock_irqsave(&ebu_lock, flags);
adr ^= 2;
*((__u16 *)(map->virt + adr)) = d.x[0];
spin_unlock_irqrestore(&ebu_lock, flags);
}
void ifxmips_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
unsigned char *p;
unsigned char *to_8;
unsigned long flags;
spin_lock_irqsave(&ebu_lock, flags);
from = (unsigned long)(from + map->virt);
p = (unsigned char *) from;
to_8 = (unsigned char *) to;
while (len--)
*to_8++ = *p++;
spin_unlock_irqrestore(&ebu_lock, flags);
}
void ifxmips_copy_to(struct map_info *map,
unsigned long to,
const void *from,
ssize_t len)
{
unsigned char *p = (unsigned char *)from;
unsigned char *to_8;
unsigned long flags;
spin_lock_irqsave(&ebu_lock, flags);
to += (unsigned long) map->virt;
to_8 = (unsigned char *)to;
while (len--)
*p++ = *to_8++;
spin_unlock_irqrestore(&ebu_lock, flags);
}
static struct mtd_partition ifxmips_partitions[] = {
{
.name = "uboot",
.offset = 0x00000000,
.size = 0x00020000,
},
{
.name = "uboot_env",
.offset = 0x00020000,
.size = 0x0,
},
{
.name = "kernel",
.offset = 0x0,
.size = 0x0,
},
{
.name = "rootfs",
.offset = 0x0,
.size = 0x0,
},
{
.name = "board_config",
.offset = 0x0,
.size = 0x0,
},
};
static struct mtd_partition ifxmips_meta_partition = {
.name = "linux",
.offset = 0x00030000,
.size = 0x0,
};
static const char *part_probe_types[] = { "cmdlinepart", NULL };
int find_uImage_size(unsigned long start_offset)
{
unsigned long magic;
unsigned long temp;
ifxmips_copy_from(&ifxmips_map, &magic, start_offset, 4);
if (le32_to_cpu(magic) != 0x56190527) {
printk(KERN_INFO "ifxmips_mtd: invalid magic (0x%08X) of kernel at 0x%08lx \n", le32_to_cpu(magic), start_offset);
return 0;
}
ifxmips_copy_from(&ifxmips_map, &temp, start_offset + 12, 4);
printk(KERN_INFO "ifxmips_mtd: kernel size is %ld \n", temp + 0x40);
return temp + 0x40;
}
int find_brn_block(unsigned long start_offset)
{
unsigned char temp[9];
ifxmips_copy_from(&ifxmips_map, &temp, start_offset, 8);
temp[8] = '\0';
printk(KERN_INFO "data in brn block %s\n", temp);
if (memcmp(temp, "BRN-BOOT", 8) == 0)
return 1;
else
return 0;
}
int detect_squashfs_partition(unsigned long start_offset)
{
unsigned long temp;
ifxmips_copy_from(&ifxmips_map, &temp, start_offset, 4);
return le32_to_cpu(temp) == SQUASHFS_MAGIC;
}
static int ifxmips_mtd_probe(struct platform_device *dev)
{
struct mtd_info *ifxmips_mtd = NULL;
struct mtd_partition *parts = NULL;
unsigned long uimage_size;
int err, i;
int kernel_part = 2, rootfs_part = 3;
int num_parts = ARRAY_SIZE(ifxmips_partitions);
ifxmips_w32(0x1d7ff, IFXMIPS_EBU_BUSCON0);
ifxmips_map.read = ifxmips_read16;
ifxmips_map.write = ifxmips_write16;
ifxmips_map.copy_from = ifxmips_copy_from;
ifxmips_map.copy_to = ifxmips_copy_to;
ifxmips_map.phys = dev->resource->start;
ifxmips_map.size = dev->resource->end - ifxmips_map.phys + 1;
ifxmips_map.virt = ioremap_nocache(ifxmips_map.phys, ifxmips_map.size);
if (!ifxmips_map.virt) {
printk(KERN_WARNING "ifxmips_mtd: failed to ioremap!\n");
return -EIO;
}
ifxmips_mtd = (struct mtd_info *) do_map_probe("cfi_probe", &ifxmips_map);
if (!ifxmips_mtd) {
iounmap(ifxmips_map.virt);
printk(KERN_WARNING "ifxmips_mtd: probing failed\n");
return -ENXIO;
}
ifxmips_mtd->owner = THIS_MODULE;
err = parse_mtd_partitions(ifxmips_mtd, part_probe_types, &parts, 0);
if (err > 0) {
printk(KERN_INFO "ifxmips_mtd: found %d partitions from cmdline\n", err);
num_parts = err;
kernel_part = 0;
rootfs_part = 0;
for (i = 0; i < num_parts; i++) {
if (strcmp(parts[i].name, "kernel") == 0)
kernel_part = i;
if (strcmp(parts[i].name, "rootfs") == 0)
rootfs_part = i;
}
} else {
/* if the flash is 64k sectors, the kernel will reside at 0xb0030000
if the flash is 128k sectors, the kernel will reside at 0xb0040000 */
ifxmips_partitions[1].size = ifxmips_mtd->erasesize;
ifxmips_partitions[2].offset = ifxmips_partitions[1].offset + ifxmips_mtd->erasesize;
parts = &ifxmips_partitions[0];
}
/* dynamic size detection only if rootfs-part follows kernel-part */
if (kernel_part+1 == rootfs_part) {
uimage_size = find_uImage_size(parts[kernel_part].offset);
if (detect_squashfs_partition(parts[kernel_part].offset + uimage_size)) {
printk(KERN_INFO "ifxmips_mtd: found a squashfs following the uImage\n");
} else {
uimage_size &= ~(ifxmips_mtd->erasesize -1);
uimage_size += ifxmips_mtd->erasesize;
}
parts[kernel_part].size = uimage_size;
parts[rootfs_part].offset = parts[kernel_part].offset + parts[kernel_part].size;
parts[rootfs_part].size = ((ifxmips_mtd->size >> 20) * 1024 * 1024) - parts[rootfs_part].offset;
ifxmips_meta_partition.offset = parts[kernel_part].offset;
ifxmips_meta_partition.size = parts[kernel_part].size + parts[rootfs_part].size;
}
if (err <= 0) {
if (ifxmips_has_brn_block()) {
parts[3].size -= ifxmips_mtd->erasesize;
parts[4].offset = ifxmips_mtd->size - ifxmips_mtd->erasesize;
parts[4].size = ifxmips_mtd->erasesize;
ifxmips_meta_partition.size -= ifxmips_mtd->erasesize;
} else {
num_parts--;
}
}
add_mtd_partitions(ifxmips_mtd, parts, num_parts);
add_mtd_partitions(ifxmips_mtd, &ifxmips_meta_partition, 1);
printk(KERN_INFO "ifxmips_mtd: added %s flash with %dMB\n",
ifxmips_map.name, ((int)ifxmips_mtd->size) >> 20);
return 0;
}
static struct platform_driver ifxmips_mtd_driver = {
.probe = ifxmips_mtd_probe,
.driver = {
.name = "ifxmips_mtd",
.owner = THIS_MODULE,
},
};
int __init init_ifxmips_mtd(void)
{
int ret = platform_driver_register(&ifxmips_mtd_driver);
if (ret)
printk(KERN_INFO "ifxmips_mtd: error registering platfom driver!");
return ret;
}
static void __exit cleanup_ifxmips_mtd(void)
{
platform_driver_unregister(&ifxmips_mtd_driver);
}
module_init(init_ifxmips_mtd);
module_exit(cleanup_ifxmips_mtd);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
MODULE_DESCRIPTION("MTD map driver for IFXMIPS boards");

View File

@@ -0,0 +1,493 @@
/*
* 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) 2005 Wu Qi Ming <Qi-Ming.Wu@infineon.com>
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/in.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/phy.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/ethtool.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/checksum.h>
#include <ifxmips.h>
#include <ifxmips_dma.h>
#include <ifxmips_pmu.h>
#include <ifxmips_platform.h>
struct ifxmips_mii_priv {
struct net_device_stats stats;
struct dma_device_info *dma_device;
struct sk_buff *skb;
struct mii_bus *mii_bus;
struct phy_device *phydev;
int oldlink, oldspeed, oldduplex;
};
static struct net_device *ifxmips_mii0_dev;
static unsigned char mac_addr[MAX_ADDR_LEN];
static int ifxmips_mdiobus_write(struct mii_bus *bus, int phy_addr,
int phy_reg, u16 phy_data)
{
u32 val = MDIO_ACC_REQUEST |
((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) |
phy_data;
while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
;
ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC);
return 0;
}
static int ifxmips_mdiobus_read(struct mii_bus *bus, int phy_addr, int phy_reg)
{
u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ |
((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET);
while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
;
ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC);
while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
;
val = ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK;
return val;
}
int ifxmips_ifxmips_mii_open(struct net_device *dev)
{
struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
struct dma_device_info *dma_dev = priv->dma_device;
int i;
for (i = 0; i < dma_dev->max_rx_chan_num; i++) {
if ((dma_dev->rx_chan[i])->control == IFXMIPS_DMA_CH_ON)
(dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]);
}
netif_start_queue(dev);
return 0;
}
int ifxmips_mii_release(struct net_device *dev)
{
struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
struct dma_device_info *dma_dev = priv->dma_device;
int i;
for (i = 0; i < dma_dev->max_rx_chan_num; i++)
dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]);
netif_stop_queue(dev);
return 0;
}
int ifxmips_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev)
{
struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
unsigned char *buf = NULL;
struct sk_buff *skb = NULL;
int len = 0;
len = dma_device_read(dma_dev, &buf, (void **)&skb);
if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) {
printk(KERN_INFO "ifxmips_mii0: packet too large %d\n", len);
goto ifxmips_mii_hw_receive_err_exit;
}
/* remove CRC */
len -= 4;
if (skb == NULL) {
printk(KERN_INFO "ifxmips_mii0: cannot restore pointer\n");
goto ifxmips_mii_hw_receive_err_exit;
}
if (len > (skb->end - skb->tail)) {
printk(KERN_INFO "ifxmips_mii0: BUG, len:%d end:%p tail:%p\n",
(len+4), skb->end, skb->tail);
goto ifxmips_mii_hw_receive_err_exit;
}
skb_put(skb, len);
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
priv->stats.rx_packets++;
priv->stats.rx_bytes += len;
return 0;
ifxmips_mii_hw_receive_err_exit:
if (len == 0) {
if (skb)
dev_kfree_skb_any(skb);
priv->stats.rx_errors++;
priv->stats.rx_dropped++;
return -EIO;
} else {
return len;
}
}
int ifxmips_mii_hw_tx(char *buf, int len, struct net_device *dev)
{
int ret = 0;
struct ifxmips_mii_priv *priv = netdev_priv(dev);
struct dma_device_info *dma_dev = priv->dma_device;
ret = dma_device_write(dma_dev, buf, len, priv->skb);
return ret;
}
int ifxmips_mii_tx(struct sk_buff *skb, struct net_device *dev)
{
int len;
char *data;
struct ifxmips_mii_priv *priv = netdev_priv(dev);
struct dma_device_info *dma_dev = priv->dma_device;
len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
data = skb->data;
priv->skb = skb;
dev->trans_start = jiffies;
/* TODO: we got more than 1 dma channel,
so we should do something intelligent here to select one */
dma_dev->current_tx_chan = 0;
wmb();
if (ifxmips_mii_hw_tx(data, len, dev) != len) {
dev_kfree_skb_any(skb);
priv->stats.tx_errors++;
priv->stats.tx_dropped++;
} else {
priv->stats.tx_packets++;
priv->stats.tx_bytes += len;
}
return 0;
}
void ifxmips_mii_tx_timeout(struct net_device *dev)
{
int i;
struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
priv->stats.tx_errors++;
for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]);
netif_wake_queue(dev);
return;
}
int dma_intr_handler(struct dma_device_info *dma_dev, int status)
{
int i;
switch (status) {
case RCV_INT:
ifxmips_mii_hw_receive(ifxmips_mii0_dev, dma_dev);
break;
case TX_BUF_FULL_INT:
printk(KERN_INFO "ifxmips_mii0: tx buffer full\n");
netif_stop_queue(ifxmips_mii0_dev);
for (i = 0; i < dma_dev->max_tx_chan_num; i++) {
if ((dma_dev->tx_chan[i])->control == IFXMIPS_DMA_CH_ON)
dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]);
}
break;
case TRANSMIT_CPT_INT:
for (i = 0; i < dma_dev->max_tx_chan_num; i++)
dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]);
netif_wake_queue(ifxmips_mii0_dev);
break;
}
return 0;
}
unsigned char *ifxmips_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt)
{
unsigned char *buffer = NULL;
struct sk_buff *skb = NULL;
skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
if (skb == NULL)
return NULL;
buffer = (unsigned char *)(skb->data);
skb_reserve(skb, 2);
*(int *)opt = (int)skb;
*byte_offset = 2;
return buffer;
}
void ifxmips_etop_dma_buffer_free(unsigned char *dataptr, void *opt)
{
struct sk_buff *skb = NULL;
if (opt == NULL) {
kfree(dataptr);
} else {
skb = (struct sk_buff *)opt;
dev_kfree_skb_any(skb);
}
}
static void
ifxmips_adjust_link(struct net_device *dev)
{
struct ifxmips_mii_priv *priv = netdev_priv(dev);
struct phy_device *phydev = priv->phydev;
int new_state = 0;
/* Did anything change? */
if (priv->oldlink != phydev->link ||
priv->oldduplex != phydev->duplex ||
priv->oldspeed != phydev->speed) {
/* Yes, so update status and mark as changed */
new_state = 1;
priv->oldduplex = phydev->duplex;
priv->oldspeed = phydev->speed;
priv->oldlink = phydev->link;
}
/* If link status changed, show new status */
if (new_state)
phy_print_status(phydev);
}
static int mii_probe(struct net_device *dev)
{
struct ifxmips_mii_priv *priv = netdev_priv(dev);
struct phy_device *phydev = NULL;
int phy_addr;
priv->oldlink = 0;
priv->oldspeed = 0;
priv->oldduplex = -1;
/* find the first (lowest address) PHY on the current MAC's MII bus */
for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
if (priv->mii_bus->phy_map[phy_addr]) {
phydev = priv->mii_bus->phy_map[phy_addr];
break; /* break out with first one found */
}
}
if (!phydev) {
printk (KERN_ERR "%s: no PHY found\n", dev->name);
return -ENODEV;
}
/* now we are supposed to have a proper phydev, to attach to... */
BUG_ON(!phydev);
BUG_ON(phydev->attached_dev);
phydev = phy_connect(dev, dev_name(&phydev->dev), &ifxmips_adjust_link,
0, PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
return PTR_ERR(phydev);
}
/* mask with MAC supported features */
phydev->supported &= (SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
| SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
| SUPPORTED_Autoneg
/* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
| SUPPORTED_MII
| SUPPORTED_TP);
phydev->advertising = phydev->supported;
priv->phydev = phydev;
printk(KERN_INFO "%s: attached PHY driver [%s] "
"(mii_bus:phy_addr=%s, irq=%d)\n",
dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
return 0;
}
static int ifxmips_mii_dev_init(struct net_device *dev)
{
int i;
struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
ether_setup(dev);
dev->watchdog_timeo = 10 * HZ;
dev->mtu = 1500;
memset(priv, 0, sizeof(struct ifxmips_mii_priv));
priv->dma_device = dma_device_reserve("PPE");
if (!priv->dma_device) {
BUG();
return -ENODEV;
}
priv->dma_device->buffer_alloc = &ifxmips_etop_dma_buffer_alloc;
priv->dma_device->buffer_free = &ifxmips_etop_dma_buffer_free;
priv->dma_device->intr_handler = &dma_intr_handler;
priv->dma_device->max_rx_chan_num = 4;
for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) {
priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE;
priv->dma_device->rx_chan[i]->control = IFXMIPS_DMA_CH_ON;
}
for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
if (i == 0)
priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_ON;
else
priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_OFF;
dma_device_register(priv->dma_device);
printk(KERN_INFO "%s: using mac=", dev->name);
for (i = 0; i < 6; i++) {
dev->dev_addr[i] = mac_addr[i];
printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':'));
}
priv->mii_bus = mdiobus_alloc();
if (priv->mii_bus == NULL)
return -ENOMEM;
priv->mii_bus->priv = dev;
priv->mii_bus->read = ifxmips_mdiobus_read;
priv->mii_bus->write = ifxmips_mdiobus_write;
priv->mii_bus->name = "ifxmips_mii";
snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
for(i = 0; i < PHY_MAX_ADDR; ++i)
priv->mii_bus->irq[i] = PHY_POLL;
mdiobus_register(priv->mii_bus);
return mii_probe(dev);
}
static void ifxmips_mii_chip_init(int mode)
{
ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_DMA);
ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_PPE);
if (mode == REV_MII_MODE)
ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_REVERSE, IFXMIPS_PPE32_CFG);
else if (mode == MII_MODE)
ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_NORMAL, IFXMIPS_PPE32_CFG);
ifxmips_w32(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, IFXMIPS_PPE32_IG_PLEN_CTRL);
ifxmips_w32(PPE32_CGEN, IFXMIPS_PPE32_ENET_MAC_CFG);
wmb();
}
static const struct net_device_ops ifxmips_eth_netdev_ops = {
.ndo_init = ifxmips_mii_dev_init,
.ndo_open = ifxmips_ifxmips_mii_open,
.ndo_stop = ifxmips_mii_release,
.ndo_start_xmit = ifxmips_mii_tx,
.ndo_tx_timeout = ifxmips_mii_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
static int
ifxmips_mii_probe(struct platform_device *dev)
{
int result = 0;
struct ifxmips_eth_data *eth = (struct ifxmips_eth_data*)dev->dev.platform_data;
ifxmips_mii0_dev = alloc_etherdev(sizeof(struct ifxmips_mii_priv));
ifxmips_mii0_dev->netdev_ops = &ifxmips_eth_netdev_ops;
memcpy(mac_addr, eth->mac, 6);
strcpy(ifxmips_mii0_dev->name, "eth%d");
ifxmips_mii_chip_init(eth->mii_mode);
result = register_netdev(ifxmips_mii0_dev);
if (result) {
printk(KERN_INFO "ifxmips_mii0: error %i registering device \"%s\"\n", result, ifxmips_mii0_dev->name);
goto out;
}
printk(KERN_INFO "ifxmips_mii0: driver loaded!\n");
out:
return result;
}
static int ifxmips_mii_remove(struct platform_device *dev)
{
struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(ifxmips_mii0_dev);
printk(KERN_INFO "ifxmips_mii0: ifxmips_mii0 cleanup\n");
dma_device_unregister(priv->dma_device);
dma_device_release(priv->dma_device);
kfree(priv->dma_device);
unregister_netdev(ifxmips_mii0_dev);
return 0;
}
static struct platform_driver ifxmips_mii_driver = {
.probe = ifxmips_mii_probe,
.remove = ifxmips_mii_remove,
.driver = {
.name = "ifxmips_mii0",
.owner = THIS_MODULE,
},
};
int __init ifxmips_mii_init(void)
{
int ret = platform_driver_register(&ifxmips_mii_driver);
if (ret)
printk(KERN_INFO "ifxmips_mii0: Error registering platfom driver!");
return ret;
}
static void __exit ifxmips_mii_cleanup(void)
{
platform_driver_unregister(&ifxmips_mii_driver);
}
module_init(ifxmips_mii_init);
module_exit(ifxmips_mii_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
MODULE_DESCRIPTION("ethernet driver for IFXMIPS boards");

View File

@@ -0,0 +1,551 @@
/*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* 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) 2004 Infineon IFAP DC COM CPE
* Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2007 John Crispin <blogic@openwrt.org>
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/circ_buf.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <asm/system.h>
#include <ifxmips.h>
#include <ifxmips_irq.h>
#define PORT_IFXMIPSASC 111
#include <linux/serial_core.h>
#define UART_DUMMY_UER_RX 1
static void ifxmipsasc_tx_chars(struct uart_port *port);
extern void prom_printf(const char *fmt, ...);
static struct uart_port ifxmipsasc_port[2];
static struct uart_driver ifxmipsasc_reg;
extern unsigned int ifxmips_get_fpi_hz(void);
static void ifxmipsasc_stop_tx(struct uart_port *port)
{
return;
}
static void ifxmipsasc_start_tx(struct uart_port *port)
{
unsigned long flags;
local_irq_save(flags);
ifxmipsasc_tx_chars(port);
local_irq_restore(flags);
return;
}
static void ifxmipsasc_stop_rx(struct uart_port *port)
{
ifxmips_w32(ASCWHBSTATE_CLRREN, port->membase + IFXMIPS_ASC_WHBSTATE);
}
static void ifxmipsasc_enable_ms(struct uart_port *port)
{
}
#include <linux/version.h>
static void ifxmipsasc_rx_chars(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
unsigned int ch = 0, rsr = 0, fifocnt;
fifocnt = ifxmips_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
while (fifocnt--) {
u8 flag = TTY_NORMAL;
ch = ifxmips_r32(port->membase + IFXMIPS_ASC_RBUF);
rsr = (ifxmips_r32(port->membase + IFXMIPS_ASC_STATE) & ASCSTATE_ANY) | UART_DUMMY_UER_RX;
tty_flip_buffer_push(tty);
port->icount.rx++;
/*
* Note that the error handling code is
* out of the main execution path
*/
if (rsr & ASCSTATE_ANY) {
if (rsr & ASCSTATE_PE) {
port->icount.parity++;
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRPE, port->membase + IFXMIPS_ASC_WHBSTATE);
} else if (rsr & ASCSTATE_FE) {
port->icount.frame++;
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRFE, port->membase + IFXMIPS_ASC_WHBSTATE);
}
if (rsr & ASCSTATE_ROE) {
port->icount.overrun++;
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRROE, port->membase + IFXMIPS_ASC_WHBSTATE);
}
rsr &= port->read_status_mask;
if (rsr & ASCSTATE_PE)
flag = TTY_PARITY;
else if (rsr & ASCSTATE_FE)
flag = TTY_FRAME;
}
if ((rsr & port->ignore_status_mask) == 0)
tty_insert_flip_char(tty, ch, flag);
if (rsr & ASCSTATE_ROE)
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
if (ch != 0)
tty_flip_buffer_push(tty);
return;
}
static void ifxmipsasc_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
if (uart_tx_stopped(port)) {
ifxmipsasc_stop_tx(port);
return;
}
while (((ifxmips_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_TXFFLMASK)
>> ASCFSTAT_TXFFLOFF) != TXFIFO_FULL) {
if (port->x_char) {
ifxmips_w32(port->x_char, port->membase + IFXMIPS_ASC_TBUF);
port->icount.tx++;
port->x_char = 0;
continue;
}
if (uart_circ_empty(xmit))
break;
ifxmips_w32(port->state->xmit.buf[port->state->xmit.tail], port->membase + IFXMIPS_ASC_TBUF);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
static irqreturn_t ifxmipsasc_tx_int(int irq, void *_port)
{
struct uart_port *port = (struct uart_port *)_port;
ifxmips_w32(ASC_IRNCR_TIR, port->membase + IFXMIPS_ASC_IRNCR);
ifxmipsasc_start_tx(port);
ifxmips_mask_and_ack_irq(irq);
return IRQ_HANDLED;
}
static irqreturn_t ifxmipsasc_er_int(int irq, void *_port)
{
struct uart_port *port = (struct uart_port *)_port;
/* clear any pending interrupts */
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRPE |
ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, port->membase + IFXMIPS_ASC_WHBSTATE);
return IRQ_HANDLED;
}
static irqreturn_t ifxmipsasc_rx_int(int irq, void *_port)
{
struct uart_port *port = (struct uart_port *)_port;
ifxmips_w32(ASC_IRNCR_RIR, port->membase + IFXMIPS_ASC_IRNCR);
ifxmipsasc_rx_chars((struct uart_port *)port);
ifxmips_mask_and_ack_irq(irq);
return IRQ_HANDLED;
}
static unsigned int ifxmipsasc_tx_empty(struct uart_port *port)
{
int status;
status = ifxmips_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
return status ? 0 : TIOCSER_TEMT;
}
static unsigned int ifxmipsasc_get_mctrl(struct uart_port *port)
{
return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
}
static void ifxmipsasc_set_mctrl(struct uart_port *port, u_int mctrl)
{
}
static void ifxmipsasc_break_ctl(struct uart_port *port, int break_state)
{
}
static int ifxmipsasc_startup(struct uart_port *port)
{
int retval;
port->uartclk = ifxmips_get_fpi_hz();
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CLC) & ~IFXMIPS_ASC_CLC_DISS, port->membase + IFXMIPS_ASC_CLC);
ifxmips_w32(((ifxmips_r32(port->membase + IFXMIPS_ASC_CLC) & ~ASCCLC_RMCMASK)) | (1 << ASCCLC_RMCOFFSET), port->membase + IFXMIPS_ASC_CLC);
ifxmips_w32(0, port->membase + IFXMIPS_ASC_PISEL);
ifxmips_w32(((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, port->membase + IFXMIPS_ASC_TXFCON);
ifxmips_w32(((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, port->membase + IFXMIPS_ASC_RXFCON);
wmb();
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) | ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN, port->membase + IFXMIPS_ASC_CON);
retval = request_irq(port->irq, ifxmipsasc_tx_int, IRQF_DISABLED, "asc_tx", port);
if (retval) {
printk(KERN_ERR "failed to request ifxmipsasc_tx_int\n");
return retval;
}
retval = request_irq(port->irq + 2, ifxmipsasc_rx_int, IRQF_DISABLED, "asc_rx", port);
if (retval) {
printk(KERN_ERR "failed to request ifxmipsasc_rx_int\n");
goto err1;
}
retval = request_irq(port->irq + 3, ifxmipsasc_er_int, IRQF_DISABLED, "asc_er", port);
if (retval) {
printk(KERN_ERR "failed to request ifxmipsasc_er_int\n");
goto err2;
}
ifxmips_w32(ASC_IRNREN_RX_BUF | ASC_IRNREN_TX_BUF | ASC_IRNREN_ERR | ASC_IRNREN_TX, port->membase + IFXMIPS_ASC_IRNREN);
return 0;
err2:
free_irq(port->irq + 2, port);
err1:
free_irq(port->irq, port);
return retval;
}
static void ifxmipsasc_shutdown(struct uart_port *port)
{
free_irq(port->irq, port);
free_irq(port->irq + 2, port);
free_irq(port->irq + 3, port);
ifxmips_w32(0, port->membase + IFXMIPS_ASC_CON);
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_RXFCON) | ASCRXFCON_RXFFLU, port->membase + IFXMIPS_ASC_RXFCON);
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_RXFCON) & ~ASCRXFCON_RXFEN, port->membase + IFXMIPS_ASC_RXFCON);
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_TXFCON) | ASCTXFCON_TXFFLU, port->membase + IFXMIPS_ASC_TXFCON);
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_TXFCON) & ~ASCTXFCON_TXFEN, port->membase + IFXMIPS_ASC_TXFCON);
}
static void ifxmipsasc_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old)
{
unsigned int cflag;
unsigned int iflag;
unsigned int quot;
unsigned int baud;
unsigned int con = 0;
unsigned long flags;
cflag = new->c_cflag;
iflag = new->c_iflag;
switch (cflag & CSIZE) {
case CS7:
con = ASCCON_M_7ASYNC;
break;
case CS5:
case CS6:
default:
con = ASCCON_M_8ASYNC;
break;
}
if (cflag & CSTOPB)
con |= ASCCON_STP;
if (cflag & PARENB) {
if (!(cflag & PARODD))
con &= ~ASCCON_ODD;
else
con |= ASCCON_ODD;
}
port->read_status_mask = ASCSTATE_ROE;
if (iflag & INPCK)
port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
port->ignore_status_mask = 0;
if (iflag & IGNPAR)
port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
if (iflag & IGNBRK) {
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (iflag & IGNPAR)
port->ignore_status_mask |= ASCSTATE_ROE;
}
if ((cflag & CREAD) == 0)
port->ignore_status_mask |= UART_DUMMY_UER_RX;
/* set error signals - framing, parity and overrun, enable receiver */
con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
local_irq_save(flags);
/* set up CON */
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) | con, port->membase + IFXMIPS_ASC_CON);
/* Set baud rate - take a divider of 2 into account */
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
quot = uart_get_divisor(port, baud);
quot = quot / 2 - 1;
/* disable the baudrate generator */
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) & ~ASCCON_R, port->membase + IFXMIPS_ASC_CON);
/* make sure the fractional divider is off */
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) & ~ASCCON_FDE, port->membase + IFXMIPS_ASC_CON);
/* set up to use divisor of 2 */
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) & ~ASCCON_BRS, port->membase + IFXMIPS_ASC_CON);
/* now we can write the new baudrate into the register */
ifxmips_w32(quot, port->membase + IFXMIPS_ASC_BG);
/* turn the baudrate generator back on */
ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) | ASCCON_R, port->membase + IFXMIPS_ASC_CON);
/* enable rx */
ifxmips_w32(ASCWHBSTATE_SETREN, port->membase + IFXMIPS_ASC_WHBSTATE);
local_irq_restore(flags);
}
static const char *ifxmipsasc_type(struct uart_port *port)
{
if (port->type == PORT_IFXMIPSASC) {
if (port->membase == (void *)IFXMIPS_ASC_BASE_ADDR)
return "asc0";
else
return "asc1";
} else {
return NULL;
}
}
static void ifxmipsasc_release_port(struct uart_port *port)
{
}
static int ifxmipsasc_request_port(struct uart_port *port)
{
return 0;
}
static void ifxmipsasc_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_IFXMIPSASC;
ifxmipsasc_request_port(port);
}
}
static int ifxmipsasc_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_IFXMIPSASC)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
return ret;
}
static struct uart_ops ifxmipsasc_pops = {
.tx_empty = ifxmipsasc_tx_empty,
.set_mctrl = ifxmipsasc_set_mctrl,
.get_mctrl = ifxmipsasc_get_mctrl,
.stop_tx = ifxmipsasc_stop_tx,
.start_tx = ifxmipsasc_start_tx,
.stop_rx = ifxmipsasc_stop_rx,
.enable_ms = ifxmipsasc_enable_ms,
.break_ctl = ifxmipsasc_break_ctl,
.startup = ifxmipsasc_startup,
.shutdown = ifxmipsasc_shutdown,
.set_termios = ifxmipsasc_set_termios,
.type = ifxmipsasc_type,
.release_port = ifxmipsasc_release_port,
.request_port = ifxmipsasc_request_port,
.config_port = ifxmipsasc_config_port,
.verify_port = ifxmipsasc_verify_port,
};
static struct uart_port ifxmipsasc_port[2] = {
{
.membase = (void *)IFXMIPS_ASC_BASE_ADDR,
.mapbase = IFXMIPS_ASC_BASE_ADDR,
.iotype = SERIAL_IO_MEM,
.irq = IFXMIPSASC_TIR(0),
.uartclk = 0,
.fifosize = 16,
.type = PORT_IFXMIPSASC,
.ops = &ifxmipsasc_pops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 0
}, {
.membase = (void *)(IFXMIPS_ASC_BASE_ADDR + IFXMIPS_ASC_BASE_DIFF),
.mapbase = IFXMIPS_ASC_BASE_ADDR + IFXMIPS_ASC_BASE_DIFF,
.iotype = SERIAL_IO_MEM,
.irq = IFXMIPSASC_TIR(1),
.uartclk = 0,
.fifosize = 16,
.type = PORT_IFXMIPSASC,
.ops = &ifxmipsasc_pops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 1
}
};
static void ifxmipsasc_console_write(struct console *co, const char *s, u_int count)
{
int port = co->index;
int i, fifocnt;
unsigned long flags;
local_irq_save(flags);
for (i = 0; i < count; i++) {
do {
fifocnt = (ifxmips_r32((u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_FSTAT)) & ASCFSTAT_TXFFLMASK)
>> ASCFSTAT_TXFFLOFF;
} while (fifocnt == TXFIFO_FULL);
if (s[i] == '\0')
break;
if (s[i] == '\n') {
ifxmips_w32('\r', (u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_TBUF));
do {
fifocnt = (ifxmips_r32((u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_FSTAT)) & ASCFSTAT_TXFFLMASK)
>> ASCFSTAT_TXFFLOFF;
} while (fifocnt == TXFIFO_FULL);
}
ifxmips_w32(s[i], (u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_TBUF));
}
local_irq_restore(flags);
}
static int __init ifxmipsasc_console_setup(struct console *co, char *options)
{
int port = co->index;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
ifxmipsasc_port[port].uartclk = ifxmips_get_fpi_hz();
ifxmipsasc_port[port].type = PORT_IFXMIPSASC;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(&ifxmipsasc_port[port], co, baud, parity, bits, flow);
}
static struct console ifxmipsasc_console[2] =
{
{
.name = "ttyS",
.write = ifxmipsasc_console_write,
.device = uart_console_device,
.setup = ifxmipsasc_console_setup,
.flags = CON_PRINTBUFFER,
.index = 0,
.data = &ifxmipsasc_reg,
}, {
.name = "ttyS",
.write = ifxmipsasc_console_write,
.device = uart_console_device,
.setup = ifxmipsasc_console_setup,
.flags = CON_PRINTBUFFER,
.index = 1,
.data = &ifxmipsasc_reg,
}
};
static int __init ifxmipsasc_console_init(void)
{
register_console(&ifxmipsasc_console[0]);
register_console(&ifxmipsasc_console[1]);
return 0;
}
console_initcall(ifxmipsasc_console_init);
static struct uart_driver ifxmipsasc_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = 2,
.cons = &ifxmipsasc_console[1],
};
int __init ifxmipsasc_init(void)
{
int ret;
uart_register_driver(&ifxmipsasc_reg);
ret = uart_add_one_port(&ifxmipsasc_reg, &ifxmipsasc_port[0]);
ret = uart_add_one_port(&ifxmipsasc_reg, &ifxmipsasc_port[1]);
return 0;
}
void __exit ifxmipsasc_exit(void)
{
uart_unregister_driver(&ifxmipsasc_reg);
}
module_init(ifxmipsasc_init);
module_exit(ifxmipsasc_exit);
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
MODULE_DESCRIPTION("MIPS IFXMips serial port driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,195 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
* Based on EP93xx wdt driver
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <ifxmips.h>
#include <ifxmips_cgu.h>
#define IFXMIPS_WDT_PW1 0x00BE0000
#define IFXMIPS_WDT_PW2 0x00DC0000
#ifndef CONFIG_WATCHDOG_NOWAYOUT
static int wdt_ok_to_close;
#endif
static int wdt_timeout = 30;
int ifxmips_wdt_enable(unsigned int timeout)
{
u32 fpi;
fpi = cgu_get_io_region_clock();
ifxmips_w32(IFXMIPS_WDT_PW1, IFXMIPS_BIU_WDT_CR);
ifxmips_w32(IFXMIPS_WDT_PW2 |
(0x3 << 26) | /* PWL */
(0x3 << 24) | /* CLKDIV */
(0x1 << 31) | /* enable */
((timeout * (fpi / 0x40000)) + 0x1000), /* reload */
IFXMIPS_BIU_WDT_CR);
return 0;
}
void ifxmips_wdt_disable(void)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
wdt_ok_to_close = 0;
#endif
ifxmips_w32(IFXMIPS_WDT_PW1, IFXMIPS_BIU_WDT_CR);
ifxmips_w32(IFXMIPS_WDT_PW2, IFXMIPS_BIU_WDT_CR);
}
static ssize_t ifxmips_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
size_t i;
if (!len)
return 0;
#ifndef CONFIG_WATCHDOG_NOWAYOUT
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
wdt_ok_to_close = 1;
}
#endif
ifxmips_wdt_enable(wdt_timeout);
return len;
}
static struct watchdog_info ident = {
.options = WDIOF_MAGICCLOSE,
.identity = "ifxmips Watchdog",
};
static int ifxmips_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETTIMEOUT:
ret = put_user(wdt_timeout, (int __user *)arg);
break;
case WDIOC_SETTIMEOUT:
ret = get_user(wdt_timeout, (int __user *)arg);
break;
case WDIOC_KEEPALIVE:
ifxmips_wdt_enable(wdt_timeout);
ret = 0;
break;
}
return ret;
}
static int ifxmips_wdt_open(struct inode *inode, struct file *file)
{
ifxmips_wdt_enable(wdt_timeout);
return nonseekable_open(inode, file);
}
static int ifxmips_wdt_release(struct inode *inode, struct file *file)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
if (wdt_ok_to_close)
ifxmips_wdt_disable();
else
#endif
printk(KERN_ERR "ifxmips_wdt: watchdog closed without warning,"
" rebooting system\n");
return 0;
}
static const struct file_operations ifxmips_wdt_fops = {
.owner = THIS_MODULE,
.write = ifxmips_wdt_write,
.ioctl = ifxmips_wdt_ioctl,
.open = ifxmips_wdt_open,
.release = ifxmips_wdt_release,
};
static struct miscdevice ifxmips_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &ifxmips_wdt_fops,
};
static int ifxmips_wdt_probe(struct platform_device *dev)
{
int err;
err = misc_register(&ifxmips_wdt_miscdev);
if (err)
printk(KERN_INFO "ifxmips_wdt: error creating device\n");
else
printk(KERN_INFO "ifxmips_wdt: loaded\n");
return err;
}
static int ifxmips_wdt_remove(struct platform_device *dev)
{
ifxmips_wdt_disable();
misc_deregister(&ifxmips_wdt_miscdev);
return 0;
}
static struct platform_driver ifxmips_wdt_driver = {
.probe = ifxmips_wdt_probe,
.remove = ifxmips_wdt_remove,
.driver = {
.name = "ifxmips_wdt",
.owner = THIS_MODULE,
},
};
static int __init init_ifxmips_wdt(void)
{
int ret = platform_driver_register(&ifxmips_wdt_driver);
if (ret)
printk(KERN_INFO "ifxmips_wdt: error registering platfom driver!");
return ret;
}
static void __exit exit_ifxmips_wdt(void)
{
platform_driver_unregister(&ifxmips_wdt_driver);
}
module_init(init_ifxmips_wdt);
module_exit(exit_ifxmips_wdt);
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
MODULE_DESCRIPTION("ifxmips Watchdog");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);