[PATCH] AMCC Crypto4xx Device Driver v2]
James Hsiao
jhsiao at amcc.com
Thu Oct 30 10:54:25 EST 2008
Hi Josh,
Thanks for the prompt review.
I agree with most of your comments.
About change log:
I will add change log in V3 based V2. Is that acceptable?
About crypto4xx_alloc_sa
We check if sa_in_dma_addr and sa_out_dma_addr is 0 in the caller
function. I will change the function to return error code.
About crypto4xx_memcpy_le:
Yes, I knew the problem, but this function is only used when copy items
in sa, which is always word aligned.
About counting interrupt:
That is some testing code for cheching interrupt coalescent. It should
be out since we didn't release the testing code.
Regards
James
On Wed, 2008-10-29 at 09:54 -0400, Josh Boyer wrote:
> On Tue, Oct 28, 2008 at 04:41:16PM -0700, James Hsiao wrote:
> >Hi Josh,
> >
> >I am reposting this patch. Thanks Kim Phillips for pointing out format
> >of my patch.
> >
> >Again this patch was already reviewed by Kim Phillips on linux-crypyo.
> >Kim suggest us submit to linuxppc-dev for review.
> >
> >Thanks
> >James
>
> You should have a changelog here that describes that the driver is,
> what hardware it is supporting, etc.
>
> >Signed-off-by: James Hsiao <jhsiao at amcc.com>
> >---
> > arch/powerpc/boot/dts/kilauea.dts | 10 +-
> > drivers/crypto/Kconfig | 9 +
> > drivers/crypto/Makefile | 1 +
> > drivers/crypto/amcc/Makefile | 27 +
> > drivers/crypto/amcc/crypto4xx_alg.c | 404 ++++++++++
> > drivers/crypto/amcc/crypto4xx_core.c | 1220 +++++++++++++++++++++++++++++++
> > drivers/crypto/amcc/crypto4xx_core.h | 200 +++++
> > drivers/crypto/amcc/crypto4xx_reg_def.h | 291 ++++++++
> > drivers/crypto/amcc/crypto4xx_sa.c | 98 +++
> > drivers/crypto/amcc/crypto4xx_sa.h | 223 ++++++
> > 10 files changed, 2482 insertions(+), 1 deletions(-)
> > create mode 100644 drivers/crypto/amcc/Makefile
> > create mode 100644 drivers/crypto/amcc/crypto4xx_alg.c
> > create mode 100644 drivers/crypto/amcc/crypto4xx_core.c
> > create mode 100644 drivers/crypto/amcc/crypto4xx_core.h
> > create mode 100644 drivers/crypto/amcc/crypto4xx_reg_def.h
> > create mode 100644 drivers/crypto/amcc/crypto4xx_sa.c
> > create mode 100644 drivers/crypto/amcc/crypto4xx_sa.h
> >
> >diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts
> >index dececc4..58b48a0 100644
> >--- a/arch/powerpc/boot/dts/kilauea.dts
> >+++ b/arch/powerpc/boot/dts/kilauea.dts
> >@@ -1,4 +1,4 @@
> >-/*
> >+/*
> > * Device Tree Source for AMCC Kilauea (405EX)
> > *
> > * Copyright 2007 DENX Software Engineering, Stefan Roese <sr at denx.de>
>
> Unneeded hunk.
>
> >@@ -94,6 +94,14 @@
> > dcr-reg = <0x010 0x002>;
> > };
> >
> >+ CRYPTO: crypto at ef700000 {
> >+ device_type = "crypto";
>
> Drop the device_type.
>
> >+ compatible = "amcc,ppc4xx-crypto";
> >+ reg = <0xef700000 0x80400>;
> >+ interrupt-parent = <&UIC0>;
> >+ interrupts = <0x17 0x2>;
> >+ };
> >+
> > MAL0: mcmal {
> > compatible = "ibm,mcmal-405ex", "ibm,mcmal2";
> > dcr-reg = <0x180 0x062>;
> >diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> >index e522144..d761664 100644
> >--- a/drivers/crypto/Kconfig
> >+++ b/drivers/crypto/Kconfig
> >@@ -200,4 +200,13 @@ config CRYPTO_DEV_IXP4XX
> > help
> > Driver for the IXP4xx NPE crypto engine.
> >
> >+config CRYPTO_DEV_PPC4XX
> >+ tristate "Driver AMCC PPC4XX crypto accelerator"
>
> "Driver for the AMCC PPC4xx crypto accelerator"
>
> >+ depends on PPC && 4xx
> >+ select CRYPTO_HASH
> >+ select CRYPTO_ALGAPI
> >+ select CRYPTO_BLKCIPHER
> >+ help
> >+ This option allows you to have support for AMCC crypto acceleration.
> >+
> > endif # CRYPTO_HW
>
> >diff --git a/drivers/crypto/amcc/Makefile b/drivers/crypto/amcc/Makefile
> >new file mode 100644
> >index 0000000..4b06655
> >--- /dev/null
> >+++ b/drivers/crypto/amcc/Makefile
> >@@ -0,0 +1,27 @@
> >+################################################################################
> >+# (C) Copyright 2007 Applied Micro Circuits Corporation
> >+# James Hsiao, AMCC, support at amcc.com
> >+#
> >+# 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
> >+#
> >+################################################################################
>
> This is a stylistic nit, but you don't need the bit long '########' lines. And
> really, the whole comment block just makes the file longer and it's really needed.
>
> >+#
> >+# Makefile for the AMCC Crypto Acclerator Device Driver
> >+#
> >+
> >+obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
> >+
> >+crypto4xx-objs := crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
>
> >diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
> >new file mode 100644
> >index 0000000..7dfe6a6
> >--- /dev/null
> >+++ b/drivers/crypto/amcc/crypto4xx_alg.c
> >@@ -0,0 +1,404 @@
> >+/*****************************************************************************
> >+ * AMCC SoC Crypto4XX Driver
> >+ *
> >+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
> >+ * All rights reserved. James Hsiao <jhsiao at amcc.com>
> >+ *
> >+ * 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.
> >+ *
> >+ * @file crypto4xx_alg.c
> >+ *
> >+ * This file implements the Linux crypto algorithms.
> >+ *
> >+ *****************************************************************************
> >+ */
>
> Same comment here about the long '*****' lines.
>
> >+#include <linux/kernel.h>
> >+#include <linux/module.h>
> >+#include <linux/moduleparam.h>
> >+#include <linux/mod_devicetable.h>
> >+#include <linux/interrupt.h>
> >+#include <linux/spinlock_types.h>
> >+#include <linux/highmem.h>
> >+#include <linux/scatterlist.h>
> >+#include <linux/crypto.h>
> >+#include <linux/hash.h>
> >+#include <crypto/internal/hash.h>
> >+#include <linux/pci.h>
> >+#include <linux/rtnetlink.h>
> >+#include <crypto/aead.h>
> >+#include <crypto/algapi.h>
> >+#include <crypto/des.h>
> >+#include <crypto/authenc.h>
> >+
> >+#include "crypto4xx_reg_def.h"
> >+#include "crypto4xx_sa.h"
> >+#include "crypto4xx_core.h"
> >+
> >+static inline int crypto4xx_encrypt(struct ablkcipher_request *req)
>
> Called via indirect function pointers. Not an inline function.
>
> >+{
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
> >+ struct crypto4xx_ctx *rctx = ablkcipher_request_ctx(req);
> >+ int rc;
> >+
> >+ /*
> >+ * Application only provided ptr for the rctx
> >+ * we alloc memory for it.
> >+ * And along we alloc memory for the sa in it.
> >+ */
> >+ ctx->use_rctx = 1;
> >+ ctx->direction = CRYPTO_OUTBOUND;
> >+ rc = crypto4xx_alloc_sa_rctx(ctx, rctx);
> >+ if (rc)
> >+ goto err_nomem;
> >+ memcpy((void *)(rctx->sa_out +
> >+ get_dynamic_sa_offset_state_ptr_field(rctx)),
> >+ (void *)&(rctx->state_record_dma_addr), 4);
>
> Do you really need the (void *) casts? Same comment elsewhere.
>
> >+ /* copy req->iv to state_record->iv */
> >+ if (req->info)
> >+ crypto4xx_memcpy_le(rctx->state_record, req->info,
> >+ get_dynamic_sa_iv_size(rctx));
> >+ else
> >+ memset(rctx->state_record, 0, get_dynamic_sa_iv_size(rctx));
> >+ rctx->hash_final = 0;
> >+ rctx->is_hash = 0;
> >+ rctx->pd_ctl = 0x1;
> >+ rctx->direction = CRYPTO_OUTBOUND;
> >+
> >+ return crypto4xx_handle_req(&req->base);
> >+
> >+err_nomem:
> >+ return -ENOMEM;
> >+}
> >+
> >+static inline int crypto4xx_decrypt(struct ablkcipher_request *req)
>
> Called via indirect function pointers. Not an inline function.
>
> >+{
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
> >+ struct crypto4xx_ctx *rctx = ablkcipher_request_ctx(req);
> >+ int rc;
> >+
> >+ /*
> >+ * Application only provided ptr for the rctx
> >+ * we alloc memory for it.
> >+ * And along we alloc memory for the sa in it
> >+ */
> >+ ctx->use_rctx = 1;
> >+ ctx->direction = CRYPTO_INBOUND;
> >+ rc = crypto4xx_alloc_sa_rctx(ctx, rctx);
> >+ if (rc != 0)
> >+ goto err_nomem;
> >+
> >+ memcpy((void *)(rctx->sa_in +
> >+ get_dynamic_sa_offset_state_ptr_field(rctx)),
> >+ (void *)&(rctx->state_record_dma_addr), 4);
> >+ /* copy req->iv to state_record->iv */
> >+ if (req->info)
> >+ crypto4xx_memcpy_le(rctx->state_record, req->info,
> >+ get_dynamic_sa_iv_size(rctx));
> >+ else
> >+ memset(rctx->state_record, 0, get_dynamic_sa_iv_size(rctx));
> >+
> >+ rctx->hash_final = 0;
> >+ rctx->is_hash = 0;
> >+ rctx->pd_ctl = 1;
> >+ rctx->direction = CRYPTO_INBOUND;
> >+
> >+ return crypto4xx_handle_req(&req->base);
> >+
> >+err_nomem:
> >+ return -ENOMEM;
> >+}
> >+
> >+/**
> >+ * AES Functions
> >+ *
> >+ */
> >+static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher,
> >+ const u8 *key,
> >+ unsigned int keylen,
> >+ unsigned char cm,
> >+ u8 fb)
> >+{
> >+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
> >+ struct dynamic_sa_ctl *sa;
> >+ int rc;
> >+
> >+ if ((keylen != 256/8) && (keylen != 128/8) && (keylen != 192/8)) {
> >+ crypto_ablkcipher_set_flags(cipher,
> >+ CRYPTO_TFM_RES_BAD_KEY_LEN);
> >+ return -1;
> >+ }
> >+
> >+ /* Create SA */
> >+ if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
> >+ crypto4xx_free_sa(ctx);
> >+
> >+ if (keylen == 256/8)
> >+ crypto4xx_alloc_sa(ctx, SA_AES256_LEN);
> >+ else if (keylen == 192/8)
> >+ crypto4xx_alloc_sa(ctx, SA_AES192_LEN);
> >+ else
> >+ crypto4xx_alloc_sa(ctx, SA_AES128_LEN);
> >+
> >+ if (!ctx->sa_in_dma_addr || !ctx->sa_out_dma_addr)
> >+ goto err_nomem;
> >+ if (ctx->state_record_dma_addr == 0) {
> >+ rc = crypto4xx_alloc_state_record(ctx);
> >+ if (rc != 0)
> >+ goto err_nomem_sr;
> >+ }
> >+ /* Setup SA */
> >+ sa = (struct dynamic_sa_ctl *)(ctx->sa_in);
> >+ ctx->hash_final = 0;
> >+ sa->sa_command_0.bf.hash_alg = SA_HASH_ALG_NULL;
> >+ sa->sa_command_0.bf.cipher_alg = SA_CIPHER_ALG_AES;
> >+ sa->sa_command_0.bf.opcode = SA_OPCODE_ENCRYPT;
> >+ sa->sa_command_0.bf.load_iv = 2;
> >+
> >+ sa->sa_command_1.bf.sa_rev = 1;
> >+ sa->sa_command_1.bf.copy_payload = 0;
> >+ sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2;
> >+ sa->sa_command_1.bf.crypto_mode9_8 = (cm & 3);
> >+ sa->sa_command_1.bf.feedback_mode = fb;
> >+ sa->sa_command_1.bf.mutable_bit_proc = 1;
> >+
> >+ if (keylen >= 256/8) {
> >+ crypto4xx_memcpy_le(((struct dynamic_sa_aes256 *)sa)->key,
> >+ key, keylen);
> >+ sa->sa_contents = SA_AES256_CONTENTS;
> >+ sa->sa_command_1.bf.key_len = SA_AES_KEY_LEN_256;
> >+ } else if (keylen >= 192/8) {
> >+ crypto4xx_memcpy_le(((struct dynamic_sa_aes192 *)sa)->key,
> >+ key, keylen);
> >+ sa->sa_contents = SA_AES192_CONTENTS;
> >+ sa->sa_command_1.bf.key_len = SA_AES_KEY_LEN_192;
> >+ } else {
> >+ crypto4xx_memcpy_le(((struct dynamic_sa_aes128 *)sa)->key,
> >+ key, keylen);
> >+ sa->sa_contents = SA_AES128_CONTENTS;
> >+ sa->sa_command_1.bf.key_len = SA_AES_KEY_LEN_128;
> >+ }
> >+ ctx->is_hash = 0;
> >+ ctx->direction = CRYPTO_INBOUND;
> >+ sa->sa_command_0.bf.dir = CRYPTO_INBOUND;
> >+ memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
> >+ (void *)&(ctx->state_record_dma_addr), 4);
> >+ memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len*4);
> >+ sa = (struct dynamic_sa_ctl *)(ctx->sa_out);
> >+ sa->sa_command_0.bf.dir = CRYPTO_OUTBOUND;
> >+
> >+ return 0;
> >+
> >+err_nomem_sr:
> >+ crypto4xx_free_sa(ctx);
> >+
> >+err_nomem:
> >+ return -ENOMEM;
> >+
> >+}
> >+
> >+static inline int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher,
> >+ const u8 *key, unsigned int keylen)
>
> Called via indirect function pointers. Not an inline function.
>
> >+{
> >+ return crypto4xx_setkey_aes(cipher, key, keylen,
> >+ CRYPTO_MODE_CBC,
> >+ CRYPTO_FEEDBACK_MODE_NO_FB);
> >+}
> >+
> >+/**
> >+ * HASH SHA1 Functions
> >+ *
> >+ */
> >+static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
> >+ unsigned int sa_len,
> >+ unsigned char ha,
> >+ unsigned char hm)
> >+{
> >+ struct crypto_alg *alg = tfm->__crt_alg;
> >+ struct crypto4xx_alg *my_alg = crypto_alg_to_crypto4xx_alg(alg);
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
> >+ struct dynamic_sa_ctl *sa;
> >+
> >+ ctx->dev = my_alg->dev;
> >+ ctx->is_hash = 1;
> >+ ctx->hash_final = 0;
> >+
> >+ /* Create SA */
> >+ if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
> >+ crypto4xx_free_sa(ctx);
> >+
> >+ crypto4xx_alloc_sa(ctx, sa_len);
> >+ if (!ctx->sa_in_dma_addr || !ctx->sa_out_dma_addr)
> >+ goto err_nomem;
> >+
> >+ if (ctx->state_record_dma_addr == 0) {
> >+ crypto4xx_alloc_state_record(ctx);
> >+ if (!ctx->state_record_dma_addr)
> >+ goto err_nomem_sr;
> >+ }
> >+
> >+ tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx);
> >+ sa = (struct dynamic_sa_ctl *)(ctx->sa_in);
> >+
> >+ /* Setup hash algorithm and hash mode */
> >+ sa->sa_command_0.w = 0;
> >+ sa->sa_command_0.bf.hash_alg = ha;
> >+ sa->sa_command_0.bf.gather = 0;
> >+ sa->sa_command_0.bf.save_hash_state = 1;
> >+ sa->sa_command_0.bf.cipher_alg = SA_CIPHER_ALG_NULL;
> >+ sa->sa_command_0.bf.opcode = SA_OPCODE_HASH;
> >+
> >+ /* load hash state set to no load, since we don't no init idigest */
> >+ sa->sa_command_0.bf.load_hash_state = 3;
> >+ sa->sa_command_0.bf.dir = 0;
> >+ sa->sa_command_0.bf.opcode = SA_OPCODE_HASH;
> >+ sa->sa_command_1.w = 0;
> >+ sa->sa_command_1.bf.hmac_muting = 0;
> >+ /* dynamic sa, need to set it to rev 2 */
> >+ sa->sa_command_1.bf.sa_rev = 1;
> >+ sa->sa_command_1.bf.copy_payload = 0;
> >+ sa->sa_command_1.bf.mutable_bit_proc = 1;
> >+
> >+ /* Need to zero hash digest in SA */
> >+ if (ha == SA_HASH_ALG_SHA1) {
> >+ sa->sa_contents = SA_HASH160_CONTENTS;
> >+ memset(((struct dynamic_sa_hash160 *)
> >+ (ctx->sa_in))->inner_digest, 0, 20);
> >+ memset(((struct dynamic_sa_hash160 *)
> >+ (ctx->sa_in))->outer_digest, 0, 20);
> >+ ((struct dynamic_sa_hash160 *)(ctx->sa_in))->state_ptr
> >+ = ctx->state_record_dma_addr;
> >+ } else {
> >+ printk(KERN_ERR "ERROR: invalid hash"
> >+ " algorithm used \n");
> >+ }
> >+
> >+ return 0;
> >+
> >+err_nomem_sr:
> >+ crypto4xx_free_sa(ctx);
> >+err_nomem:
> >+ return -ENOMEM;
> >+
> >+}
> >+
> >+static int crypto4xx_hash_init(struct ahash_request *req)
> >+{
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
> >+ int ds;
> >+ struct dynamic_sa_ctl *sa;
> >+
> >+ ctx->use_rctx = 0;
> >+ sa = (struct dynamic_sa_ctl *)(ctx->sa_in);
> >+ ds = crypto_ahash_digestsize(
> >+ __crypto_ahash_cast(req->base.tfm));
> >+ sa->sa_command_0.bf.digest_len = ds>>2;
> >+ sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
> >+ ctx->is_hash = 1;
> >+ ctx->direction = CRYPTO_INBOUND;
> >+
> >+ return 0;
> >+}
> >+
> >+static int crypto4xx_hash_update(struct ahash_request *req)
> >+{
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
> >+
> >+ ctx->is_hash = 1;
> >+ ctx->hash_final = 0;
> >+ ctx->use_rctx = 0;
> >+ ctx->pd_ctl = 0x11;
> >+ ctx->direction = CRYPTO_INBOUND;
> >+ return crypto4xx_handle_req(&req->base);
> >+}
> >+
> >+static int crypto4xx_hash_final(struct ahash_request *req)
> >+{
> >+ struct crypto4xx_ctx *rctx = ahash_request_ctx(req);
> >+
> >+ crypto4xx_free_sa_rctx(rctx);
> >+ return 0;
> >+}
> >+
> >+static int crypto4xx_hash_digest(struct ahash_request *req)
> >+{
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
> >+ ctx->use_rctx = 0;
> >+ ctx->hash_final = 1;
> >+ ctx->pd_ctl = 0x11;
> >+ ctx->direction = CRYPTO_INBOUND;
> >+ return crypto4xx_handle_req(&req->base);
> >+}
> >+
> >+/**
> >+ * SHA1 and SHA2 Algorithm
> >+ */
> >+static int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm)
> >+{
> >+ return crypto4xx_hash_alg_init(tfm,
> >+ SA_HASH160_LEN,
> >+ SA_HASH_ALG_SHA1,
> >+ SA_HASH_MODE_HASH);
> >+}
> >+
> >+/**
> >+ * Support Crypto Algorithms
> >+ */
> >+struct crypto_alg crypto4xx_basic_alg[] = {
> >+
> >+ /* Crypto AES modes */
> >+ {.cra_name = "cbc(aes)",
> >+ .cra_driver_name = "cbc-aes-ppc4xx",
> >+ .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
> >+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
> >+ .cra_blocksize = 16, /* 128-bits block */
> >+ .cra_ctxsize = sizeof(struct crypto4xx_ctx),
> >+ .cra_alignmask = 0,
> >+ .cra_type = &crypto_ablkcipher_type,
> >+ .cra_module = THIS_MODULE,
> >+ .cra_u = {.ablkcipher = {
> >+ .min_keysize = 16, /* AES min key size is 128-bits */
> >+ .max_keysize = 32, /* AES max key size is 256-bits */
> >+ .ivsize = 16, /* IV size is 16 bytes */
> >+ .setkey = crypto4xx_setkey_aes_cbc,
> >+ .encrypt = crypto4xx_encrypt,
> >+ .decrypt = crypto4xx_decrypt,
> >+ } }
> >+ },
> >+ /* Hash SHA1, SHA2 */
> >+ {.cra_name = "sha1",
> >+ .cra_driver_name = "sha1-ppc4xx",
> >+ .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
> >+ .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
> >+ .cra_blocksize = 64, /* SHA1 block size is 512-bits */
> >+ .cra_ctxsize = sizeof(struct crypto4xx_ctx),
> >+ .cra_alignmask = 0,
> >+ .cra_type = &crypto_ahash_type,
> >+ .cra_init = crypto4xx_sha1_alg_init,
> >+ .cra_module = THIS_MODULE,
> >+ .cra_u = {.ahash = {
> >+ .digestsize = 20, /* Disgest is 160-bits */
> >+ .init = crypto4xx_hash_init,
> >+ .update = crypto4xx_hash_update,
> >+ .final = crypto4xx_hash_final,
> >+ .digest = crypto4xx_hash_digest,
> >+ } }
> >+ },
> >+};
> >+
> >+int crypto4xx_register_basic_alg(void)
> >+{
> >+ return crypto4xx_register_alg(&lsec_core.dev,
> >+ crypto4xx_basic_alg,
> >+ ARRAY_SIZE(crypto4xx_basic_alg));
> >+}
> >+
> >diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
> >new file mode 100644
> >index 0000000..7845a25
> >--- /dev/null
> >+++ b/drivers/crypto/amcc/crypto4xx_core.c
> >@@ -0,0 +1,1220 @@
> >+/****************************************************************************
> >+ * AMCC SoC Crypto4XX Driver
> >+ *
> >+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
> >+ * All rights reserved. James Hsiao <jhsiao at amcc.com>
> >+ *
> >+ * 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.
> >+ *
> >+ * @file crypto4xx_core.c
> >+ *
> >+ * This file implements AMCC crypto offload Linux device driver for use with
> >+ * Linux CryptoAPI.
> >+ *
> >+ ****************************************************************************
> >+ */
> >+
> >+#include <linux/kernel.h>
> >+#include <linux/module.h>
> >+#include <linux/moduleparam.h>
> >+#include <linux/mod_devicetable.h>
> >+#include <linux/interrupt.h>
> >+#include <linux/completion.h>
> >+#include <linux/spinlock_types.h>
> >+#include <linux/highmem.h>
> >+#include <linux/random.h>
> >+#include <linux/scatterlist.h>
> >+#include <linux/crypto.h>
> >+#include <crypto/algapi.h>
> >+#include <crypto/des.h>
> >+#include <linux/slab.h>
> >+#include <linux/pci.h>
> >+#include <linux/platform_device.h>
> >+#include <linux/proc_fs.h>
> >+#include <linux/timer.h>
> >+#include <linux/of_platform.h>
> >+#include <asm/dcr.h>
> >+#include <asm/dcr-regs.h>
> >+#include <asm/cacheflush.h>
> >+#include <crypto/internal/hash.h>
> >+#include "crypto4xx_reg_def.h"
> >+#include "crypto4xx_core.h"
> >+#include "crypto4xx_sa.h"
> >+
> >+#define CRYPTO4XX_CRYPTO_PRIORITY 300
> >+#define PPC4XX_SEC_VERSION_STR "0.1"
> >+
> >+struct crypto4xx_core_device lsec_core;
>
> I realize your driver only supports one device at a time,
> but I still think you should follow Kim's advice and put
> this as part of the struct device.
>
> >+
> >+u32 crypto4xx_write32(u32 reg, u32 val)
> >+{
> >+ writel(val, lsec_core.ce_base + reg);
> >+ return 0;
> >+}
> >+
> >+u32 crypto4xx_read32(u32 reg, u32 *val)
> >+{
> >+ *val = readl(lsec_core.ce_base + reg);
> >+ return 0;
> >+}
>
> The writel/readl wrappers are little-endian. Is that
> what you expect? Also, you seem to have introduced
> these wrappers for really no need. We have ioread32
> and iowrite32 for little-endian I/O, and ioread32be
> and iowrite32be for big-endian I/O. Is there a
> reason you can't just use those everywhere you are
> using these wrappers?
>
>
> >+
> >+/**
> >+ * PPC4XX Crypto Engine Initialization Routine
> >+ */
> >+int32_t crypto4xx_init(struct crypto4xx_device *dev)
>
> This can be a static function. Also, why int32_t as the return type?
> A regular 'int' shoud be just fine.
>
> >+{
> >+ u32 rc = 0;
> >+ union ce_ring_size ring_size;
> >+ union ce_ring_contol ring_ctrl;
> >+ union ce_part_ring_size part_ring_size;
> >+ union ce_io_threshold io_threshold;
> >+ u32 rand_num;
> >+
> >+ union ce_pe_dma_cfg pe_dma_cfg;
> >+ if ((cur_cpu_spec->pvr_value & 0xffff0000) == 0x13020000) {
> >+ mtdcri(SDR0, 0x201, mfdcri(SDR0, 0x201) | 0x08000000);
> >+ mtdcri(SDR0, 0x201, mfdcri(SDR0, 0x201) & ~0x08000000);
> >+ } else if ((cur_cpu_spec->pvr_value & 0xffff0000) == 0x12910000) {
> >+ mtdcri(SDR0, 0x200, mfdcri(SDR0, 0x200) | 0x00000008);
> >+ mtdcri(SDR0, 0x200, mfdcri(SDR0, 0x200) & ~0x00000008);
> >+ } else if ((cur_cpu_spec->pvr_value & 0xffff0000) == 0x13540000) {
> >+ mtdcri(SDR0, 0x201, mfdcri(SDR0, 0x201) | 0x20000000);
> >+ mtdcri(SDR0, 0x201, mfdcri(SDR0, 0x201) & ~0x20000000);
> >+ } else {
> >+ printk(KERN_ERR "Crypto Function Not supported!\n");
> >+ return -EINVAL;
> >+ }
>
> What are you doing with these magic PVR lookups and values? First,
> you should be at least using symbolic #defines so the values are at
> least somewhat descriptive.
>
> Secondly, you should probably be using the device tree here instead
> of doing the PVR compare. Something like getting the CPU model
> property and doing the if/else based on that. You might have to
> move this out into the probe function.
>
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_BYTE_ORDER_CFG, 0x22222);
> >+
> >+ /* setup pe dma, include reset sg, pdr and pe, then release reset */
> >+ pe_dma_cfg.w = 0;
> >+
> >+ pe_dma_cfg.bf.bo_sgpd_en = 1;
> >+ pe_dma_cfg.bf.bo_data_en = 0;
> >+ pe_dma_cfg.bf.bo_sa_en = 1;
> >+ pe_dma_cfg.bf.bo_pd_en = 1;
> >+
> >+ pe_dma_cfg.bf.dynamic_sa_en = 1;
> >+ pe_dma_cfg.bf.reset_sg = 1;
> >+ pe_dma_cfg.bf.reset_pdr = 1;
> >+ pe_dma_cfg.bf.reset_pe = 1;
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_PE_DMA_CFG, pe_dma_cfg.w);
> >+
> >+ /* un reset pe,sg and pdr */
> >+ pe_dma_cfg.bf.pe_mode = 0;
> >+ pe_dma_cfg.bf.reset_sg = 0;
> >+ pe_dma_cfg.bf.reset_pdr = 0;
> >+ pe_dma_cfg.bf.reset_pe = 0;
> >+ pe_dma_cfg.bf.bo_td_en = 0;
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_PE_DMA_CFG, pe_dma_cfg.w);
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_PDR_BASE, dev->pdr_pa);
> >+ crypto4xx_write32(CRYPTO_ENGINE_RDR_BASE, dev->pdr_pa);
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_PRNG_CTRL, 3);
> >+ get_random_bytes(&rand_num, sizeof(rand_num));
> >+ crypto4xx_write32(CRYPTO_ENGINE_PRNG_SEED_L, rand_num);
> >+ get_random_bytes(&rand_num, sizeof(rand_num));
> >+ crypto4xx_write32(CRYPTO_ENGINE_PRNG_SEED_L, rand_num);
> >+
> >+ ring_size.w = 0;
> >+ ring_size.bf.ring_offset = PPC4XX_PD_SIZE;
> >+ ring_size.bf.ring_size = PPC4XX_NUM_PD;
> >+ crypto4xx_write32(CRYPTO_ENGINE_RING_SIZE, ring_size.w);
> >+
> >+ ring_ctrl.w = 0;
> >+ crypto4xx_write32(CRYPTO_ENGINE_RING_CTRL, ring_ctrl.w);
> >+ crypto4xx_write32(CRYPTO_ENGINE_DC_CTRL, 1);
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_GATH_RING_BASE, dev->gdr_pa);
> >+ crypto4xx_write32(CRYPTO_ENGINE_SCAT_RING_BASE, dev->sdr_pa);
> >+
> >+ part_ring_size.w = 0;
> >+ part_ring_size.bf.sdr_size = PPC4XX_SDR_SIZE;
> >+ part_ring_size.bf.gdr_size = PPC4XX_GDR_SIZE;
> >+ crypto4xx_write32(CRYPTO_ENGINE_PART_RING_SIZE, part_ring_size.w);
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_PART_RING_CFG,
> >+ 0x0000ffff & PPC4XX_SD_BUFFER_SIZE);
> >+ io_threshold.w = 0;
> >+ io_threshold.bf.output_threshold = PPC4XX_OUTPUT_THRESHOLD;
> >+ io_threshold.bf.input_threshold = PPC4XX_INPUT_THRESHOLD;
> >+ crypto4xx_write32(CRYPTO_ENGINE_IO_THRESHOLD, io_threshold.w);
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_PDR_BASE_UADDR, 0x0);
> >+ crypto4xx_write32(CRYPTO_ENGINE_RDR_BASE_UADDR, 0x0);
> >+ crypto4xx_write32(CRYPTO_ENGINE_PKT_SRC_UADDR, 0x0);
> >+ crypto4xx_write32(CRYPTO_ENGINE_PKT_DEST_UADDR, 0x0);
> >+ crypto4xx_write32(CRYPTO_ENGINE_SA_UADDR, 0x0);
> >+ crypto4xx_write32(CRYPTO_ENGINE_GATH_RING_BASE_UADDR, 0x0);
> >+ crypto4xx_write32(CRYPTO_ENGINE_SCAT_RING_BASE_UADDR, 0x0);
> >+
> >+ /* un reset pe,sg and pdr */
> >+ pe_dma_cfg.bf.pe_mode = 1;
> >+ pe_dma_cfg.bf.reset_sg = 0;
> >+ pe_dma_cfg.bf.reset_pdr = 0;
> >+ pe_dma_cfg.bf.reset_pe = 0;
> >+ pe_dma_cfg.bf.bo_td_en = 0;
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_PE_DMA_CFG, pe_dma_cfg.w);
> >+ /*clear all pending interrupt*/
> >+ crypto4xx_write32(CRYPTO_ENGINE_INT_CLR, 0x3ffff);
> >+ crypto4xx_write32(CRYPTO_ENGINE_INT_DESCR_CNT, PPC4XX_INT_DESCR_CNT);
> >+
> >+ crypto4xx_write32(CRYPTO_ENGINE_INT_TIMEOUT_CNT,
> >+ PPC4XX_INT_TIMEOUT_CNT);
> >+ crypto4xx_write32(CRYPTO_ENGINE_INT_CFG, PPC4XX_INT_CFG);
> >+ crypto4xx_write32(CRYPTO_ENGINE_INT_EN, CRYPTO_PD_DONE_INT);
> >+
> >+ return rc;
> >+}
> >+
> >+void crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size)
> >+{
> >+ ctx->sa_in = dma_alloc_coherent(NULL, size * 4,
> >+ &ctx->sa_in_dma_addr, GFP_ATOMIC);
> >+ ctx->sa_out = dma_alloc_coherent(NULL, size * 4,
> >+ &ctx->sa_out_dma_addr, GFP_ATOMIC);
> >+ ctx->sa_len = size;
>
> dma_alloc_coherent can fail and return NULL. You don't handle that here
> or anywhere you call this function from what I can tell.
>
> >+}
> >+
> >+void crypto4xx_free_sa(struct crypto4xx_ctx *ctx)
> >+{
> >+ if (ctx->sa_in != NULL)
> >+ dma_free_coherent(NULL, ctx->sa_len*4,
> >+ ctx->sa_in, ctx->sa_in_dma_addr);
> >+ if (ctx->sa_out != NULL)
> >+ dma_free_coherent(NULL, ctx->sa_len*4,
> >+ ctx->sa_out, ctx->sa_out_dma_addr);
> >+
> >+ ctx->sa_in_dma_addr = 0;
> >+ ctx->sa_out_dma_addr = 0;
> >+ ctx->sa_len = 0;
> >+}
> >+
> >+u32 crypto4xx_alloc_state_record(struct crypto4xx_ctx *ctx)
> >+{
> >+ ctx->state_record = dma_alloc_coherent(NULL,
> >+ sizeof(struct dynamic_sa_state_record),
> >+ &ctx->state_record_dma_addr, GFP_ATOMIC);
> >+ if (!ctx->state_record_dma_addr)
> >+ return -ENOMEM;
> >+ memset(ctx->state_record, 0, sizeof(struct dynamic_sa_state_record));
> >+ return 0;
> >+}
> >+
> >+void crypto4xx_free_state_record(struct crypto4xx_ctx *ctx)
> >+{
> >+ if (ctx->state_record != NULL)
> >+ dma_free_coherent(NULL,
> >+ sizeof(struct dynamic_sa_state_record),
> >+ ctx->state_record,
> >+ ctx->state_record_dma_addr);
> >+ ctx->state_record_dma_addr = 0;
> >+}
> >+
> >+/**
> >+ * alloc memory for the gather ring
> >+ * no need to alloc buf for the ring
> >+ * gdr_tail, gdr_head and gdr_count are initialized by this function
> >+ */
> >+u32 crypto4xx_build_pdr(struct crypto4xx_device *dev)
> >+{
> >+ dev->pdr = dma_alloc_coherent(NULL,
> >+ sizeof(struct ce_pd) * PPC4XX_NUM_PD,
> >+ &dev->pdr_pa, GFP_ATOMIC);
> >+ if (!dev->pdr)
> >+ return -ENOMEM;
> >+ dev->pdr_uinfo = kzalloc(sizeof(struct pd_uinfo) * PPC4XX_NUM_PD,
> >+ GFP_KERNEL);
> >+ if (!dev->pdr_uinfo)
> >+ return -ENOMEM;
> >+
> >+ memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD);
> >+ return 0;
> >+}
> >+
> >+void crypto4xx_destroy_pdr(struct crypto4xx_device *dev)
> >+{
> >+ if (dev->pdr != NULL)
> >+ dma_free_coherent(NULL,
> >+ sizeof(struct ce_pd) * PPC4XX_NUM_PD,
> >+ dev->pdr,
> >+ dev->pdr_pa);
> >+ if (dev->pdr_uinfo != NULL)
> >+ kfree(dev->pdr_uinfo);
> >+}
> >+
> >+u32 crypto4xx_get_pd_from_pdr(struct crypto4xx_device *dev)
> >+{
> >+ u32 retval;
> >+ u32 tmp;
> >+
> >+ retval = dev->pdr_head;
> >+ tmp = (dev->pdr_head + 1) % PPC4XX_NUM_PD;
> >+
> >+ if (tmp == dev->pdr_tail)
> >+ return ERING_WAS_FULL;
> >+ dev->pdr_head = tmp;
> >+
> >+ return retval;
> >+}
> >+
> >+
> >+u32 crypto4xx_put_pd_to_pdr(struct crypto4xx_device *dev, u32 idx)
> >+{
> >+ struct pd_uinfo *pd_uinfo;
> >+
> >+ pd_uinfo = (struct pd_uinfo *)((dev->pdr_uinfo) +
> >+ sizeof(struct pd_uinfo)*idx);
> >+
> >+ if (dev->pdr_tail != PPC4XX_LAST_PD)
> >+ dev->pdr_tail++;
> >+ else
> >+ dev->pdr_tail = 0;
> >+ pd_uinfo->state = PD_ENTRY_FREE;
> >+
> >+ return 0;
> >+}
> >+
> >+struct ce_pd *crypto4xx_get_pdp(struct crypto4xx_device *dev,
> >+ dma_addr_t *pd_dma, u32 idx)
>
> Should be static. And maybe inline.
>
> >+{
> >+ *pd_dma = dev->pdr_pa + sizeof(struct ce_pd) * idx;
> >+ return dev->pdr + sizeof(struct ce_pd)*idx;
> >+}
> >+
> >+/**
> >+ * alloc memory for the gather ring
> >+ * no need to alloc buf for the ring
> >+ * gdr_tail, gdr_head and gdr_count are initialized by this function
> >+ */
> >+u32 crypto4xx_build_gdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ dev->gdr = dma_alloc_coherent(NULL,
> >+ sizeof(struct ce_gd) * PPC4XX_NUM_GD,
> >+ &dev->gdr_pa, GFP_ATOMIC);
> >+ if (!dev->gdr)
> >+ return -ENOMEM;
> >+ memset(dev->gdr, 0, sizeof(struct ce_gd) * PPC4XX_NUM_GD);
> >+ return 0;
> >+}
> >+
> >+void crypto4xx_destroy_gdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ dma_free_coherent(NULL,
> >+ sizeof(struct ce_gd) * PPC4XX_NUM_GD,
> >+ dev->gdr, dev->gdr_pa);
> >+}
> >+
> >+u32 crypto4xx_get_gd_from_gdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ u32 retval;
> >+ u32 tmp;
> >+
> >+ retval = dev->gdr_head;
> >+ tmp = (dev->gdr_head+1) % PPC4XX_NUM_GD;
> >+
> >+ if (tmp == dev->gdr_tail)
> >+ return ERING_WAS_FULL;
> >+ dev->gdr_head = tmp;
> >+ return retval;
> >+}
> >+
> >+u32 crypto4xx_put_gd_to_gdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ if (dev->gdr_tail == dev->gdr_head)
> >+ return 0;
> >+
> >+ if (dev->gdr_tail != PPC4XX_LAST_GD)
> >+ dev->gdr_tail++;
> >+ else
> >+ dev->gdr_tail = 0;
> >+
> >+ return 0;
> >+}
> >+
> >+struct ce_gd *crypto4xx_get_gdp(struct crypto4xx_device *dev,
> >+ dma_addr_t *gd_dma, u32 idx)
>
> Make static. And maybe inline.
>
> >+{
> >+ *gd_dma = dev->gdr_pa + sizeof(struct ce_gd)*idx;
> >+ return (struct ce_gd *) (dev->gdr + sizeof(struct ce_gd) * idx);
> >+}
> >+
> >+/**
> >+ * alloc memory for the scatter ring
> >+ * need to alloc buf for the ring
> >+ * sdr_tail, sdr_head and sdr_count are initialized by this function
> >+ */
> >+u32 crypto4xx_build_sdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ int i;
> >+ struct ce_sd *sd_array;
> >+ /* alloc memory for scatter descriptor ring */
> >+ dev->sdr = dma_alloc_coherent(NULL,
> >+ sizeof(struct ce_sd) * PPC4XX_NUM_SD,
> >+ &dev->sdr_pa, GFP_ATOMIC);
> >+ if (!dev->sdr)
> >+ return -ENOMEM;
> >+
> >+ dev->scatter_buffer_size = PPC4XX_SD_BUFFER_SIZE;
> >+ dev->scatter_buffer_va =
> >+ dma_alloc_coherent(NULL,
> >+ dev->scatter_buffer_size * PPC4XX_NUM_SD,
> >+ &dev->scatter_buffer_pa, GFP_ATOMIC);
> >+ if (!dev->scatter_buffer_va)
> >+ return -ENOMEM;
> >+
> >+ sd_array = dev->sdr;
> >+
> >+ for (i = 0; i < PPC4XX_NUM_SD; i++) {
> >+ sd_array[i].ptr = dev->scatter_buffer_pa +
> >+ dev->scatter_buffer_size * i;
> >+ }
> >+ return 0;
> >+}
> >+
> >+void crypto4xx_destroy_sdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ dma_free_coherent(NULL,
> >+ sizeof(struct ce_sd) * PPC4XX_NUM_SD,
> >+ dev->sdr,
> >+ dev->sdr_pa);
> >+
> >+ dma_free_coherent(NULL,
> >+ dev->scatter_buffer_size * PPC4XX_NUM_SD,
> >+ dev->scatter_buffer_va,
> >+ dev->scatter_buffer_pa);
> >+}
> >+
> >+u32 crypto4xx_get_sd_from_sdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ u32 retval;
> >+ u32 tmp;
> >+
> >+ retval = dev->sdr_head;
> >+ tmp = (dev->sdr_head+1) % PPC4XX_NUM_SD;
> >+
> >+ if (tmp == dev->sdr_tail)
> >+ return ERING_WAS_FULL;
> >+
> >+ dev->sdr_head = tmp;
> >+ return retval;
> >+}
> >+
> >+u32 crypto4xx_put_sd_to_sdr(struct crypto4xx_device *dev)
>
> Make static.
>
> >+{
> >+ if (dev->sdr_tail == dev->sdr_head)
> >+ return 0;
> >+
> >+ if (dev->sdr_tail != PPC4XX_LAST_SD)
> >+ dev->sdr_tail++;
> >+ else
> >+ dev->sdr_tail = 0;
> >+
> >+ return 0;
> >+}
> >+
> >+struct ce_sd *crypto4xx_get_sdp(struct crypto4xx_device *dev,
> >+ dma_addr_t *sd_dma, u32 idx)
>
> Make static. And maybe inline.
>
> >+{
> >+ *sd_dma = dev->sdr_pa + sizeof(struct ce_sd) * idx;
> >+ return (struct ce_sd *)(dev->sdr + sizeof(struct ce_sd) * idx);
> >+}
> >+
> >+u32 crypto4xx_fill_one_page(dma_addr_t *addr, u32 *length,
> >+ u32 *idx, u32 *offset, u32 *nbytes)
>
> Make static. This function also makes my eyes hurt, but I'll
> look at it more closely later.
>
> >+
> >+{
> >+ struct crypto4xx_device *dev = &(lsec_core.dev);
> >+ u32 len;
> >+ if ((*length) > dev->scatter_buffer_size) {
> >+ memcpy(phys_to_virt(*addr),
> >+ dev->scatter_buffer_va +
> >+ (*idx)*dev->scatter_buffer_size + (*offset),
> >+ dev->scatter_buffer_size);
> >+ *offset = 0;
> >+ *length -= dev->scatter_buffer_size;
> >+ *nbytes -= dev->scatter_buffer_size;
> >+ if (*idx == PPC4XX_LAST_SD)
> >+ *idx = 0;
> >+ else
> >+ (*idx)++;
> >+ *addr = *addr + dev->scatter_buffer_size;
> >+ return 1;
> >+ } else if ((*length) < dev->scatter_buffer_size) {
> >+ memcpy(phys_to_virt(*addr),
> >+ dev->scatter_buffer_va +
> >+ (*idx)*dev->scatter_buffer_size + (*offset),
> >+ *length);
> >+ if ((*offset + *length) == dev->scatter_buffer_size) {
> >+ if (*idx == PPC4XX_LAST_SD)
> >+ *idx = 0;
> >+ else
> >+ (*idx)++;
> >+ *nbytes -= *length;
> >+ *offset = 0;
> >+ } else {
> >+ *nbytes -= *length;
> >+ *offset += *length;
> >+ }
> >+
> >+ return 0;
> >+ } else {
> >+ len = (*nbytes <=
> >+ dev->scatter_buffer_size) ?
> >+ (*nbytes) : dev->scatter_buffer_size;
> >+ memcpy(phys_to_virt(*addr),
> >+ dev->scatter_buffer_va +
> >+ (*idx)*dev->scatter_buffer_size + (*offset),
> >+ len);
> >+ *offset = 0;
> >+ *nbytes -= len;
> >+
> >+ if (*idx == PPC4XX_LAST_SD)
> >+ *idx = 0;
> >+ else
> >+ (*idx)++;
> >+
> >+ return 0;
> >+ }
> >+}
> >+
> >+void crypto4xx_copy_pkt_to_dst(struct ce_pd *pd,
> >+ struct pd_uinfo *pd_uinfo,
> >+ u32 nbytes,
> >+ struct scatterlist *dst,
> >+ u8 type)
> >+{
>
> Make static.
>
> >+ struct crypto4xx_device *dev = &(lsec_core.dev);
> >+ dma_addr_t addr;
> >+ u32 this_sd;
> >+ u32 offset;
> >+ u32 len;
> >+ u32 i;
> >+ u32 sg_len;
> >+ struct scatterlist *sg;
> >+ this_sd = pd_uinfo->first_sd;
> >+ offset = 0;
> >+ i = 0;
> >+
> >+ while (nbytes) {
> >+ sg = &dst[i];
> >+ sg_len = sg->length;
> >+ addr = dma_map_page(NULL, sg_page(sg), sg->offset,
> >+ sg->length, DMA_TO_DEVICE);
> >+
> >+ if (offset == 0) {
> >+ len = (nbytes <= sg->length) ? nbytes : sg->length;
> >+ while (crypto4xx_fill_one_page(&addr, &len,
> >+ &this_sd, &offset, &nbytes))
> >+ ;
> >+ if (!nbytes)
> >+ return ;
> >+ i++;
> >+
> >+ } else {
> >+ len = (nbytes <= (dev->scatter_buffer_size - offset)) ?
> >+ nbytes : (dev->scatter_buffer_size - offset);
> >+ len = (sg->length < len) ? sg->length : len;
> >+ while (crypto4xx_fill_one_page(&addr,
> >+ &len, &this_sd, &offset, &nbytes))
> >+ ;
> >+ if (!nbytes)
> >+ return;
> >+ sg_len -= len;
> >+ if (sg_len) {
> >+ addr += len;
> >+ while (crypto4xx_fill_one_page(&addr, &sg_len,
> >+ &this_sd, &offset, &nbytes))
> >+ ;
> >+ }
> >+ i++;
> >+ }
> >+ }
> >+}
> >+
> >+u32 crypto4xx_copy_digest_to_dst(struct pd_uinfo *pd_uinfo,
> >+ struct crypto4xx_ctx *ctx)
>
> Make static.
>
> >+{
> >+ struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *)(ctx->sa_in);
> >+ struct dynamic_sa_state_record *state_record =
> >+ (struct dynamic_sa_state_record *)(ctx->state_record);
> >+
> >+ if (sa->sa_command_0.bf.hash_alg == SA_HASH_ALG_SHA1) {
> >+ memcpy((void *)pd_uinfo->dest_va, state_record->save_digest,
> >+ SA_HASH_ALG_SHA1_DIGEST_SIZE);
> >+ }
> >+ return 0;
> >+}
> >+
> >+
> >+void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev,
> >+ struct pd_uinfo *pd_uinfo)
>
> Make static.
>
> >+{
> >+ int i;
> >+ struct ce_sd *sd = NULL;
> >+
> >+ if (pd_uinfo->first_gd != 0xffffffff) {
> >+ if (pd_uinfo->first_gd <= pd_uinfo->last_gd) {
> >+ for (i = pd_uinfo->first_gd;
> >+ i <= pd_uinfo->last_gd; i++)
> >+ crypto4xx_put_gd_to_gdr(dev);
> >+
> >+ } else {
> >+ for (i = pd_uinfo->first_gd;
> >+ i < PPC4XX_NUM_GD; i++)
> >+ crypto4xx_put_gd_to_gdr(dev);
> >+ for (i = 0; i <= pd_uinfo->last_gd; i++)
> >+ crypto4xx_put_gd_to_gdr(dev);
> >+ }
> >+ }
> >+
> >+ if (pd_uinfo->first_sd != 0xffffffff) {
> >+ if (pd_uinfo->first_sd <= pd_uinfo->last_sd) {
> >+ for (i = pd_uinfo->first_sd;
> >+ i <= pd_uinfo->last_sd; i++) {
> >+ sd = (struct ce_sd *)(dev->sdr +
> >+ sizeof(struct ce_sd)*i);
> >+ sd->ctl.done = 0;
> >+ sd->ctl.rdy = 0;
> >+ crypto4xx_put_sd_to_sdr(dev);
> >+ }
> >+ } else {
> >+ for (i = pd_uinfo->first_sd; i < PPC4XX_NUM_SD; i++) {
> >+ sd = (struct ce_sd *)(dev->sdr +
> >+ sizeof(struct ce_sd)*i);
> >+ sd->ctl.done = 0;
> >+ sd->ctl.rdy = 0;
> >+ crypto4xx_put_sd_to_sdr(dev);
> >+ }
> >+ for (i = 0; i <= pd_uinfo->last_sd; i++) {
> >+ sd = (struct ce_sd *)(dev->sdr +
> >+ sizeof(struct ce_sd)*i);
> >+ sd->ctl.done = 0;
> >+ sd->ctl.rdy = 0;
> >+ crypto4xx_put_sd_to_sdr(dev);
> >+ }
> >+ }
> >+ }
> >+
> >+ pd_uinfo->first_gd = pd_uinfo->last_gd = 0xffffffff;
> >+ pd_uinfo->first_sd = pd_uinfo->last_sd = 0xffffffff;
> >+}
> >+
> >+
> >+u32 crypto4xx_ablkcipher_done(struct pd_uinfo *pd_uinfo, struct ce_pd *pd)
>
> Make static.
>
> >+{
> >+ struct crypto4xx_ctx *ctx;
> >+ struct crypto4xx_ctx *rctx = NULL;
> >+ struct ablkcipher_request *ablk_req;
> >+ struct scatterlist *dst;
> >+ dma_addr_t addr;
> >+
> >+ ablk_req = ablkcipher_request_cast(pd_uinfo->async_req);
> >+ ctx = crypto_tfm_ctx(ablk_req->base.tfm);
> >+
> >+ if (ctx->use_rctx == 1)
> >+ rctx = ablkcipher_request_ctx(ablk_req);
> >+
> >+ if (pd_uinfo->using_sd) {
> >+ crypto4xx_copy_pkt_to_dst(pd,
> >+ pd_uinfo,
> >+ ablk_req->nbytes,
> >+ ablk_req->dst,
> >+ CRYPTO_ALG_TYPE_ABLKCIPHER);
> >+ } else {
> >+ dst = pd_uinfo->dest_va;
> >+ addr = dma_map_page(NULL, sg_page(dst), dst->offset,
> >+ dst->length, DMA_FROM_DEVICE);
> >+ }
> >+ crypto4xx_ret_sg_desc(&(lsec_core.dev), pd_uinfo);
> >+ if (rctx != NULL)
> >+ crypto4xx_free_sa_rctx(rctx);
> >+ if (ablk_req->base.complete != NULL)
> >+ ablk_req->base.complete(&ablk_req->base, 0);
> >+ return 0;
> >+}
> >+
> >+u32 crypto4xx_ahash_done(struct pd_uinfo *pd_uinfo)
>
> Make static.
>
> >+{
> >+ struct crypto4xx_ctx *ctx;
> >+ struct crypto4xx_ctx *rctx = NULL;
> >+ struct ahash_request *ahash_req;
> >+
> >+ ahash_req = ahash_request_cast(pd_uinfo->async_req);
> >+ ctx = crypto_tfm_ctx(ahash_req->base.tfm);
> >+
> >+ crypto4xx_copy_digest_to_dst(pd_uinfo,
> >+ crypto_tfm_ctx(ahash_req->base.tfm));
> >+ crypto4xx_ret_sg_desc(&(lsec_core.dev), pd_uinfo);
> >+
> >+ if (ctx->use_rctx == 1) {
> >+ rctx = ahash_request_ctx(ahash_req);
> >+ if (rctx != NULL) {
> >+ if (rctx->sa_in_dma_addr)
> >+ dma_free_coherent(NULL,
> >+ rctx->sa_len * 4,
> >+ rctx->sa_in,
> >+ rctx->sa_in_dma_addr);
> >+ if (rctx->sa_out_dma_addr)
> >+ dma_free_coherent(NULL,
> >+ rctx->sa_len * 4,
> >+ rctx->sa_out,
> >+ rctx->sa_out_dma_addr);
> >+ }
> >+ }
> >+ /* call user provided callback function x */
> >+ if (ahash_req->base.complete != NULL)
> >+ ahash_req->base.complete(&ahash_req->base, 0);
> >+ return 0;
> >+}
> >+
> >+u32 crypto4xx_pd_done(struct crypto4xx_core_device *lsec, u32 idx)
>
> Make static.
>
> >+{
> >+ struct ce_pd *pd;
> >+ struct pd_uinfo *pd_uinfo;
> >+
> >+ pd = lsec->dev.pdr + sizeof(struct ce_pd)*idx;
> >+ pd_uinfo = lsec->dev.pdr_uinfo + sizeof(struct pd_uinfo)*idx;
> >+ if (crypto_tfm_alg_type(pd_uinfo->async_req->tfm) ==
> >+ CRYPTO_ALG_TYPE_ABLKCIPHER)
> >+ return crypto4xx_ablkcipher_done(pd_uinfo, pd);
> >+ else
> >+ return crypto4xx_ahash_done(pd_uinfo);
> >+ return 0;
> >+}
> >+
> >+u32 crypto4xx_alloc_sa_rctx(struct crypto4xx_ctx *ctx,
> >+ struct crypto4xx_ctx *rctx)
> >+{
> >+ int rc;
> >+ struct dynamic_sa_ctl *sa = NULL;
> >+
> >+ if (ctx->direction == CRYPTO_INBOUND) {
> >+ sa = (struct dynamic_sa_ctl *)(ctx->sa_in);
> >+ rctx->sa_in = dma_alloc_coherent(NULL,
> >+ ctx->sa_len*4,
> >+ &rctx->sa_in_dma_addr, GFP_ATOMIC);
> >+ if (rctx->sa_in == NULL)
> >+ return -ENOMEM;
> >+ memcpy(rctx->sa_in, ctx->sa_in, ctx->sa_len*4);
> >+ rctx->sa_out = NULL;
> >+ rctx->sa_out_dma_addr = 0;
> >+ } else {
> >+ sa = (struct dynamic_sa_ctl *)(ctx->sa_out);
> >+ rctx->sa_out = dma_alloc_coherent(NULL,
> >+ ctx->sa_len*4,
> >+ &rctx->sa_out_dma_addr, GFP_ATOMIC);
> >+ if (rctx->sa_out == NULL)
> >+ return -ENOMEM;
> >+
> >+ memcpy(rctx->sa_out, ctx->sa_out, ctx->sa_len*4);
> >+ rctx->sa_in = NULL;
> >+ rctx->sa_in_dma_addr = 0;
> >+ }
> >+
> >+ if (sa->sa_contents & 0x20000000) {
> >+ rc = crypto4xx_alloc_state_record(rctx);
> >+ if (rc != 0)
> >+ return -ENOMEM;
> >+
> >+ memcpy(rctx->state_record, ctx->state_record, 16);
> >+ } else {
> >+ rctx->state_record = NULL;
> >+ }
> >+
> >+ rctx->direction = ctx->direction;
> >+ rctx->sa_len = ctx->sa_len;
> >+ rctx->bypass = ctx->bypass;
> >+
> >+ return 0;
> >+}
> >+
> >+void crypto4xx_free_sa_rctx(struct crypto4xx_ctx *rctx)
> >+{
> >+ if (rctx->sa_in != NULL)
> >+ dma_free_coherent(NULL,
> >+ rctx->sa_len * 4,
> >+ rctx->sa_in,
> >+ rctx->sa_in_dma_addr);
> >+
> >+ if (rctx->sa_out != NULL)
> >+ dma_free_coherent(NULL,
> >+ rctx->sa_len * 4,
> >+ rctx->sa_out,
> >+ rctx->sa_out_dma_addr);
> >+
> >+ crypto4xx_free_state_record(rctx);
> >+ rctx->sa_len = 0;
> >+ rctx->state_record = NULL;
> >+ rctx->state_record_dma_addr = 0;
> >+}
> >+
> >+void crypto4xx_memcpy_le(unsigned int *dst,
> >+ const unsigned char *buf,
> >+ int len)
> >+{
> >+ /* SA is in big endian */
> >+ for (; len; buf += 4, len -= 4)
> >+ *dst++ = cpu_to_le32(*(unsigned int *) buf);
> >+}
>
> This doesn't check if len is word aligned. What happens if
> it's not? Seems len could wrap to a negative value and
> things would explode because the copy would just keep going...
>
> >+
> >+u32 crypto4xx_stop_all(void)
>
> Make static.
>
> >+{
> >+ crypto4xx_destroy_pdr(&lsec_core.dev);
> >+ crypto4xx_destroy_sdr(&lsec_core.dev);
> >+ crypto4xx_destroy_gdr(&lsec_core.dev);
> >+
> >+ return 0;
> >+}
> >+
> >+u32 crypto4xx_build_pd(struct crypto4xx_device *dev,
> >+ struct crypto_async_request *req,
> >+ u32 pd_entry,
> >+ struct crypto4xx_ctx *ctx,
> >+ struct scatterlist *src,
> >+ struct scatterlist *dst,
> >+ u16 datalen,
> >+ u8 type)
> >+{
>
> Make static.
>
> >+ dma_addr_t addr, pd_dma, sd_dma, gd_dma;
> >+ struct dynamic_sa_ctl *sa;
> >+ struct scatterlist *sg;
> >+ struct ce_pd *pd;
> >+ struct pd_uinfo *pd_uinfo;
> >+ unsigned int nbytes = datalen, idx;
> >+ struct ce_gd *gd = NULL;
> >+ u32 gd_idx = 0;
> >+ struct ce_sd *sd = NULL;
> >+ u32 sd_idx = 0;
> >+
> >+ pd = crypto4xx_get_pdp(dev, &pd_dma, pd_entry);
> >+ pd_uinfo = (struct pd_uinfo *)((dev->pdr_uinfo) +
> >+ sizeof(struct pd_uinfo)*pd_entry);
> >+ pd_uinfo->async_req = req;
> >+
> >+ if (ctx->direction == CRYPTO_INBOUND) {
> >+ pd->sa = ctx->sa_in_dma_addr;
> >+ sa = (struct dynamic_sa_ctl *)ctx->sa_in;
> >+ } else {
> >+ pd->sa = ctx->sa_out_dma_addr;
> >+ sa = (struct dynamic_sa_ctl *)ctx->sa_out;
> >+ }
> >+
> >+ pd->sa_len = ctx->sa_len;
> >+
> >+ /* If first is last then we are single */
> >+ if (sg_is_last(src)) {
> >+ pd->src = dma_map_page(NULL, sg_page(src),
> >+ src->offset, src->length,
> >+ DMA_TO_DEVICE);
> >+ /* Disable gather in sa command */
> >+ sa->sa_command_0.bf.gather = 0;
> >+ /* Indicate gather array is not used */
> >+ pd_uinfo->first_gd = pd_uinfo->last_gd = 0xffffffff;
> >+ } else {
> >+ src = &src[0];
> >+ /* get first gd we are going to use */
> >+ gd_idx = crypto4xx_get_gd_from_gdr(dev);
> >+ if (gd_idx == ERING_WAS_FULL) {
> >+ crypto4xx_ret_sg_desc(dev, pd_uinfo);
> >+ return -EAGAIN;
> >+ }
> >+ pd_uinfo->first_gd = gd_idx;
> >+ gd = crypto4xx_get_gdp(dev, &gd_dma, gd_idx);
> >+ pd->src = gd_dma;
> >+ /* Enable gather */
> >+ sa->sa_command_0.bf.gather = 1;
> >+ idx = 0;
> >+
> >+ /* walk the sg, and setup gather array */
> >+ /* Seems that CRYPTO_ENGINE DMA is byte align,
> >+ so we can use ptr directly from sg */
> >+ while (nbytes != 0) {
> >+ sg = &src[idx];
> >+ addr = dma_map_page(NULL, sg_page(sg),
> >+ sg->offset, sg->length,
> >+ DMA_TO_DEVICE);
> >+ gd->ptr = addr;
> >+ gd->ctl_len.len = sg->length;
> >+ gd->ctl_len.done = 0;
> >+ gd->ctl_len.ready = 1;
> >+ nbytes -= sg->length;
> >+ if (!nbytes)
> >+ break;
> >+ /* Get first gd we are going to use */
> >+ gd_idx = crypto4xx_get_gd_from_gdr(dev);
> >+ if (gd_idx == ERING_WAS_FULL) {
> >+ crypto4xx_ret_sg_desc(dev, pd_uinfo);
> >+ return -EAGAIN;
> >+ }
> >+ gd = crypto4xx_get_gdp(dev, &gd_dma, gd_idx);
> >+ pd_uinfo->last_gd = gd_idx;
> >+ idx++;
> >+ }
> >+ }
> >+
> >+
> >+ if (ctx->is_hash || sg_is_last(dst)) {
> >+ /* we know application give us dst a whole piece of memory */
> >+ /* no need to use scatter ring */
> >+ pd_uinfo->using_sd = 0;
> >+ pd_uinfo->first_sd = pd_uinfo->last_sd = 0xffffffff;
> >+ pd_uinfo->dest_va = dst;
> >+ sa->sa_command_0.bf.scatter = 0;
> >+ if (ctx->is_hash) {
> >+ pd->dest = virt_to_phys((void *)dst);
> >+ } else {
> >+ pd->dest = dma_map_page(NULL, sg_page(dst),
> >+ dst->offset, dst->length,
> >+ DMA_TO_DEVICE);
> >+ }
> >+
> >+ } else {
> >+ nbytes = datalen;
> >+ sa->sa_command_0.bf.scatter = 1;
> >+ pd_uinfo->using_sd = 1;
> >+
> >+ sd_idx = crypto4xx_get_sd_from_sdr(dev);
> >+ if (sd_idx == ERING_WAS_FULL) {
> >+ crypto4xx_ret_sg_desc(dev, pd_uinfo);
> >+ return -EAGAIN;
> >+ }
> >+ pd_uinfo->first_sd = pd_uinfo->last_sd = sd_idx;
> >+ sd = crypto4xx_get_sdp(dev, &sd_dma, sd_idx);
> >+ pd->dest = sd_dma;
> >+ wmb();
> >+ /* setup scatter descriptor */
> >+ sd->ctl.done = 0;
> >+ sd->ctl.rdy = 1;
> >+ /* sd->ptr should be setup by sd_init routine*/
> >+ if (nbytes >= PPC4XX_SD_BUFFER_SIZE)
> >+ nbytes -= PPC4XX_SD_BUFFER_SIZE;
> >+ else if (nbytes < PPC4XX_SD_BUFFER_SIZE)
> >+ nbytes = 0;
> >+ while (nbytes) {
> >+ sd_idx = crypto4xx_get_sd_from_sdr(dev);
> >+ if (sd_idx == ERING_WAS_FULL) {
> >+ crypto4xx_ret_sg_desc(dev, pd_uinfo);
> >+ /*Fixme implement some error code later */
> >+ return -EAGAIN;
> >+ }
> >+ sd = crypto4xx_get_sdp(dev, &sd_dma, sd_idx);
> >+ pd_uinfo->last_sd = sd_idx;
> >+ /* setup scatter descriptor */
> >+ sd->ctl.done = 0;
> >+ sd->ctl.rdy = 1;
> >+ if (nbytes >= PPC4XX_SD_BUFFER_SIZE)
> >+ nbytes -= PPC4XX_SD_BUFFER_SIZE;
> >+ else
> >+ nbytes = 0;
> >+ }
> >+ }
> >+ pd->pd_ctl.w = ctx->pd_ctl;
> >+ pd->pd_ctl_len.w = 0x00400000 | (ctx->bypass<<24) | datalen;
> >+ pd_uinfo->state = PD_ENTRY_INUSE;
> >+ crypto4xx_write32(CRYPTO_ENGINE_INT_DESCR_RD, 1);
> >+
> >+ return -EINPROGRESS;
> >+
> >+}
> >+
> >+u32 crypto4xx_start_device(struct crypto4xx_device *dev)
> >+{
> >+ u32 rc ;
> >+ rc = crypto4xx_init(dev);
> >+ return rc;
> >+}
>
> Why does this function even exist? Can't you just call
> crypto4xx_init directly?
>
> >+
> >+int crypto4xx_handle_req(struct crypto_async_request *req)
> >+{
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->tfm);
> >+ struct crypto4xx_device *dev = ctx->dev;
> >+ struct crypto4xx_ctx *rctx;
> >+ struct pd_uinfo *pd_uinfo;
> >+
> >+ int ret = -EAGAIN;
> >+
> >+ u32 pd_entry;
> >+
> >+ pd_entry = crypto4xx_get_pd_from_pdr(dev); /* index to the entry */
> >+ if (pd_entry == ERING_WAS_FULL)
> >+ return -EAGAIN;
> >+
> >+ pd_uinfo = (struct pd_uinfo *)((dev->pdr_uinfo) +
> >+ sizeof(struct pd_uinfo)*pd_entry);
> >+
> >+ if (crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_ABLKCIPHER) {
> >+ struct ablkcipher_request *ablk_req;
> >+ ablk_req = ablkcipher_request_cast(req);
> >+ if (ctx->use_rctx) {
> >+ rctx = ablkcipher_request_ctx(ablk_req);
> >+ return crypto4xx_build_pd(dev, req, pd_entry, rctx,
> >+ ablk_req->src, ablk_req->dst,
> >+ ablk_req->nbytes, ABLK);
> >+ } else {
> >+ return crypto4xx_build_pd(dev, req, pd_entry, ctx,
> >+ ablk_req->src, ablk_req->dst,
> >+ ablk_req->nbytes,
> >+ ABLK);
> >+ }
> >+ } else {
> >+ struct ahash_request *ahash_req;
> >+ ahash_req = ahash_request_cast(req);
> >+ if (ctx->use_rctx) {
> >+ rctx = ahash_request_ctx(ahash_req);
> >+ return crypto4xx_build_pd(dev, req, pd_entry, rctx,
> >+ ahash_req->src,
> >+ (struct scatterlist *) ahash_req->result,
> >+ ahash_req->nbytes,
> >+ AHASH);
> >+ } else {
> >+ return crypto4xx_build_pd(dev, req, pd_entry, ctx,
> >+ ahash_req->src,
> >+ (struct scatterlist *) ahash_req->result,
> >+ ahash_req->nbytes,
> >+ AHASH);
> >+ }
> >+ }
> >+ return ret;
> >+}
> >+
> >+int crypto4xx_setup_crypto(struct crypto_async_request *req)
> >+{
> >+ return crypto4xx_handle_req(req);
> >+}
>
> Is this even called from anywhere?
>
> >+
> >+/**
> >+ * Algorithm Registration Functions
> >+ *
> >+ */
> >+static int crypto4xx_alg_init(struct crypto_tfm *tfm)
> >+{
> >+ struct crypto_alg *alg = tfm->__crt_alg;
> >+ struct crypto4xx_alg *amcc_alg = crypto_alg_to_crypto4xx_alg(alg);
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
> >+
> >+ ctx->dev = amcc_alg->dev;
> >+ ctx->sa_in = NULL;
> >+ ctx->sa_out = NULL;
> >+ ctx->sa_in_dma_addr = 0;
> >+ ctx->sa_out_dma_addr = 0;
> >+ ctx->sa_len = 0;
> >+
> >+ if (alg->cra_type == &crypto_ablkcipher_type)
> >+ tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx);
> >+ else if (alg->cra_type == &crypto_ahash_type)
> >+ tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx);
> >+ return 0;
> >+}
> >+
> >+void crypto4xx_alg_exit(struct crypto_tfm *tfm)
>
> Static?
>
> >+{
> >+ struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
> >+ crypto4xx_free_sa(ctx);
> >+ crypto4xx_free_state_record(ctx);
> >+}
> >+
> >+int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
> >+ struct crypto_alg *crypto_alg, int array_size)
> >+{
> >+ struct crypto4xx_alg *alg;
> >+ int i;
> >+ int rc = 0;
> >+
> >+ for (i = 0; i < array_size; i++) {
> >+ alg = kzalloc(sizeof(struct crypto4xx_alg), GFP_KERNEL);
> >+ if (!alg)
> >+ return -ENOMEM;
> >+
> >+ alg->alg = crypto_alg[i];
> >+ INIT_LIST_HEAD(&alg->alg.cra_list);
> >+ if (alg->alg.cra_init == NULL)
> >+ alg->alg.cra_init = crypto4xx_alg_init;
> >+ if (alg->alg.cra_exit == NULL)
> >+ alg->alg.cra_exit = crypto4xx_alg_exit;
> >+ alg->dev = sec_dev;
> >+ list_add_tail(&alg->entry, &sec_dev->alg_list);
> >+ rc = crypto_register_alg(&alg->alg);
> >+ if (rc) {
> >+ list_del(&alg->entry);
> >+ kfree(alg);
> >+ return rc;
> >+ }
> >+ }
> >+ return rc;
> >+}
> >+
> >+static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
> >+{
> >+ struct crypto4xx_alg *alg, *tmp;
> >+
> >+ list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {
> >+ list_del(&alg->entry);
> >+ crypto_unregister_alg(&alg->alg);
> >+ kfree(alg);
> >+ }
> >+}
> >+
> >+static void crypto4xx_bh_tasklet_cb(unsigned long data)
> >+{
> >+ struct crypto4xx_core_device *lsec;
> >+ struct pd_uinfo *pd_uinfo;
> >+ struct ce_pd *pd;
> >+ u32 tail;
> >+
> >+ lsec = (struct crypto4xx_core_device *) data;
> >+
> >+ while (lsec->dev.pdr_head != lsec->dev.pdr_tail) {
> >+ tail = lsec->dev.pdr_tail;
> >+ pd_uinfo = lsec->dev.pdr_uinfo + sizeof(struct pd_uinfo)*tail;
> >+ pd = lsec->dev.pdr + sizeof(struct ce_pd)*tail;
> >+ if ((pd_uinfo->state == PD_ENTRY_INUSE) &&
> >+ pd->pd_ctl.bf.pe_done &&
> >+ !pd->pd_ctl.bf.host_ready) {
> >+ pd->pd_ctl.bf.pe_done = 0;
> >+ crypto4xx_pd_done(lsec, tail);
> >+ crypto4xx_put_pd_to_pdr(&(lsec->dev), tail);
> >+ pd_uinfo->state = PD_ENTRY_FREE;
> >+ } else {
> >+ /* if tail not done, break */
> >+ break;
> >+ }
> >+ }
> >+}
> >+
> >+/**
> >+ * Top Half of isr.
> >+ */
> >+static int crypto4xx_ce_interrupt_handler(int irq, void *id)
> >+{
> >+ if (lsec_core.ce_base == 0)
> >+ return 0;
> >+
> >+ lsec_core.irq_cnt++;
>
> What exactly is this used for? You seem to be counting
> the number of interrupts, but I don't see a way to report
> that or see it used anywhere.
>
> >+ crypto4xx_write32(CRYPTO_ENGINE_INT_CLR, 0x3ffff);
> >+ tasklet_schedule(&lsec_core.tasklet);
> >+
> >+ return IRQ_HANDLED;
> >+}
> >+
> >+/**
> >+ * Module Initialization Routine
> >+ *
> >+ */
> >+static int __init crypto4xx_crypto_probe(struct of_device *ofdev,
> >+ const struct of_device_id *match)
> >+{
> >+ int rc;
> >+ struct resource res;
> >+
> >+ lsec_core.ce_base = 0;
> >+ lsec_core.irq_cnt = 0ll;
>
> = 0; is just fine. If you need that at all.
>
> >+
> >+ memset(&lsec_core.dev, 0, sizeof(struct crypto4xx_device));
> >+
> >+ INIT_LIST_HEAD(&lsec_core.dev.alg_list);
> >+
> >+ crypto4xx_build_pdr(&(lsec_core.dev));
> >+ crypto4xx_build_gdr(&(lsec_core.dev));
> >+ crypto4xx_build_sdr(&(lsec_core.dev));
> >+
> >+ /* Init tasklet for bottom half processing */
> >+ tasklet_init(&lsec_core.tasklet, crypto4xx_bh_tasklet_cb,
> >+ (unsigned long)&lsec_core);
> >+
> >+ /* Register for Crypto isr, Crypto Engine IRQ */
> >+ lsec_core.irq = of_irq_to_resource(ofdev->node, 0, NULL);
> >+ rc = request_irq(lsec_core.irq, crypto4xx_ce_interrupt_handler, 0,
> >+ lsec_core.dev.name, NULL);
> >+ if (rc)
> >+ goto err_request_irq;
> >+
> >+ rc = of_address_to_resource(ofdev->node, 0, &res);
> >+ if (rc)
> >+ return -ENODEV;
> >+
> >+ lsec_core.ce_phy_address = res.start;
> >+ lsec_core.ce_base = ioremap(lsec_core.ce_phy_address,
> >+ res.end - res.start + 1);
> >+
> >+ /* need to setup pdr, rdr, gdr and sdr */
> >+ rc = crypto4xx_start_device(&lsec_core.dev);
> >+ if (rc)
> >+ goto err_start_device;
> >+
> >+ /* Register security algorithms with Linux CryptoAPI */
> >+ rc = crypto4xx_register_basic_alg();
> >+ if (rc)
> >+ goto err_register_alg;
> >+
> >+ printk(KERN_INFO "Loaded AMCC PPC4XX crypto "
> >+ "accelerator driver v%s\n", PPC4XX_SEC_VERSION_STR);
> >+
> >+ return rc;
> >+
> >+err_register_alg:
> >+ crypto4xx_unregister_alg(&lsec_core.dev);
> >+err_start_device:
> >+ free_irq(lsec_core.irq, &lsec_core.dev.name);
> >+err_request_irq:
> >+ crypto4xx_stop_all();
> >+
> >+ return rc;
> >+}
> >+
> >+static int __exit crypto4xx_crypto_remove(struct of_device *dev)
> >+{
> >+ free_irq(lsec_core.irq, NULL);
> >+ /* Un-register with Linux CryptoAPI */
> >+ crypto4xx_unregister_alg(&lsec_core.dev);
> >+ /* Free all allocated memory */
> >+ crypto4xx_stop_all();
> >+
> >+ printk(KERN_INFO "Unloaded AMCC PPC4XX crypto "
> >+ "accelerator driver v%s\n", PPC4XX_SEC_VERSION_STR);
> >+
> >+ return 0;
> >+}
> >+
> >+static struct of_device_id crypto4xx_crypto_match[] = {
> >+ { .compatible = "amcc,ppc4xx-crypto",},
> >+ { },
> >+};
> >+
> >+static struct of_platform_driver crypto4xx_crypto_driver = {
> >+ .name = "crypto4xx-crypto",
> >+ .match_table = crypto4xx_crypto_match,
> >+ .probe = crypto4xx_crypto_probe,
> >+ .remove = crypto4xx_crypto_remove,
> >+};
> >+
> >+static int __init crypto4xx_lsec_init(void)
> >+{
> >+ return of_register_platform_driver(&crypto4xx_crypto_driver);
> >+}
> >+
> >+static void __exit crypto4xx_lsec_exit(void)
> >+{
> >+ of_unregister_platform_driver(&crypto4xx_crypto_driver);
> >+}
> >+
> >+module_init(crypto4xx_lsec_init);
> >+module_exit(crypto4xx_lsec_exit);
> >+
> >+MODULE_LICENSE("GPL");
> >+MODULE_AUTHOR("James Hsiao <jhsiao at amcc.com>");
> >+MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator");
> >+
> >diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
> >new file mode 100644
> >index 0000000..b7a6191
> >--- /dev/null
> >+++ b/drivers/crypto/amcc/crypto4xx_core.h
> >@@ -0,0 +1,200 @@
> >+/*******************************************************************************
> >+ * AMCC SoC Crypto4XX Driver
> >+ *
> >+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
> >+ * All rights reserved. James Hsiao <jhsiao at amcc.com>
> >+ *
> >+ * 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.
> >+ *
> >+ * @file crypto4xx_core.h
> >+ *
> >+ * This is the header file for AMCC Crypto offload Linux device driver for
> >+ * use with Linux CryptoAPI.
> >+ *
> >+ *******************************************************************************
> >+ */
> >+
> >+#ifndef __CRYPTO4XX_CORE_H__
> >+#define __CRYPTO4XX_CORE_H__
> >+
> >+#define CRYPTO4XX_CRYPTO_PRIORITY 300
> >+
> >+#define PPC4XX_LAST_PD 63
> >+#define PPC4XX_NUM_PD 64
> >+
> >+#define PPC4XX_LAST_GD 1023
> >+#define PPC4XX_NUM_GD 1024
> >+
> >+#define PPC4XX_LAST_SD 63
> >+#define PPC4XX_NUM_SD 64
> >+
> >+#define PPC4XX_SD_BUFFER_SIZE 2048
> >+
> >+#define PPC4XX_INT_DESCR_CNT 4
> >+#define PPC4XX_INT_TIMEOUT_CNT 0
> >+/* FIXme arbitory number*/
> >+#define PPC4XX_INT_CFG 1
> >+/*
> >+ * These define will be used in crypto4xx_build_pd
> >+ * AHASH don't have dst scatterlist iso u8*
> >+ * with the type field it can destinguish what is
> >+ */
> >+#define ABLK 0
> >+#define AHASH 1
> >+
> >+#define PD_ENTRY_INUSE 1
> >+#define PD_ENTRY_FREE 0
> >+
> >+#define EALLOC_MEM_FAIL 0xfffffffd
> >+#define EDOWNSEMA_FAIL 0xfffffffe
> >+#define ERING_WAS_FULL 0xffffffff
> >+
> >+struct crypto4xx_device;
> >+extern struct crypto4xx_core_device lsec_core;
> >+extern struct crypto_alg crypto4xx_basic_alg[];
> >+
> >+struct pd_uinfo {
> >+ struct crypto4xx_device *dev;
> >+ u32 state;
> >+ u32 using_sd;
> >+ void *pd_va; /* offset from pdr */
> >+ void *rd_va; /* offset from rdr, could be
> >+ same as pdr(same as pd_va)*/
> >+ u32 first_gd; /* first gather discriptor
> >+ used by this packet */
> >+ u32 last_gd; /* last gather discriptor
> >+ used by this packet */
> >+ u32 first_sd; /* first scatter discriptor
> >+ used by this packet */
> >+ u32 last_sd; /* last scatter discriptor
> >+ used by this packet */
> >+ u32 first_done;
> >+ u32 last_done;
> >+ struct scatterlist *dest_va;
> >+ u32 cryptype;
> >+ struct crypto_async_request *async_req; /* base crypto request
> >+ for this packet */
> >+};
> >+
> >+struct crypto4xx_device {
> >+ u8 dev_id; /* Device ID - id of device to
> >+ send request to */
> >+ char *name;
> >+ void *pdr; /* base address of packet
> >+ descriptor ring */
> >+ dma_addr_t pdr_pa; /* physical address used to
> >+ program ce pdr_base_register */
> >+ void *rdr; /* result descriptor ring, maybe same
> >+ location as pdr */
> >+ dma_addr_t rdr_pa; /* physical address used to
> >+ program ce rdr_base_register */
> >+ void *gdr; /* gather descriptor ring,
> >+ for inbound packet/fragments */
> >+ /* address of particle is
> >+ from the request, src sg*/
> >+ dma_addr_t gdr_pa; /* physical address used to
> >+ program ce gdr_base_register */
> >+ void *sdr; /* scatter descriptor ring,for outbound
> >+ packet/fragments
> >+ must be same size, so init them
> >+ to 2k each safe for large
> >+ packets */
> >+ dma_addr_t sdr_pa; /* physical address used to
> >+ program ce sdr_base_register */
> >+ dma_addr_t scatter_buffer_pa;
> >+ void *scatter_buffer_va;
> >+ u32 scatter_buffer_size;
> >+ int pdr_tail;
> >+ int pdr_head;
> >+ u32 gdr_tail;
> >+ u32 gdr_head;
> >+ u32 sdr_tail;
> >+ u32 sdr_head;
> >+ void *pdr_uinfo;
> >+ struct list_head alg_list; /* List of algorithm supported
> >+ by this device */
> >+};
> >+
> >+struct crypto4xx_core_device {
> >+ struct crypto4xx_device dev;
> >+ u32 int_status;
> >+ u32 irq;
> >+ u64 irq_cnt;
> >+ struct tasklet_struct tasklet;
> >+ u64 ce_phy_address;
> >+ void __iomem *ce_base;
> >+};
> >+
> >+struct crypto4xx_ctx {
> >+ struct crypto4xx_device *dev;
> >+ void *sa_in;
> >+ dma_addr_t sa_in_dma_addr;
> >+ void *sa_out;
> >+ dma_addr_t sa_out_dma_addr;
> >+ void *state_record;
> >+ dma_addr_t state_record_dma_addr;
> >+ u16 sa_len;
> >+ u32 direction;
> >+ u32 use_rctx;
> >+ u32 next_hdr;
> >+ u32 save_iv;
> >+ u32 pd_ctl_len;
> >+ u32 pd_ctl;
> >+ u32 bypass;
> >+ u32 is_hash;
> >+ u32 hash_final;
> >+};
> >+
> >+struct crypto4xx_req_ctx {
> >+ struct crypto4xx_device *dev; /* Device in which
> >+ operation to send to */
> >+ void *sa;
> >+ dma_addr_t sa_dma_addr;
> >+ u16 sa_len;
> >+};
> >+
> >+struct crypto4xx_alg {
> >+ struct list_head entry;
> >+ struct crypto_alg alg;
> >+ struct crypto4xx_device *dev;
> >+};
> >+
> >+#define crypto_alg_to_crypto4xx_alg(x) \
> >+ container_of(x, struct crypto4xx_alg, alg)
> >+
> >+extern void crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size);
> >+extern u32 crypto4xx_alloc_sa_rctx(struct crypto4xx_ctx *ctx,
> >+ struct crypto4xx_ctx *rctx);
> >+extern void crypto4xx_free_ctx(struct crypto4xx_ctx *ctx);
> >+extern u32 crypto4xx_pd_done(struct crypto4xx_core_device *lsec, u32 idx);
>
> This function doesn't need to be listed.
>
> >+extern void crypto4xx_free_sa(struct crypto4xx_ctx *ctx);
> >+extern u32 crypto4xx_alloc_state_record(struct crypto4xx_ctx *ctx);
> >+extern void crypto4xx_free_state_record(struct crypto4xx_ctx *ctx);
>
> This function doesn't need to be listed.
> >+
> >+extern u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx *ctx);
> >+extern u32 get_dynamic_sa_offset_iv_field(struct crypto4xx_ctx *ctx);
> >+extern u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx *ctx);
> >+extern void crypto4xx_memcpy_le(unsigned int *dst,
> >+ const unsigned char *buf, int len);
> >+extern void crypto4xx_free_sa_rctx(struct crypto4xx_ctx *rctx);
> >+extern int crypto4xx_handle_req(struct crypto_async_request *req);
> >+extern u32 crypto4xx_build_pd(struct crypto4xx_device *dev,
> >+ struct crypto_async_request *req,
> >+ u32 pd_entry,
> >+ struct crypto4xx_ctx *ctx,
> >+ struct scatterlist *src,
> >+ struct scatterlist *dst,
> >+ u16 datalen,
> >+ u8 type);
>
> This function doesn't need to be listed.
>
> >+extern int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
> >+ struct crypto_alg *crypto_alg, int array_size);
> >+extern int crypto4xx_register_basic_alg(void);
> >+#endif
> >diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
> >new file mode 100644
> >index 0000000..73003b1
> >--- /dev/null
> >+++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
> >@@ -0,0 +1,291 @@
> >+/****************************************************************************
> >+ * AMCC SoC Crypto4XX Driver
> >+ *
> >+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
> >+ * All rights reserved. James Hsiao <jhsiao at amcc.com>
> >+ *
> >+ * 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.
> >+ *
> >+ * @file crypto4xx_reg_def.h
> >+ *
> >+ * This filr defines the register set for Security Subsystem
> >+ *
> >+ ****************************************************************************
> >+ */
> >+
> >+#ifndef __CRYPTO_ENGINE_REG_DEF_H__
> >+#define __CRYPTO_ENGINE_REG_DEF_H__
> >+
> >+/* CRYPTO_ENGINE Register offset */
> >+#define CRYPTO_ENGINE_DESCRIPTOR 0x00000000
> >+#define CRYPTO_ENGINE_CTRL_STAT 0x00000000
> >+#define CRYPTO_ENGINE_SOURCE 0x00000004
> >+#define CRYPTO_ENGINE_DEST 0x00000008
> >+#define CRYPTO_ENGINE_SA 0x0000000C
> >+#define CRYPTO_ENGINE_SA_LENGTH 0x00000010
> >+#define CRYPTO_ENGINE_LENGTH 0x00000014
> >+
> >+
> >+#define CRYPTO_ENGINE_PE_DMA_CFG 0x00000040
> >+#define CRYPTO_ENGINE_PE_DMA_STAT 0x00000044
> >+#define CRYPTO_ENGINE_PDR_BASE 0x00000048
> >+#define CRYPTO_ENGINE_RDR_BASE 0x0000004c
> >+#define CRYPTO_ENGINE_RING_SIZE 0x00000050
> >+#define CRYPTO_ENGINE_RING_CTRL 0x00000054
> >+#define CRYPTO_ENGINE_INT_RING_STAT 0x00000058
> >+#define CRYPTO_ENGINE_EXT_RING_STAT 0x0000005c
> >+#define CRYPTO_ENGINE_IO_THRESHOLD 0x00000060
> >+#define CRYPTO_ENGINE_GATH_RING_BASE 0x00000064
> >+#define CRYPTO_ENGINE_SCAT_RING_BASE 0x00000068
> >+#define CRYPTO_ENGINE_PART_RING_SIZE 0x0000006c
> >+#define CRYPTO_ENGINE_PART_RING_CFG 0x00000070
> >+
> >+#define CRYPTO_ENGINE_PDR_BASE_UADDR 0x00000080
> >+#define CRYPTO_ENGINE_RDR_BASE_UADDR 0x00000084
> >+#define CRYPTO_ENGINE_PKT_SRC_UADDR 0x00000088
> >+#define CRYPTO_ENGINE_PKT_DEST_UADDR 0x0000008c
> >+#define CRYPTO_ENGINE_SA_UADDR 0x00000090
> >+#define CRYPTO_ENGINE_GATH_RING_BASE_UADDR 0x000000A0
> >+#define CRYPTO_ENGINE_SCAT_RING_BASE_UADDR 0x000000A4
> >+
> >+#define CRYPTO_ENGINE_SEQ_RD 0x00000408
> >+#define CRYPTO_ENGINE_SEQ_MASK_RD 0x0000040C
> >+
> >+#define CRYPTO_ENGINE_SA_CMD_0 0x00010600
> >+#define CRYPTO_ENGINE_SA_CMD_1 0x00010604
> >+
> >+#define CRYPTO_ENGINE_STATE_PTR 0x000106dc
> >+#define CRYPTO_ENGINE_STATE_IV 0x00010700
> >+#define CRYPTO_ENGINE_STATE_HASH_BYTE_CNT_0 0x00010710
> >+#define CRYPTO_ENGINE_STATE_HASH_BYTE_CNT_1 0x00010714
> >+
> >+#define CRYPTO_ENGINE_STATE_IDIGEST_0 0x00010718
> >+#define CRYPTO_ENGINE_STATE_IDIGEST_1 0x0001071c
> >+
> >+#define CRYPTO_ENGINE_DATA_IN 0x00018000
> >+#define CRYPTO_ENGINE_DATA_OUT 0x0001c000
> >+
> >+
> >+#define CRYPTO_ENGINE_INT_UNMASK_STAT 0x000500a0
> >+#define CRYPTO_ENGINE_INT_MASK_STAT 0x000500a4
> >+#define CRYPTO_ENGINE_INT_CLR 0x000500a4
> >+#define CRYPTO_ENGINE_INT_EN 0x000500a8
> >+
> >+#define CRYPTO_ENGINE_INT_PKA 0x00000002
> >+#define CRYPTO_ENGINE_INT_PDR_DONE 0x00008000
> >+#define CRYPTO_ENGINE_INT_MA_WR_ERR 0x00020000
> >+#define CRYPTO_ENGINE_INT_MA_RD_ERR 0x00010000
> >+#define CRYPTO_ENGINE_INT_PE_ERR 0x00000200
> >+#define CRYPTO_ENGINE_INT_USER_DMA_ERR 0x00000040
> >+#define CRYPTO_ENGINE_INT_SLAVE_ERR 0x00000010
> >+#define CRYPTO_ENGINE_INT_MASTER_ERR 0x00000008
> >+#define CRYPTO_ENGINE_INT_ERROR 0x00030258
> >+
> >+#define CRYPTO_ENGINE_INT_CFG 0x000500ac
> >+#define CRYPTO_ENGINE_INT_DESCR_RD 0x000500b0
> >+#define CRYPTO_ENGINE_INT_DESCR_CNT 0x000500b4
> >+#define CRYPTO_ENGINE_INT_TIMEOUT_CNT 0x000500b8
> >+
> >+#define CRYPTO_ENGINE_DC_CTRL 0x00060080
> >+#define CRYPTO_ENGINE_DEVICE_ID 0x00060084
> >+#define CRYPTO_ENGINE_DEVICE_INFO 0x00060088
> >+#define CRYPTO_ENGINE_DMA_USER_SRC 0x00060094
> >+#define CRYPTO_ENGINE_DMA_USER_DEST 0x00060098
> >+#define CRYPTO_ENGINE_DMA_USER_CMD 0x0006009C
> >+
> >+#define CRYPTO_ENGINE_DMA_CFG 0x000600d4
> >+#define CRYPTO_ENGINE_BYTE_ORDER_CFG 0x000600d8
> >+#define CRYPTO_ENGINE_ENDIAN_CFG 0x000600d8
> >+
> >+#define CRYPTO_ENGINE_PRNG_STAT 0x00070000
> >+#define CRYPTO_ENGINE_PRNG_CTRL 0x00070004
> >+#define CRYPTO_ENGINE_PRNG_SEED_L 0x00070008
> >+#define CRYPTO_ENGINE_PRNG_SEED_H 0x0007000c
> >+
> >+#define CRYPTO_ENGINE_PRNG_RES_0 0x00070020
> >+#define CRYPTO_ENGINE_PRNG_RES_1 0x00070024
> >+#define CRYPTO_ENGINE_PRNG_RES_2 0x00070028
> >+#define CRYPTO_ENGINE_PRNG_RES_3 0x0007002C
> >+
> >+#define CRYPTO_ENGINE_PRNG_LFSR_L 0x00070030
> >+#define CRYPTO_ENGINE_PRNG_LFSR_H 0x00070034
> >+
> >+/**
> >+ * Initilize CRYPTO ENGINE registers, and memory bases.
> >+ */
> >+
> >+#define PPC4XX_PDR_POLL 0x3ff
> >+#define PPC4XX_OUTPUT_THRESHOLD 2
> >+#define PPC4XX_INPUT_THRESHOLD 2
> >+#define PPC4XX_PD_SIZE 6
> >+#define CRYPTO_CTX_DONE_INT 0x2000
> >+#define CRYPTO_PD_DONE_INT 0x8000
> >+/**
> >+ * all follow define are ad hoc
> >+ */
> >+#define PPC4XX_RING_RETRY 100
> >+#define PPC4XX_RING_POLL 100
> >+#define PPC4XX_SDR_SIZE PPC4XX_NUM_SD
> >+#define PPC4XX_GDR_SIZE PPC4XX_NUM_GD
> >+
> >+/**
> >+ *
> >+ * IPE Generic Security Association (SA) with all possible fields. These will
> >+ * never likely used except for reference purpose. These structure format
> >+ * can be not changed as the hardware expects them to be layout as defined.
> >+ * Field can be removed or reduced but ordering can not be changed.
> >+ *
> >+ *
> >+ */
> >+
> >+#define CRYPTO_ENGINE_DMA_CFG_OFFSET 0x40
> >+union ce_pe_dma_cfg {
> >+ struct {
> >+ u32 rsv:7;
> >+ u32 dir_host:1;
> >+ u32 rsv1:2;
> >+ u32 bo_td_en:1;
> >+ u32 dis_pdr_upd:1;
> >+ u32 bo_sgpd_en:1;
> >+ u32 bo_data_en:1;
> >+ u32 bo_sa_en:1;
> >+ u32 bo_pd_en:1;
> >+ u32 rsv2:4;
> >+ u32 dynamic_sa_en:1;
> >+ u32 pdr_mode:2;
> >+ u32 pe_mode:1;
> >+ u32 rsv3:5;
> >+ u32 reset_sg:1;
> >+ u32 reset_pdr:1;
> >+ u32 reset_pe:1;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+#define CRYPTO_ENGINE_PDR_BASE_OFFSET 0x48
> >+#define CRYPTO_ENGINE_RDR_BASE_OFFSET 0x4c
> >+
> >+#define CRYPTO_ENGINE_RING_SIZE_OFFSET 0x50
> >+union ce_ring_size {
> >+ struct {
> >+ u32 ring_offset:16;
> >+ u32 rsv:6;
> >+ u32 ring_size:10;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+#define CRYPTO_ENGINE_RING_CONTROL_OFFSET 0x54
> >+union ce_ring_contol {
> >+ struct {
> >+ u32 continuous:1;
> >+ u32 rsv:5;
> >+ u32 ring_retry_divisor:10;
> >+ u32 rsv1:4;
> >+ u32 ring_poll_divisor:10;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+#define CRYPTO_ENGINE_IO_THRESHOLD_OFFSET 0x60
> >+union ce_io_threshold {
> >+ struct {
> >+ u32 rsv:6;
> >+ u32 output_threshold:10;
> >+ u32 rsv1:6;
> >+ u32 input_threshold:10;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+#define CRYPTO_ENGINE_GATHER_RING_BASE_OFFSET 0x64
> >+#define CRYPTO_ENGINE_SCATTER_RING_BASE_OFFSET 0x68
> >+
> >+union ce_part_ring_size {
> >+ struct {
> >+ u32 sdr_size:16;
> >+ u32 gdr_size:16;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+#define MAX_BURST_SIZE_32 0
> >+#define MAX_BURST_SIZE_64 1
> >+#define MAX_BURST_SIZE_128 2
> >+#define MAX_BURST_SIZE_256 3
> >+
> >+/* gather descriptor control length */
> >+struct gd_ctl_len {
> >+ u32 len:16;
> >+ u32 rsv:14;
> >+ u32 done:1;
> >+ u32 ready:1;
> >+} __attribute__((packed));
> >+
> >+struct ce_gd {
> >+ u32 ptr;
> >+ struct gd_ctl_len ctl_len;
> >+} __attribute__((packed));
> >+
> >+struct sd_ctl {
> >+ u32 ctl:30;
> >+ u32 done:1;
> >+ u32 rdy:1;
> >+} __attribute__((packed));
> >+
> >+struct ce_sd {
> >+ u32 ptr;
> >+ struct sd_ctl ctl;
> >+} __attribute__((packed));
> >+
> >+#define PD_PAD_CTL_32 0x10
> >+#define PD_PAD_CTL_64 0x20
> >+#define PD_PAD_CTL_128 0x40
> >+#define PD_PAD_CTL_256 0x80
> >+union ce_pd_ctl {
> >+ struct {
> >+ u32 pd_pad_ctl:8;
> >+ u32 status:8;
> >+ u32 next_hdr:8;
> >+ u32 rsv:2;
> >+ u32 cached_sa:1;
> >+ u32 hash_final:1;
> >+ u32 init_arc4:1;
> >+ u32 rsv1:1;
> >+ u32 pe_done:1;
> >+ u32 host_ready:1;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+union ce_pd_ctl_len {
> >+ struct {
> >+ u32 bypass:8;
> >+ u32 pe_done:1;
> >+ u32 host_ready:1;
> >+ u32 rsv:2;
> >+ u32 pkt_len:20;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+struct ce_pd {
> >+ union ce_pd_ctl pd_ctl;
> >+ dma_addr_t src;
> >+ dma_addr_t dest;
> >+ dma_addr_t sa; /* get from ctx->sa_dma_addr */
> >+ u32 sa_len; /* only if dynamic sa is used */
> >+ union ce_pd_ctl_len pd_ctl_len;
> >+
> >+} __attribute__((packed));
> >+
> >+
> >+#endif
> >diff --git a/drivers/crypto/amcc/crypto4xx_sa.c b/drivers/crypto/amcc/crypto4xx_sa.c
> >new file mode 100644
> >index 0000000..a7adfcf
> >--- /dev/null
> >+++ b/drivers/crypto/amcc/crypto4xx_sa.c
> >@@ -0,0 +1,98 @@
> >+/****************************************************************************
> >+ * AMCC SoC Crypto4XX Driver
> >+ *
> >+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
> >+ * All rights reserved. James Hsiao <jhsiao at amcc.com>
> >+ *
> >+ * 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.
> >+ *
> >+ * @file crypto4xx_sa.c
> >+ *
> >+ * This file implements the security context
> >+ * assoicate format.
> >+ *
> >+ ****************************************************************************
> >+ */
> >+#include <linux/kernel.h>
> >+#include <linux/module.h>
> >+#include <linux/moduleparam.h>
> >+#include <linux/mod_devicetable.h>
> >+#include <linux/interrupt.h>
> >+#include <linux/spinlock_types.h>
> >+#include <linux/highmem.h>
> >+#include <linux/scatterlist.h>
> >+#include <linux/crypto.h>
> >+#include <crypto/algapi.h>
> >+#include <crypto/des.h>
> >+#include "crypto4xx_reg_def.h"
> >+#include "crypto4xx_sa.h"
> >+#include "crypto4xx_core.h"
> >+
> >+u32 get_dynamic_sa_offset_iv_field(struct crypto4xx_ctx *ctx)
> >+{
> >+ u32 offset;
> >+ union dynamic_sa_contents cts;
> >+
> >+ if (ctx->direction == CRYPTO_INBOUND)
> >+ cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
> >+ else
> >+ cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
> >+ offset = cts.bf.key_size
> >+ + cts.bf.inner_size
> >+ + cts.bf.outer_size
> >+ + cts.bf.spi
> >+ + cts.bf.seq_num0
> >+ + cts.bf.seq_num1
> >+ + cts.bf.seq_num_mask0
> >+ + cts.bf.seq_num_mask1
> >+ + cts.bf.seq_num_mask2
> >+ + cts.bf.seq_num_mask3;
> >+
> >+ return sizeof(struct dynamic_sa_ctl) + offset * 4;
> >+}
> >+
> >+u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx *ctx)
> >+{
> >+ u32 offset;
> >+ union dynamic_sa_contents cts;
> >+
> >+ if (ctx->direction == CRYPTO_INBOUND)
> >+ cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
> >+ else
> >+ cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
> >+ offset = cts.bf.key_size
> >+ + cts.bf.inner_size
> >+ + cts.bf.outer_size
> >+ + cts.bf.spi
> >+ + cts.bf.seq_num0
> >+ + cts.bf.seq_num1
> >+ + cts.bf.seq_num_mask0
> >+ + cts.bf.seq_num_mask1
> >+ + cts.bf.seq_num_mask2
> >+ + cts.bf.seq_num_mask3
> >+ + cts.bf.iv0
> >+ + cts.bf.iv1
> >+ + cts.bf.iv2
> >+ + cts.bf.iv3;
> >+
> >+ return sizeof(struct dynamic_sa_ctl) + offset * 4;
> >+}
> >+
> >+u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx *ctx)
> >+{
> >+ union dynamic_sa_contents cts;
> >+
> >+ if (ctx->direction == CRYPTO_INBOUND)
> >+ cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
> >+ else
> >+ cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
> >+ return (cts.bf.iv0 + cts.bf.iv1 + cts.bf.iv2 + cts.bf.iv3) * 4;
> >+}
> >diff --git a/drivers/crypto/amcc/crypto4xx_sa.h b/drivers/crypto/amcc/crypto4xx_sa.h
> >new file mode 100644
> >index 0000000..f60a9d8
> >--- /dev/null
> >+++ b/drivers/crypto/amcc/crypto4xx_sa.h
> >@@ -0,0 +1,223 @@
> >+/****************************************************************************
> >+ * AMCC SoC Crypto4XX Driver
> >+ *
> >+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
> >+ * All rights reserved. James Hsiao <jhsiao at amcc.com>
> >+ *
> >+ * 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.
> >+ *
> >+ * @file crypto4xx_sa.h
> >+ *
> >+ * This file defines the security context
> >+ * assoicate format.
> >+ *
> >+ ****************************************************************************
> >+ */
> >+
> >+#ifndef __CRYPTO4XX_SA_H__
> >+#define __CRYPTO4XX_SA_H__
> >+
> >+#define u32 unsigned int
> >+
> >+/**
> >+ *
> >+ * Contents of Dynamic Security Association (SA) with all possible fields
> >+ */
> >+union dynamic_sa_contents {
> >+ struct {
> >+ u32 arc4_state_ptr:1;
> >+ u32 arc4_ij_ptr:1;
> >+ u32 state_ptr:1;
> >+ u32 iv3:1;
> >+ u32 iv2:1;
> >+ u32 iv1:1;
> >+ u32 iv0:1;
> >+ u32 seq_num_mask3:1;
> >+ u32 seq_num_mask2:1;
> >+ u32 seq_num_mask1:1;
> >+ u32 seq_num_mask0:1;
> >+ u32 seq_num1:1;
> >+ u32 seq_num0:1;
> >+ u32 spi:1;
> >+ u32 outer_size:5;
> >+ u32 inner_size:5;
> >+ u32 key_size:4;
> >+ u32 cmd_size:4;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+#define CRYPTO_OUTBOUND 0
> >+#define CRYPTO_INBOUND 1
> >+
> >+#define SA_OPCODE_ENCRYPT 0
> >+#define SA_OPCODE_DECRYPT 0
> >+
> >+#define SA_OPCODE_HASH 3
> >+
> >+#define SA_CIPHER_ALG_DES 0
> >+#define SA_CIPHER_ALG_3DES 1
> >+#define SA_CIPHER_ALG_ARC4 2
> >+#define SA_CIPHER_ALG_AES 3
> >+#define SA_CIPHER_ALG_KASUMI 4
> >+#define SA_CIPHER_ALG_NULL 15
> >+
> >+#define SA_HASH_ALG_MD5 0
> >+#define SA_HASH_ALG_SHA1 1
> >+#define SA_HASH_ALG_NULL 15
> >+
> >+#define SA_HASH_ALG_SHA1_DIGEST_SIZE 20
> >+
> >+#define SA_LOAD_HASH_FROM_SA 0
> >+#define SA_LOAD_HASH_FROM_STATE 2
> >+#define SA_LOAD_HASH_NO_LOAD 3
> >+
> >+union sa_command_0 {
> >+ struct {
> >+ u32 scatter:1;
> >+ u32 gather:1;
> >+ u32 save_hash_state:1;
> >+ u32 save_iv:1;
> >+ u32 load_hash_state:2;
> >+ u32 load_iv:2;
> >+ u32 digest_len:4;
> >+ u32 hdr_proc:1;
> >+ u32 extend_pad:1;
> >+ u32 stream_cipher_pad:1;
> >+ u32 rsv:1;
> >+ u32 hash_alg:4;
> >+ u32 cipher_alg:4;
> >+ u32 pad_type:2;
> >+ u32 op_group:2;
> >+ u32 dir:1;
> >+ u32 opcode:3;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+#define CRYPTO_MODE_ECB 0
> >+#define CRYPTO_MODE_CBC 1
> >+
> >+#define CRYPTO_FEEDBACK_MODE_NO_FB 0
> >+#define CRYPTO_FEEDBACK_MODE_64BIT_OFB 0
> >+#define CRYPTO_FEEDBACK_MODE_8BIT_CFB 1
> >+#define CRYPTO_FEEDBACK_MODE_1BIT_CFB 2
> >+#define CRYPTO_FEEDBACK_MODE_128BIT_CFB 3
> >+
> >+#define SA_AES_KEY_LEN_128 2
> >+#define SA_AES_KEY_LEN_192 3
> >+#define SA_AES_KEY_LEN_256 4
> >+
> >+/**
> >+ * The follow 4 defines usage of hmac_muting bit in sa_command_1
> >+ * In Basic hash mode this bit define simple hash or hmac.
> >+ * In IPsec mode, this bit define muting control.
> >+ */
> >+#define SA_HASH_MODE_HASH 0
> >+#define SA_HASH_MODE_HMAC 1
> >+
> >+union sa_command_1 {
> >+ struct {
> >+ u32 crypto_mode31:1;
> >+ u32 save_arc4_state:1;
> >+ u32 arc4_stateful:1;
> >+ u32 key_len:5;
> >+ u32 hash_crypto_offset:8;
> >+ u32 sa_rev:2;
> >+ u32 byte_offset:1;
> >+ u32 hmac_muting:1;
> >+ u32 feedback_mode:2;
> >+ u32 crypto_mode9_8:2;
> >+ u32 extended_seq_num:1;
> >+ u32 seq_num_mask:1;
> >+ u32 mutable_bit_proc:1;
> >+ u32 ip_version:1;
> >+ u32 copy_pad:1;
> >+ u32 copy_payload:1;
> >+ u32 copy_hdr:1;
> >+ u32 rsv1:1;
> >+ } bf;
> >+ u32 w;
> >+} __attribute__((packed));
> >+
> >+struct dynamic_sa_ctl {
> >+ u32 sa_contents;
> >+ union sa_command_0 sa_command_0;
> >+ union sa_command_1 sa_command_1;
> >+
> >+} __attribute__((packed));
> >+
> >+/**
> >+ * State Record for Security Association (SA)
> >+ */
> >+struct dynamic_sa_state_record {
> >+ u32 save_iv[4];
> >+ u32 save_hash_byte_cnt[2];
> >+ u32 save_digest[16];
> >+} __attribute__((packed));
> >+
> >+/**
> >+ * Security Association (SA) for AES128
> >+ *
> >+ */
> >+struct dynamic_sa_aes128 {
> >+ struct dynamic_sa_ctl ctrl;
> >+ u32 key[4];
> >+ u32 iv[4]; /* for CBC, OFC, and CFB mode */
> >+ u32 state_ptr;
> >+ u32 reserved;
> >+} __attribute__((packed));
> >+
> >+#define SA_AES128_LEN (sizeof(struct dynamic_sa_aes128)/4)
> >+#define SA_AES128_CONTENTS 0x3e000042
> >+
> >+/*
> >+ * Security Association (SA) for AES192
> >+ */
> >+struct dynamic_sa_aes192 {
> >+ struct dynamic_sa_ctl ctrl;
> >+ u32 key[6];
> >+ u32 iv[4]; /* for CBC, OFC, and CFB mode */
> >+ u32 state_ptr;
> >+ u32 reserved;
> >+} __attribute__((packed));
> >+
> >+#define SA_AES192_LEN (sizeof(struct dynamic_sa_aes192)/4)
> >+#define SA_AES192_CONTENTS 0x3e000062
> >+
> >+/**
> >+ * Security Association (SA) for AES256
> >+ */
> >+struct dynamic_sa_aes256 {
> >+ struct dynamic_sa_ctl ctrl;
> >+ u32 key[8];
> >+ u32 iv[4]; /* for CBC, OFC, and CFB mode */
> >+ u32 state_ptr;
> >+ u32 reserved;
> >+} __attribute__((packed));
> >+
> >+#define SA_AES256_LEN (sizeof(struct dynamic_sa_aes256)/4)
> >+#define SA_AES256_CONTENTS 0x3e000082
> >+
> >+/**
> >+ * Security Association (SA) for HASH160: HMAC-SHA1
> >+ */
> >+struct dynamic_sa_hash160 {
> >+ struct dynamic_sa_ctl ctrl;
> >+ u32 inner_digest[5];
> >+ u32 outer_digest[5];
> >+ u32 state_ptr;
> >+ u32 reserved;
> >+} __attribute__((packed));
> >+#define SA_HASH160_LEN (sizeof(struct dynamic_sa_hash160)/4)
> >+#define SA_HASH160_CONTENTS 0x2000a502
> >+
> >+#endif
> >
> >_______________________________________________
> >Linuxppc-dev mailing list
> >Linuxppc-dev at ozlabs.org
> >https://ozlabs.org/mailman/listinfo/linuxppc-dev
More information about the Linuxppc-dev
mailing list