From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from sdcmail02.amcc.com (sdcmail02.amcc.com [198.137.200.73]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "Messaging Gateway Appliance Demo Cert", Issuer "Messaging Gateway Appliance Demo Cert" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 4C118DDDE7 for ; Thu, 30 Oct 2008 10:53:12 +1100 (EST) Subject: Re: [PATCH] AMCC Crypto4xx Device Driver v2] From: James Hsiao To: Josh Boyer In-Reply-To: <20081029135418.GA2448@yoda.jdub.homelinux.org> References: <1225237276.1850.13.camel@jhsiao-usb> <20081029135418.GA2448@yoda.jdub.homelinux.org> Content-Type: text/plain Date: Wed, 29 Oct 2008 16:54:25 -0700 Message-Id: <1225324465.4841.91.camel@jhsiao-usb> Mime-Version: 1.0 Cc: linuxppc-dev@ozlabs.org Reply-To: jhsiao@amcc.com List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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 > >--- > > 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 > > Unneeded hunk. > > >@@ -94,6 +94,14 @@ > > dcr-reg = <0x010 0x002>; > > }; > > > >+ CRYPTO: crypto@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@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 > >+ * > >+ * 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 > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+ > >+#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 > >+ * > >+ * 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 > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#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 "); > >+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 > >+ * > >+ * 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 > >+ * > >+ * 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 > >+ * > >+ * 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 > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#include > >+#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 > >+ * > >+ * 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@ozlabs.org > >https://ozlabs.org/mailman/listinfo/linuxppc-dev