LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 2.6.31] ehca: Tolerate dynamic memory operations and huge pages
From: Michael Ellerman @ 2009-06-10  0:02 UTC (permalink / raw)
  To: Hannes Hering
  Cc: rdreier, alexs, linux-kernel, ewg, linuxppc-dev, raisch, ossrosch
In-Reply-To: <200906091559.24661.hannes.hering@linux.vnet.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 1801 bytes --]

On Tue, 2009-06-09 at 15:59 +0200, Hannes Hering wrote:
> This patch implements toleration of dynamic memory operations and 16 GB
> gigantic pages. On module load the driver walks through available system
> memory, checks for available memory ranges and then registers the kernel
> internal memory region accordingly. The translation of address ranges is
> implemented via a 3-level busmap.

Hi Hannes,

For those of us who haven't read the HEA spec lately, can you give us
some more detail on that? :)

How does it interact with kexec/kdump?

> +static int ehca_update_busmap(unsigned long pfn, unsigned long nr_pages)
> +{
> +	unsigned long i, start_section, end_section;
> +	int top, dir, idx;
> +
> +	if (!nr_pages)
> +		return 0;
> +
> +	if (!ehca_bmap) {
> +		ehca_bmap = kmalloc(sizeof(struct ehca_bmap), GFP_KERNEL);
> +		if (!ehca_bmap)
> +			return -ENOMEM;
> +		/* Set map block to 0xFF according to EHCA_INVAL_ADDR */
> +		memset(ehca_bmap, 0xFF, EHCA_TOP_MAP_SIZE);
> +	}
> +
> +	start_section = phys_to_abs(pfn * PAGE_SIZE) / EHCA_SECTSIZE;
> +	end_section = phys_to_abs((pfn + nr_pages) * PAGE_SIZE) / EHCA_SECTSIZE;


phys_to_abs() ? As below, or does it come from somewhere else?

 arch/powerpc/include/asm/abs_addr.h:
 47 static inline unsigned long phys_to_abs(unsigned long pa)                   
 48 {
 49         unsigned long chunk;
 50 
 51         /* This is a no-op on non-iSeries */
 52         if (!firmware_has_feature(FW_FEATURE_ISERIES))
 53                 return pa;
 54 
 55         chunk = addr_to_chunk(pa);
 56 
 57         if (chunk < mschunks_map.num_chunks)
 58                 chunk = mschunks_map.mapping[chunk];
 59 
 60         return chunk_to_addr(chunk) + (pa & MSCHUNKS_OFFSET_MASK);
 61 }


cheers

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* [PATCH] of_serial: Add UPF_FIXED_TYPE flag
From: Dave Mitchell @ 2009-06-09 23:39 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: arnd

This patch adds the UPF_FIXED_TYPE flag which will bypass the
8250's autoconfig probe for uart type. The uart type identified
by the of_serial's parse of the flat device tree will be utilized
as defined.

Signed-off-by: Dave Mitchell <dmitchell@amcc.com>
---
 drivers/serial/of_serial.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 14f8fa9..3f2027c 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -67,7 +67,7 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
 	port->type = type;
 	port->uartclk = *clk;
 	port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
-		| UPF_FIXED_PORT;
+		| UPF_FIXED_PORT | UPF_FIXED_TYPE;
 	port->dev = &ofdev->dev;
 	/* If current-speed was set, then try not to change it. */
 	if (spd)
-- 
1.6.3.2

^ permalink raw reply related

* Re: [BUILD FAILURE 01/04] Next June 04:PPC64 randconfig [drivers/staging/comedi/drivers.o]
From: Benjamin Herrenschmidt @ 2009-06-09 22:34 UTC (permalink / raw)
  To: subrata
  Cc: sachinp, sfr, fmhess, Greg KH, linux-kernel, Linuxppc-dev,
	Ian Abbott, linux-next, paulus, Geert.Uytterhoeven, geert,
	David Miller
In-Reply-To: <1244572446.5497.32.camel@subratamodak.linux.ibm.com>


> > In any case, doing PAGE_KERNEL_NOCACHE for DMA memory is incorrect on
> > many architectures. So at this stage, there's no much option but ifdef I
> > suspect for now until this is fixed properly.
> 
> Ok. But, i am not sure whether Greg will agree to this. If, Ok, is the
> following patch i sent earlier Ok ?
> 
> http://lkml.org/lkml/2009/6/5/462,

Not really.

You probably want to use a constant (call it MY_DMA_MAP_PGPROT), and
in a header, you have a bunch of ifdef's that set it to PAGE_KERNEL,
PAGE_KERNEL_NOCACHE or PAGE_KERNEL_NC depending on what's needed.

Today, you can pretty much assume that

 - x86*, sparc*, ia64*, alpha, ... needs PAGE_KERNEL
 - powerpc needs PAGE_KERNEL if !CONFIG_NOT_COHERENT_CACHE
 - powerpc needs PAGE_KERNEL_NC if CONFIG_NOT_COHERENT_CACHE
 - ARM and MIPS, I think, needs PAGE_KERNEL_NOCACHE
 - ... others I don't know.

Cheers,
Ben.

> Regards--
> Subrata
> 
> > 
> > It does make sense to want to have some memory like that shared between
> > user space and DMA, though I don't know what the right approach that
> > works on all archs is at this stage. Worth asking the Alsa guys, I think
> > they have similar issues :-)
> > 
> > But doing double buffering might do the trick fine for now.
> > 
> > Cheers,
> > Ben.
> > 
> > 
> > 
> > 

^ permalink raw reply

* [PATCH] AMCC Crypto4xx Device Driver v7
From: Shasi Pulijala @ 2009-06-09 21:37 UTC (permalink / raw)
  To: linuxppc-dev


From: Shasi Pulijala <spulijala@amcc.com>

This patch adds further support for AMCC ppc4xx security device driver. =
This is the
second release that adds algorithms like:
 des/3des
 rfc3686(ctr(aes))
 gcm, ccm
 hmac(md5,sha1,..,sha512)
 xcbc(aes), arc4 and kasumi.

Signed-off-by: Shasi Pulijala <spulijala@amcc.com>
Acked-by: Loc Ho <lho@amcc.com>
---
 crypto/md5.c                         |   15 +
 crypto/sha1_generic.c                |   15 +
 crypto/sha256_generic.c              |   15 +
 crypto/sha512_generic.c              |   19 +
 drivers/crypto/amcc/crypto4xx_alg.c  | 1492 =
+++++++++++++++++++++++++++++++++-
 drivers/crypto/amcc/crypto4xx_core.c |  816 ++++++++++++++++++-
 drivers/crypto/amcc/crypto4xx_core.h |   92 +++
 drivers/crypto/amcc/crypto4xx_sa.c   |  114 +++
 drivers/crypto/amcc/crypto4xx_sa.h   |  337 ++++++++-
 include/crypto/sha.h                 |    7 +
 10 files changed, 2870 insertions(+), 52 deletions(-)

diff --git a/crypto/md5.c b/crypto/md5.c
index 83eb529..0c74b84 100644
--- a/crypto/md5.c
+++ b/crypto/md5.c
@@ -220,6 +220,21 @@ static int md5_final(struct shash_desc *desc, u8 =
*out)
 	return 0;
 }
=20
+void md5_get_immediate_hash(struct crypto_tfm *tfm, u8 *data)
+{
+	struct shash_desc *desc =3D crypto_tfm_ctx(tfm);
+	struct md5_ctx *mctx =3D shash_desc_ctx(desc);
+	int i;
+
+	for (i =3D 0; i < MD5_HASH_WORDS; i++) {
+		*data++ =3D mctx->hash[i] & 0xFF;
+		*data++ =3D (mctx->hash[i] >> 8) & 0xFF;
+		*data++ =3D (mctx->hash[i] >> 16) & 0xFF;
+		*data++ =3D (mctx->hash[i] >> 24) & 0xFF;
+	}
+}
+EXPORT_SYMBOL_GPL(md5_get_immediate_hash);
+
 static struct shash_alg alg =3D {
 	.digestsize	=3D	MD5_DIGEST_SIZE,
 	.init		=3D	md5_init,
diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c
index 9efef20..e77b591 100644
--- a/crypto/sha1_generic.c
+++ b/crypto/sha1_generic.c
@@ -111,6 +111,21 @@ static int sha1_final(struct shash_desc *desc, u8 =
*out)
 	return 0;
 }
=20
+void sha1_get_immediate_hash(struct crypto_tfm *tfm, u8 *data)
+{
+	struct shash_desc *desc =3D crypto_tfm_ctx(tfm);
+	struct sha1_ctx *sctx =3D shash_desc_ctx(desc);
+	int i;
+
+	for (i =3D 0; i < 5; i++) {
+		*data++ =3D sctx->state[i] & 0xFF;
+		*data++ =3D (sctx->state[i] >> 8) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 16) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 24) & 0xFF;
+	}
+}
+EXPORT_SYMBOL_GPL(sha1_get_immediate_hash);
+
 static struct shash_alg alg =3D {
 	.digestsize	=3D	SHA1_DIGEST_SIZE,
 	.init		=3D	sha1_init,
diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c
index 6349d83..0f5a66b 100644
--- a/crypto/sha256_generic.c
+++ b/crypto/sha256_generic.c
@@ -331,6 +331,21 @@ static int sha224_final(struct shash_desc *desc, u8 =
*hash)
 	return 0;
 }
=20
+void sha256_get_immediate_hash(struct crypto_tfm *tfm, u8 *data)
+{
+	struct shash_desc *desc =3D crypto_tfm_ctx(tfm);
+	struct sha256_ctx *sctx =3D shash_desc_ctx(desc);
+	int i;
+
+	for (i =3D 0; i < 8; i++) {
+		*data++ =3D sctx->state[i] & 0xFF;
+		*data++ =3D (sctx->state[i] >> 8) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 16) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 24) & 0xFF;
+	}
+}
+EXPORT_SYMBOL_GPL(sha256_get_immediate_hash);
+
 static struct shash_alg sha256 =3D {
 	.digestsize	=3D	SHA256_DIGEST_SIZE,
 	.init		=3D	sha256_init,
diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c
index 3bea38d..c329903 100644
--- a/crypto/sha512_generic.c
+++ b/crypto/sha512_generic.c
@@ -257,6 +257,25 @@ static int sha384_final(struct shash_desc *desc, u8 =
*hash)
 	return 0;
 }
=20
+void sha512_get_immediate_hash(struct crypto_tfm *tfm, u8 *data)
+{
+	struct shash_desc *desc =3D crypto_tfm_ctx(tfm);
+	struct sha512_ctx *sctx =3D shash_desc_ctx(desc);
+	int i;
+
+	for (i =3D 0; i < 8; i++) {
+		*data++ =3D (sctx->state[i] >> 32) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 40) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 48) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 56) & 0xFF;
+		*data++ =3D sctx->state[i] & 0xFF;
+		*data++ =3D (sctx->state[i] >> 8) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 16) & 0xFF;
+		*data++ =3D (sctx->state[i] >> 24) & 0xFF;
+	}
+}
+EXPORT_SYMBOL_GPL(sha512_get_immediate_hash);
+
 static struct shash_alg sha512 =3D {
 	.digestsize	=3D	SHA512_DIGEST_SIZE,
 	.init		=3D	sha512_init,
diff --git a/drivers/crypto/amcc/crypto4xx_alg.c =
b/drivers/crypto/amcc/crypto4xx_alg.c
index 61b6e1b..fac3543 100644
--- a/drivers/crypto/amcc/crypto4xx_alg.c
+++ b/drivers/crypto/amcc/crypto4xx_alg.c
@@ -24,10 +24,13 @@
 #include <linux/crypto.h>
 #include <linux/hash.h>
 #include <crypto/internal/hash.h>
+#include <crypto/aead.h>
 #include <linux/dma-mapping.h>
 #include <crypto/algapi.h>
 #include <crypto/aes.h>
+#include <crypto/des.h>
 #include <crypto/sha.h>
+#include <crypto/authenc.h>
 #include "crypto4xx_reg_def.h"
 #include "crypto4xx_sa.h"
 #include "crypto4xx_core.h"
@@ -58,9 +61,10 @@ void set_dynamic_sa_command_1(struct dynamic_sa_ctl =
*sa, u32 cm, u32 hmac_mc,
 {
 	sa->sa_command_1.w =3D 0;
 	sa->sa_command_1.bf.crypto_mode31 =3D (cm & 4) >> 2;
-	sa->sa_command_1.bf.crypto_mode9_8 =3D cm & 3;
+	sa->sa_command_1.bf.crypto_mode9_8 =3D (cm & 3);
 	sa->sa_command_1.bf.feedback_mode =3D cfb,
 	sa->sa_command_1.bf.sa_rev =3D 1;
+	sa->sa_command_1.bf.hmac_muting =3D hmac_mc;
 	sa->sa_command_1.bf.extended_seq_num =3D esn;
 	sa->sa_command_1.bf.seq_num_mask =3D sn_mask;
 	sa->sa_command_1.bf.mutable_bit_proc =3D mute;
@@ -69,6 +73,338 @@ void set_dynamic_sa_command_1(struct dynamic_sa_ctl =
*sa, u32 cm, u32 hmac_mc,
 	sa->sa_command_1.bf.copy_hdr =3D cp_hdr;
 }
=20
+/** Table lookup for SA Hash Digest length and
+ *  Hash Contents (based on Hash type)
+ */
+unsigned int crypto4xx_sa_hash_tbl[3][HASH_ALG_MAX_CNT] =3D {
+	/* Hash Contents */
+	{ SA_HASH128_CONTENTS, SA_HASH160_CONTENTS, SA_HASH256_CONTENTS,
+	SA_HASH256_CONTENTS, SA_HASH512_CONTENTS, SA_HASH512_CONTENTS },
+	/* Digest len */
+	{4 * 4, 5 * 4, 7 * 4, 8 * 4, 12 * 4, 16 * 4},
+	/* SA Length */
+	{ SA_HASH128_LEN, SA_HASH160_LEN, SA_HASH256_LEN, SA_HASH256_LEN,
+	SA_HASH512_LEN, SA_HASH512_LEN }
+};
+
+/** Table lookup for Hash Algorithms based on Hash type, used in
+ *  crypto4xx_pre_compute_hmac()
+ */
+char *crypto4xx_hash_alg_map_tbl[HASH_ALG_MAX_CNT] =3D =
CRYPTO4XX_MAC_ALGS;
+
+static void crypto4xx_sg_setbuf(unsigned char *data, size_t bufsize,
+				struct scatterlist *sg, int sg_num)
+{
+	int remainder_of_page;
+	int i =3D 0;
+
+	sg_init_table(sg, sg_num);
+	while (bufsize > 0 && i < sg_num) {
+		sg_set_buf(&sg[i], data, bufsize);
+		remainder_of_page =3D PAGE_SIZE - sg[i].offset;
+		if (bufsize > remainder_of_page) {
+			/* the buffer was split over multiple pages */
+			sg[i].length =3D remainder_of_page;
+			bufsize -=3D remainder_of_page;
+			data +=3D remainder_of_page;
+		} else {
+			bufsize =3D 0;
+		}
+		i++;
+	}
+}
+
+void crypto4xx_compute_immediate_hash(struct crypto_tfm *child_tfm, u8 =
*data,
+				     unsigned char ha)
+{
+	switch (ha) {
+	case SA_HASH_ALG_MD5:
+		md5_get_immediate_hash(child_tfm, data);
+		break;
+	case SA_HASH_ALG_SHA1:
+		sha1_get_immediate_hash(child_tfm, data);
+		break;
+	case SA_HASH_ALG_SHA256:
+	case SA_HASH_ALG_SHA224:
+		sha256_get_immediate_hash(child_tfm, data);
+		break;
+	case SA_HASH_ALG_SHA384:
+	case SA_HASH_ALG_SHA512:
+		sha512_get_immediate_hash(child_tfm, data);
+		break;
+	default:
+		break;
+	}
+}
+
+int crypto4xx_pre_compute_hmac(struct crypto4xx_ctx *ctx,
+			       void *key,
+			       unsigned int keylen,
+			       unsigned int bs,
+			       unsigned char ha,
+			       unsigned char digs)
+{
+	u8 *ipad =3D NULL;
+	u8 *opad;
+	struct crypto_hash *child_hash =3D NULL;
+	struct hash_desc desc;
+	struct scatterlist sg[1];
+	struct scatterlist asg[2];
+	struct crypto_tfm *child_tfm;
+	char *child_name =3D NULL;
+	int i, rc =3D 0;
+	int ds;
+
+	BUG_ON(ha >=3D HASH_ALG_MAX_CNT);
+	child_name =3D crypto4xx_hash_alg_map_tbl[ha];
+	child_hash =3D crypto_alloc_hash(child_name, 0, 0);
+	if (IS_ERR(child_hash)) {
+		rc =3D PTR_ERR(child_hash);
+		printk(KERN_ERR "failed to load "
+				"transform for %s error %d\n",
+				child_name, rc);
+		return rc;
+	}
+
+	ipad =3D  kmalloc(bs * 2, GFP_KERNEL);
+	if (ipad =3D=3D NULL) {
+		crypto_free_hash(child_hash);
+		return -ENOMEM;
+	}
+
+	opad =3D ipad + bs;
+	child_tfm =3D crypto_hash_tfm(child_hash);
+	ds =3D crypto_hash_digestsize(child_hash);
+	desc.tfm =3D child_hash;
+	desc.flags =3D 0;
+	if (keylen > bs) {
+		crypto4xx_sg_setbuf(key, keylen, asg, 2);
+		rc =3D crypto_hash_init(&desc);
+		if (rc < 0)
+			goto err_alg_hash_key;
+		rc =3D crypto_hash_update(&desc, asg, keylen);
+		if (rc < 0)
+			goto err_alg_hash_key;
+		rc =3D crypto_hash_final(&desc, ipad);
+		keylen =3D ds;
+	} else {
+		memcpy(ipad, key, keylen);
+	}
+	memset(ipad + keylen, 0, bs-keylen);
+	memcpy(opad, ipad, bs);
+
+	for (i =3D 0; i < bs; i++) {
+		ipad[i] ^=3D 0x36;
+		opad[i] ^=3D 0x5c;
+	}
+
+	sg_init_one(&sg[0], ipad, bs);
+	rc =3D crypto_hash_init(&desc);
+	if (rc < 0)
+		goto err_alg_hash_key;
+	rc =3D crypto_hash_update(&desc, sg, bs);
+	if (rc < 0)
+		goto err_alg_hash_key;
+
+	if (ha =3D=3D SA_HASH_ALG_SHA224)
+		ds =3D SHA256_DIGEST_SIZE;
+	else if (ha =3D=3D SA_HASH_ALG_SHA384)
+		ds =3D SHA512_DIGEST_SIZE;
+
+	crypto4xx_compute_immediate_hash(child_tfm, ipad, ha);
+	crypto4xx_memcpy_le(ctx->sa_in +
+			get_dynamic_sa_offset_inner_digest(ctx), ipad, ds);
+
+	sg_init_one(&sg[0], opad, bs);
+	rc =3D crypto_hash_init(&desc);
+	if (rc < 0)
+		goto err_alg_hash_key;
+
+	rc =3D crypto_hash_update(&desc, sg, bs);
+	if (rc < 0)
+		goto err_alg_hash_key;
+
+	crypto4xx_compute_immediate_hash(child_tfm, opad, ha);
+	crypto4xx_memcpy_le(ctx->sa_in +
+			get_dynamic_sa_offset_outer_digest(ctx), opad, ds);
+
+err_alg_hash_key:
+	kfree(ipad);
+	crypto_free_hash(child_hash);
+	return rc;
+}
+
+int crypto4xx_compute_gcm_hash_key_sw(struct crypto4xx_ctx *ctx,
+				      const u8 *key,
+				      unsigned int keylen)
+{
+	struct crypto_blkcipher *aes_tfm =3D NULL;
+	struct blkcipher_desc 	desc;
+	struct scatterlist sg[1];
+	char src[16];
+	int rc =3D 0;
+
+	aes_tfm =3D crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(aes_tfm)) {
+		printk(KERN_ERR "failed to load transform for %ld\n",
+		       PTR_ERR(aes_tfm));
+		rc =3D PTR_ERR(aes_tfm);
+		return rc;
+	}
+	desc.tfm    =3D aes_tfm;
+	desc.flags  =3D 0;
+
+	memset(src, 0, 16);
+	rc =3D crypto_blkcipher_setkey(aes_tfm, key, keylen);
+	if (rc) {
+		printk(KERN_ERR "setkey() failed flags=3D%x\n",
+		       crypto_blkcipher_get_flags(aes_tfm));
+		goto out;
+	}
+
+	sg_init_one(sg, src, 16);
+	rc =3D crypto_blkcipher_encrypt(&desc, sg, sg, 16);
+	if (rc)
+		goto out;
+	crypto4xx_memcpy_le(ctx->sa_in +
+			get_dynamic_sa_offset_inner_digest(ctx), src, 16);
+
+out:
+	crypto_free_blkcipher(aes_tfm);
+	return rc;
+}
+
+/**
+ * 3DES/DES Functions
+ *
+ */
+static int crypto4xx_setkey_3des(struct crypto_ablkcipher *cipher,
+				 const u8 *key,
+				 unsigned int keylen,
+				 unsigned char cm,
+				 unsigned char fb)
+{
+	struct crypto_tfm    *tfm =3D crypto_ablkcipher_tfm(cipher);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(tfm);
+	struct dynamic_sa_ctl *sa;
+	int rc;
+
+	if (keylen !=3D DES_KEY_SIZE && keylen !=3D DES3_EDE_KEY_SIZE) {
+		crypto_ablkcipher_set_flags(cipher,
+			CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+		return -EINVAL;
+	}
+
+	if (keylen =3D=3D DES_KEY_SIZE) {
+		u32 tmp[32];
+		rc =3D des_ekey(tmp, key);
+		if (unlikely(rc =3D=3D 0) &&
+				  (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+			crypto_ablkcipher_set_flags(cipher,
+				CRYPTO_TFM_RES_WEAK_KEY);
+			return -EINVAL;
+		}
+	}
+
+	/* Create SA */
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		crypto4xx_free_sa(ctx);
+
+	rc =3D crypto4xx_alloc_sa(ctx, keylen =3D=3D 8 ? SA_DES_LEN : =
SA_3DES_LEN);
+	if (rc)
+		return rc;
+	/*
+	 *  state record will state in base ctx, so iv and
+	 *  hash result can be reused
+	 *  also don't need to alloc each packet coming
+	 */
+	if (ctx->state_record_dma_addr =3D=3D 0) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc) {
+			crypto4xx_free_sa(ctx);
+			return rc;
+		}
+	}
+
+	/* Setup SA */
+	ctx->direction =3D DIR_INBOUND;
+	ctx->hash_final =3D 0;
+
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
+				 SA_NO_HEADER_PROC, SA_HASH_ALG_NULL,
+				 SA_CIPHER_ALG_DES,
+				 SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+				 SA_OPCODE_DECRYPT, DIR_INBOUND);
+
+	set_dynamic_sa_command_1(sa, cm, SA_HASH_MODE_HASH,
+				 fb, SA_EXTENDED_SN_OFF,
+				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+				 SA_NOT_COPY_PAD, SA_COPY_PAYLOAD,
+				 SA_NOT_COPY_HDR);
+
+	if (keylen =3D=3D DES_KEY_SIZE) {
+		crypto4xx_memcpy_le(((struct dynamic_sa_des *) sa)->key,
+				      key, keylen);
+		((struct dynamic_sa_des *)sa)->ctrl.sa_contents =3D
+				SA_DES_CONTENTS;
+		sa->sa_command_0.bf.cipher_alg =3D SA_CIPHER_ALG_DES;
+	} else {
+		crypto4xx_memcpy_le(((struct dynamic_sa_3des *) sa)->key,
+				      key, keylen);
+		((struct dynamic_sa_3des *)sa)->ctrl.sa_contents =3D
+				SA_3DES_CONTENTS;
+		sa->sa_command_0.bf.cipher_alg =3D SA_CIPHER_ALG_3DES;
+	}
+
+	memcpy((void *)(ctx->sa_in +
+			get_dynamic_sa_offset_state_ptr_field(ctx)),
+			(void *)&ctx->state_record_dma_addr, 4);
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+	ctx->is_hash =3D 0;
+	sa->sa_command_0.bf.dir =3D DIR_INBOUND;
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	sa->sa_command_0.bf.dir =3D DIR_OUTBOUND;
+
+	return 0;
+}
+
+int crypto4xx_setkey_3des_cfb(struct crypto_ablkcipher *cipher,
+			      const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_3des(cipher, key, keylen,
+					CRYPTO_MODE_CFB,
+					CRYPTO_FEEDBACK_MODE_8BIT_CFB);
+}
+
+int crypto4xx_setkey_3des_ofb(struct crypto_ablkcipher *cipher,
+			      const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_3des(cipher, key, keylen,
+				       CRYPTO_MODE_OFB,
+				       CRYPTO_FEEDBACK_MODE_64BIT_OFB);
+}
+
+int crypto4xx_setkey_3des_cbc(struct crypto_ablkcipher *cipher,
+			      const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_3des(cipher, key, keylen,
+				     CRYPTO_MODE_CBC,
+				     CRYPTO_FEEDBACK_MODE_NO_FB);
+}
+
+int crypto4xx_setkey_3des_ecb(struct crypto_ablkcipher *cipher,
+			      const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_3des(cipher, key, keylen,
+				     CRYPTO_MODE_ECB,
+				     CRYPTO_FEEDBACK_MODE_NO_FB);
+}
+
+
 int crypto4xx_encrypt(struct ablkcipher_request *req)
 {
 	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(req->base.tfm);
@@ -79,22 +415,54 @@ int crypto4xx_encrypt(struct ablkcipher_request =
*req)
 	ctx->pd_ctl =3D 0x1;
=20
 	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
-				  req->nbytes, req->info,
-				  get_dynamic_sa_iv_size(ctx));
+				   req->nbytes, NULL, 0, req->info,
+				   get_dynamic_sa_iv_size(ctx));
 }
=20
 int crypto4xx_decrypt(struct ablkcipher_request *req)
 {
 	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(req->base.tfm);
=20
+	ctx->hash_final =3D 0;
+	ctx->is_hash =3D 0;
+	ctx->pd_ctl =3D 0x1;
 	ctx->direction =3D DIR_INBOUND;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				   req->nbytes, NULL, 0, req->info,
+				   get_dynamic_sa_iv_size(ctx));
+}
+
+int crypto4xx_encrypt_ctr(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *ablkcipher =3D =
crypto_ablkcipher_reqtfm(req);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(req->base.tfm);
+
 	ctx->hash_final =3D 0;
 	ctx->is_hash =3D 0;
-	ctx->pd_ctl =3D 1;
+	ctx->pd_ctl =3D 0x1;
+	ctx->direction =3D DIR_OUTBOUND;
=20
 	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
-				  req->nbytes, req->info,
-				  get_dynamic_sa_iv_size(ctx));
+				  req->nbytes, NULL, 0,
+				  req->info,
+				  crypto_ablkcipher_ivsize(ablkcipher));
+}
+
+int crypto4xx_decrypt_ctr(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *ablkcipher =3D =
crypto_ablkcipher_reqtfm(req);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(req->base.tfm);
+
+	ctx->hash_final =3D 0;
+	ctx->is_hash =3D 0;
+	ctx->pd_ctl =3D 0x1;
+	ctx->direction =3D DIR_INBOUND;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->nbytes, NULL, 0,
+				  req->info,
+				  crypto_ablkcipher_ivsize(ablkcipher));
 }
=20
 /**
@@ -166,6 +534,13 @@ static int crypto4xx_setkey_aes(struct =
crypto_ablkcipher *cipher,
 	return 0;
 }
=20
+int crypto4xx_setkey_aes_ecb(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_ECB,
+				    CRYPTO_FEEDBACK_MODE_NO_FB);
+}
+
 int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher,
 			     const u8 *key, unsigned int keylen)
 {
@@ -173,8 +548,677 @@ int crypto4xx_setkey_aes_cbc(struct =
crypto_ablkcipher *cipher,
 				    CRYPTO_FEEDBACK_MODE_NO_FB);
 }
=20
+int crypto4xx_setkey_aes_ctr(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen)
+{
+	struct crypto_tfm    *tfm =3D crypto_ablkcipher_tfm(cipher);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(tfm);
+	struct dynamic_sa_ctl *sa;
+	u32 cnt =3D 1;
+	int    rc;
+	u32 cm =3D CRYPTO_MODE_AES_CTR;
+
+	keylen -=3D 4;
+	/* Create SA */
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		 crypto4xx_free_sa(ctx);
+
+	if (keylen !=3D AES_KEYSIZE_256 &&
+		   keylen !=3D AES_KEYSIZE_192 && keylen !=3D AES_KEYSIZE_128) {
+		crypto_ablkcipher_set_flags(cipher,
+					    CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	rc =3D crypto4xx_alloc_sa(ctx, SA_AES128_LEN + (keylen-16) / 4);
+	if (rc)
+		return rc;
+
+	if (ctx->state_record_dma_addr =3D=3D 0) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc) {
+			crypto4xx_free_sa(ctx);
+			return rc;
+		}
+	}
+
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	ctx->hash_final =3D 0;
+	ctx->ctr_aes =3D 1;
+	/* Setup SA */
+	set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
+				 SA_NO_HEADER_PROC, SA_HASH_ALG_NULL,
+				 SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO,
+				 SA_OP_GROUP_BASIC, SA_OPCODE_ENCRYPT,
+				 DIR_INBOUND);
+	set_dynamic_sa_command_1(sa, cm, SA_HASH_MODE_HASH,
+				 CRYPTO_FEEDBACK_MODE_NO_FB,
+				 SA_EXTENDED_SN_OFF, SA_SEQ_MASK_OFF,
+				 SA_MC_ENABLE, SA_NOT_COPY_PAD,
+				 SA_NOT_COPY_PAYLOAD,
+				 SA_NOT_COPY_HDR);
+
+	crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx),
+			    key, keylen);
+	sa->sa_contents =3D SA_AES_CONTENTS | (keylen << 2);
+	sa->sa_command_1.bf.key_len =3D keylen >> 3;
+
+	ctx->direction =3D DIR_INBOUND;
+	memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
+	       (void *)&ctx->state_record_dma_addr, 4);
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+
+	crypto4xx_memcpy_le(ctx->state_record, key + keylen, 4);
+	crypto4xx_memcpy_le(ctx->state_record + 12, (void *)&cnt, 4);
+
+	sa->sa_command_0.bf.dir =3D DIR_INBOUND;
+
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	sa->sa_command_0.bf.dir =3D DIR_OUTBOUND;
+
+	return 0;
+}
+
+int crypto4xx_setkey_aes_cfb(struct crypto_ablkcipher *cipher,
+					  const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CFB,
+				    CRYPTO_FEEDBACK_MODE_128BIT_CFB);
+}
+
+int crypto4xx_setkey_aes_ofb(struct crypto_ablkcipher *cipher,
+					  const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_OFB,
+				    CRYPTO_FEEDBACK_MODE_64BIT_OFB);
+}
+
+int crypto4xx_setkey_aes_icm(struct crypto_ablkcipher *cipher,
+					  const u8 *key, unsigned int keylen)
+{
+	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_AES_ICM,
+				    CRYPTO_FEEDBACK_MODE_NO_FB);
+}
+
+/**
+ * AES-GCM Functions
+ */
+static inline int crypto4xx_aes_gcm_validate_keylen(unsigned int =
keylen)
+{
+	switch (keylen) {
+	case 16:
+	case 20:
+	case 24:
+	case 30:
+	case 32:
+	case 36:
+		return 0;
+	default:
+		printk(KERN_ERR "crypto4xx_setkey_aes_gcm: "
+				"ERROR keylen =3D 0x%08x\n", keylen);
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+int crypto4xx_setkey_aes_gcm(struct crypto_aead *cipher,
+				     const u8 *key, unsigned int keylen)
+
+{
+	struct crypto_tfm    *tfm =3D crypto_aead_tfm(cipher);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(tfm);
+	struct dynamic_sa_ctl *sa;
+	int    rc =3D 0;
+
+	u32 cm =3D 4;
+
+	if (crypto4xx_aes_gcm_validate_keylen(keylen) !=3D 0) {
+		printk(KERN_ERR "crypto4xx_setkey_aes_gcm:"
+				"ERROR keylen =3D 0x%08x\n", keylen);
+		crypto_aead_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+	    return -EINVAL;
+	}
+
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		 crypto4xx_free_sa(ctx);
+
+	rc =3D crypto4xx_alloc_sa(ctx, SA_AES128_GCM_LEN + (keylen-16) / 4);
+	if (rc)
+		return rc;
+
+	if (ctx->state_record_dma_addr =3D=3D 0) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc)
+			goto err;
+	}
+
+	sa  =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+
+	sa->sa_contents =3D SA_AES_GCM_CONTENTS | (keylen << 2);
+	sa->sa_command_1.bf.key_len =3D keylen >> 3;
+
+	ctx->direction =3D DIR_INBOUND;
+	crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx),
+			    key, keylen);
+
+	memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
+	       (void *)&ctx->state_record_dma_addr, 4);
+
+	rc =3D crypto4xx_compute_gcm_hash_key_sw(ctx, key, keylen);
+	if (rc) {
+		printk(KERN_ERR "GCM hash key setting failed =3D %d\n", rc);
+		goto err;
+	}
+
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+	ctx->is_gcm =3D 1;
+	ctx->hash_final =3D 1;
+	ctx->is_hash =3D 0;
+	ctx->pd_ctl =3D 0x11;
+
+	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
+				 SA_NO_HEADER_PROC, SA_HASH_ALG_GHASH,
+				 SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO,
+				 SA_OP_GROUP_BASIC, SA_OPCODE_HASH_DECRYPT,
+				 DIR_INBOUND);
+
+	sa->sa_command_1.bf.crypto_mode31 =3D (cm & 4) >> 2;
+	sa->sa_command_1.bf.crypto_mode9_8 =3D (cm & 3);
+	sa->sa_command_1.bf.feedback_mode =3D 0;
+
+	sa->sa_command_1.bf.hash_crypto_offset =3D 0;
+	sa->sa_command_1.bf.sa_rev =3D 1;
+	sa->sa_command_1.bf.copy_payload =3D 1;
+
+	sa->sa_command_1.bf.copy_pad =3D 0;
+	sa->sa_command_1.bf.copy_hdr =3D 0;
+	sa->sa_command_1.bf.mutable_bit_proc =3D 1;
+	sa->sa_command_1.bf.seq_num_mask =3D 1;
+
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	sa->sa_command_0.bf.dir =3D DIR_OUTBOUND;
+	sa->sa_command_0.bf.opcode =3D SA_OPCODE_ENCRYPT_HASH;
+
+	return 0;
+err:
+	crypto4xx_free_sa(ctx);
+	return rc;
+}
+
+int crypto4xx_encrypt_aes_gcm(struct aead_request *req)
+{
+	struct crypto_aead *aead =3D crypto_aead_reqtfm(req);
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+
+	ctx->direction =3D DIR_OUTBOUND;
+	ctx->append_icv =3D 1;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->cryptlen, req->assoc, req->assoclen,
+				  req->iv, crypto_aead_ivsize(aead));
+}
+
+int crypto4xx_decrypt_aes_gcm(struct aead_request *req)
+{
+	struct crypto_aead *aead =3D crypto_aead_reqtfm(req);
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+	int len =3D req->cryptlen - crypto_aead_authsize(aead);
+
+	ctx->direction =3D DIR_INBOUND;
+	ctx->append_icv =3D 0;
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  len, req->assoc, req->assoclen,
+				  req->iv, crypto_aead_ivsize(aead));
+}
+
+int crypto4xx_givencrypt_aes_gcm(struct aead_givcrypt_request *req)
+{
+	return -ENOSYS;
+}
+
+int crypto4xx_givdecrypt_aes_gcm(struct aead_givcrypt_request *req)
+{
+	return -ENOSYS;
+}
+
 /**
- * HASH SHA1 Functions
+ * AES-CCM Functions
+ */
+int crypto4xx_setauthsize_aes(struct crypto_aead *ciper,
+			      unsigned int authsize)
+{
+	struct aead_tfm *tfm =3D crypto_aead_crt(ciper);
+
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+	case 10:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tfm->authsize =3D authsize;
+	return 0;
+}
+
+int crypto4xx_setkey_aes_ccm(struct crypto_aead *cipher, const u8 *key,
+				unsigned int keylen)
+{
+	struct crypto_tfm    *tfm =3D crypto_aead_tfm(cipher);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(tfm);
+	struct dynamic_sa_ctl *sa;
+	int rc =3D 0;
+
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		 crypto4xx_free_sa(ctx);
+
+	rc =3D crypto4xx_alloc_sa(ctx, SA_AES128_CCM_LEN + (keylen-16) / 4);
+	if (rc)
+		return rc;
+
+	if (ctx->state_record_dma_addr =3D=3D 0) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc) {
+			crypto4xx_free_sa(ctx);
+			return rc;
+		}
+	}
+
+	/* Setup SA */
+	sa  =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	sa->sa_contents =3D SA_AES_CCM_CONTENTS | (keylen << 2);
+
+	set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
+				 SA_NO_HEADER_PROC, SA_HASH_ALG_CBC_MAC,
+				 SA_CIPHER_ALG_AES,
+				 SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+				 SA_OPCODE_HASH_DECRYPT, DIR_INBOUND);
+
+	sa->sa_command_0.bf.digest_len =3D 0;
+	sa->sa_command_1.bf.key_len =3D keylen >> 3;
+	ctx->direction =3D DIR_INBOUND;
+	ctx->append_icv =3D 0;
+	ctx->is_gcm =3D 0;
+	ctx->hash_final =3D 1;
+	ctx->is_hash =3D 0;
+	ctx->pd_ctl =3D 0x11;
+
+	crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx),
+			    key, keylen);
+	memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
+	       (void *)&ctx->state_record_dma_addr, 4);
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+
+	set_dynamic_sa_command_1(sa, CRYPTO_MODE_AES_CTR, SA_HASH_MODE_HASH,
+				 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+				 SA_NOT_COPY_PAD, SA_COPY_PAYLOAD,
+				 SA_NOT_COPY_HDR);
+
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
+				 SA_NO_HEADER_PROC, SA_HASH_ALG_CBC_MAC,
+				 SA_CIPHER_ALG_AES,
+				 SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+				 SA_OPCODE_ENCRYPT_HASH, DIR_OUTBOUND);
+	set_dynamic_sa_command_1(sa, CRYPTO_MODE_AES_CTR, SA_HASH_MODE_HASH,
+				 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+				 SA_NOT_COPY_PAD, SA_COPY_PAYLOAD,
+				 SA_NOT_COPY_HDR);
+
+	return 0;
+}
+
+int crypto4xx_encrypt_aes_ccm(struct aead_request *req)
+{
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+	struct crypto_aead *aead =3D crypto_aead_reqtfm(req);
+	struct dynamic_sa_ctl *sa;
+
+	ctx->direction =3D DIR_OUTBOUND;
+
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	if (req->assoclen)
+		sa->sa_command_1.bf.hash_crypto_offset =3D req->assoclen >> 2;
+
+	sa->sa_command_0.bf.digest_len =3D (crypto_aead_authsize(aead) >> 2);
+	if ((req->iv[0] & 7) =3D=3D 1)
+		sa->sa_command_1.bf.crypto_mode9_8 =3D 1;
+
+	ctx->append_icv =3D 1;
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->cryptlen, req->assoc, req->assoclen,
+				  req->iv, 16);
+}
+
+int crypto4xx_decrypt_aes_ccm(struct aead_request *req)
+{
+	struct crypto4xx_ctx   *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+	struct crypto_aead *aead =3D crypto_aead_reqtfm(req);
+	struct dynamic_sa_ctl *sa;
+
+	/* Support only counter field length of 2 and 4 bytes */
+	if ((req->iv[0] & 0x7) !=3D 1 && (req->iv[0] & 0x7) !=3D 3) {
+		printk(KERN_ERR "algorithm AES-CCM "
+				"unsupported counter length %d\n",
+			req->iv[0] & 0x7);
+		return -EINVAL;
+	}
+
+	ctx->direction =3D DIR_INBOUND;
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+
+	sa->sa_command_0.bf.digest_len =3D (crypto_aead_authsize(aead) >> 2);
+	if ((req->iv[0] & 7) =3D=3D 1)
+		sa->sa_command_1.bf.crypto_mode9_8 =3D 1;
+	else
+		sa->sa_command_1.bf.crypto_mode9_8 =3D 0;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->cryptlen, req->assoc, req->assoclen,
+				  req->iv, 16);
+}
+
+int crypto4xx_givencrypt_aes_ccm(struct aead_givcrypt_request *req)
+{
+	return -ENOSYS;
+}
+
+int crypto4xx_givdecrypt_aes_ccm(struct aead_givcrypt_request *req)
+{
+	return -ENOSYS;
+}
+
+/**
+ * Kasumi Functions
+ *
+ */
+int crypto4xx_setkey_kasumi(struct crypto_ablkcipher *cipher,
+				   const u8 *key,
+				   unsigned int keylen,
+				   unsigned char cm)
+{
+	struct crypto_tfm *tfm =3D crypto_ablkcipher_tfm(cipher);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(tfm);
+	struct dynamic_sa_ctl *sa;
+	u32 sa_len =3D 0;
+	int rc;
+
+	if (keylen !=3D 16) {
+		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		printk(KERN_ERR "%s: keylen fail\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Create SA - SA is created here as the alg init function is
+	 * common to many algorithm and it does not have the SA length
+	 * as it is specify to an algorithm. See setkey function has
+	 * to be called for encryption/decryption algorithm once,
+	 * it is okay to do this here.
+	 */
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		 crypto4xx_free_sa(ctx);
+
+	if (cm =3D=3D CRYPTO_MODE_KASUMI)
+		 sa_len =3D SA_KASUMI_LEN;
+	else if (cm =3D=3D CRYPTO_MODE_KASUMI_f8)
+		 sa_len =3D SA_KASUMI_F8_LEN;
+
+	rc =3D crypto4xx_alloc_sa(ctx, sa_len);
+	if (rc)
+		return rc;
+
+	if (!ctx->state_record) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc) {
+			crypto4xx_free_sa(ctx);
+			return rc;
+		}
+	}
+
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	/* Setup SA - SA is a shared resource for request operation. As
+	 * crypto alg and crypto mode can not be change, it should be
+	 * ok to store them there. SA control words are not used by the
+	 * hardware (configured in token instead), we use it to store
+	 * software algorithm and mode selected.
+	 */
+
+	if (cm =3D=3D CRYPTO_MODE_KASUMI) {
+		sa->sa_contents =3D SA_KASUMI_CONTENTS;
+		sa->sa_command_0.bf.cipher_alg =3D SA_CIPHER_ALG_KASUMI;
+		sa->sa_command_0.bf.hash_alg =3D SA_HASH_ALG_NULL;
+		sa->sa_command_0.bf.pad_type =3D 3; /* set to zero padding */
+		sa->sa_command_0.bf.opcode =3D 0;
+		sa->sa_command_1.bf.crypto_mode31 =3D (cm & 4) >> 2;
+		sa->sa_command_1.bf.crypto_mode9_8 =3D (cm & 3);
+		sa->sa_command_1.bf.feedback_mode =3D 0;
+	} else {
+		sa->sa_contents =3D SA_KASUMI_F8_CONTENTS;
+		sa->sa_command_0.bf.cipher_alg =3D SA_CIPHER_ALG_KASUMI;
+		sa->sa_command_0.bf.hash_alg =3D SA_HASH_ALG_NULL;
+		sa->sa_command_0.bf.pad_type =3D 3;
+		sa->sa_command_0.bf.load_iv =3D SA_LOAD_IV_FROM_STATE;
+		sa->sa_command_0.bf.opcode =3D SA_OPCODE_ENCRYPT;
+		sa->sa_command_1.bf.crypto_mode31 =3D (cm & 4) >> 2;;
+		sa->sa_command_1.bf.crypto_mode9_8 =3D (cm & 3);
+		sa->sa_command_1.bf.feedback_mode =3D 0;
+		sa->sa_command_1.bf.mutable_bit_proc =3D 1;
+	}
+
+	ctx->direction =3D DIR_INBOUND;
+	sa->sa_command_1.bf.sa_rev =3D 1;
+	crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx),
+			    key, keylen);
+	ctx->is_hash =3D 0;
+
+	memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
+	       (void *)&ctx->state_record_dma_addr, 4);
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+	sa->sa_command_0.bf.dir =3D DIR_INBOUND;
+
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	sa->sa_command_0.bf.dir =3D DIR_OUTBOUND;
+
+	return 0;
+}
+
+int crypto4xx_setkey_kasumi_p(struct crypto_ablkcipher *cipher,
+					const u8 *key,
+					unsigned int keylen)
+{
+	return crypto4xx_setkey_kasumi(cipher, key, keylen,
+				       CRYPTO_MODE_KASUMI);
+}
+
+int crypto4xx_setkey_kasumi_f8(struct crypto_ablkcipher *cipher,
+					     const u8 *key,
+					     unsigned int keylen)
+{
+	return crypto4xx_setkey_kasumi(cipher, key, keylen,
+				       CRYPTO_MODE_KASUMI_f8);
+}
+
+/**
+ * Kasumi and Kasumi f8 work with number of bits.
+ * The crypto engine can only take number bytes as source/destination =
length
+ * User should round up bit number to byte number. When receive the =
result
+ * packet and then mask off the extra bits in the last
+ * byte.
+ */
+int crypto4xx_encrypt_kasumi(struct ablkcipher_request *req)
+{
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+	ctx->direction =3D DIR_OUTBOUND;
+	ctx->pd_ctl =3D 0x1;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->nbytes, NULL, 0, NULL, 0);
+}
+
+/**
+ * Kasumi and Kasumi f8 work with number of bits.
+ * The crypto engine can only take number bytes as source/destination =
length
+ * User should round up bit number to byte number.
+ * When receive the result packet and then mask off the extra bits in =
the last
+ * byte.
+ */
+int crypto4xx_decrypt_kasumi(struct aead_request *req)
+{
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+
+	ctx->pd_ctl =3D 0x1;
+	ctx->direction =3D DIR_INBOUND;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->cryptlen, NULL, 0, NULL, 0);
+}
+
+/**
+ * Kasumi and Kasumi f8 work with number of bits.
+ * The crypto engine can only take number bytes as source/destination =
length
+ * The user should round up bit number to byte number.
+ * When receive the result packet and then mask
+ * off the extra bits in the last byte.
+ */
+int crypto4xx_encrypt_kasumi_f8(struct ablkcipher_request *req)
+{
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+
+	ctx->direction =3D DIR_OUTBOUND;
+	ctx->is_hash =3D 0;
+	ctx->pd_ctl =3D 0x1;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->nbytes, NULL, 0, req->info, 8);
+}
+
+/** Note:
+ * Kasumi and Kasumi f8 work with number of bits.
+ * The crypto engine can only take number bytes as source/destination =
length
+ *  User should round up bit number to byte number.
+ * When receive the result packet and then mask off the extra bits in =
the last
+ * byte.
+ */
+int crypto4xx_decrypt_kasumi_f8(struct ablkcipher_request *req)
+{
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+
+	ctx->direction =3D DIR_INBOUND;
+	ctx->is_hash =3D 0;
+	ctx->pd_ctl =3D 0x1;
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+				  req->nbytes, NULL, 0, req->info, 8);
+}
+
+/**
+ * ARC4 Functions
+ *
+ */
+int crypto4xx_setkey_arc4(struct crypto_ablkcipher *cipher,
+				 const u8 *key, unsigned int keylen)
+{
+	struct crypto_tfm *tfm =3D crypto_ablkcipher_tfm(cipher);
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(tfm);
+	struct dynamic_sa_ctl *sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	int rc =3D 0;
+
+	/* Create SA */
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		crypto4xx_free_sa(ctx);
+
+	rc =3D crypto4xx_alloc_sa(ctx, SA_ARC4_LEN);
+	if (rc)
+		return rc;
+
+	crypto4xx_alloc_arc4_state_record(ctx);
+	if (ctx->arc4_state_record =3D=3D NULL) {
+		crypto4xx_free_sa(ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup SA */
+	ctx->sa_len =3D SA_ARC4_LEN;
+	ctx->init_arc4 =3D 1;
+	ctx->direction =3D DIR_INBOUND;
+
+	sa =3D ctx->sa_in;
+	memset(((struct dynamic_sa_arc4 *)sa)->key, 0, 16);
+
+	crypto4xx_memcpy_le(((struct dynamic_sa_arc4 *)sa)->key, key, keylen);
+	sa->sa_contents =3D SA_ARC4_CONTENTS;
+
+	set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
+				 SA_NO_HEADER_PROC, SA_HASH_ALG_NULL,
+				 SA_CIPHER_ALG_ARC4, SA_PAD_TYPE_ZERO,
+				 SA_OP_GROUP_BASIC, SA_OPCODE_ENCRYPT,
+				 DIR_INBOUND);
+
+	set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH,
+				 CRYPTO_FEEDBACK_MODE_NO_FB,
+				 SA_EXTENDED_SN_OFF, SA_SEQ_MASK_OFF,
+				 SA_MC_ENABLE, SA_NOT_COPY_PAD,
+				 SA_COPY_PAYLOAD, SA_NOT_COPY_HDR);
+
+	sa->sa_command_1.bf.key_len =3D keylen;
+	memcpy(sa + get_dynamic_sa_offset_arc4_state_ptr(ctx),
+	       (void *)&ctx->arc4_state_record_dma_addr, 4);
+
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	sa->sa_command_0.bf.dir =3D DIR_OUTBOUND;
+
+	return 0;
+}
+
+int crypto4xx_arc4_encrypt(struct ablkcipher_request *req)
+{
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+
+	if (ctx->init_arc4) {
+		ctx->init_arc4 =3D 0;
+		ctx->pd_ctl =3D 9;
+	} else {
+		ctx->pd_ctl =3D 0x1;
+	}
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src,
+				  req->dst,
+				  req->nbytes, NULL, 0, NULL, 0);
+}
+
+int crypto4xx_arc4_decrypt(struct ablkcipher_request *req)
+{
+	struct crypto4xx_ctx *ctx  =3D crypto_tfm_ctx(req->base.tfm);
+
+	if (ctx->init_arc4) {
+		ctx->init_arc4 =3D 0;
+		ctx->pd_ctl =3D 9;
+	} else {
+		ctx->pd_ctl =3D 0x1;
+	}
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src,
+				  req->dst,
+				  req->nbytes, NULL, 0, NULL, 0);
+}
+
+/**
+ * Support MD5/SHA/HMAC Hashing Algorithms
+ *
  */
 static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
 				   unsigned int sa_len,
@@ -185,7 +1229,6 @@ static int crypto4xx_hash_alg_init(struct =
crypto_tfm *tfm,
 	struct crypto4xx_alg *my_alg =3D crypto_alg_to_crypto4xx_alg(alg);
 	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(tfm);
 	struct dynamic_sa_ctl *sa;
-	struct dynamic_sa_hash160 *sa_in;
 	int rc;
=20
 	ctx->dev   =3D my_alg->dev;
@@ -210,6 +1253,9 @@ static int crypto4xx_hash_alg_init(struct =
crypto_tfm *tfm,
=20
 	tfm->crt_ahash.reqsize =3D sizeof(struct crypto4xx_ctx);
 	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	/*
+	 * Setup hash algorithm and hash mode
+	 */
 	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
 				 SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
 				 SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
@@ -220,13 +1266,12 @@ static int crypto4xx_hash_alg_init(struct =
crypto_tfm *tfm,
 				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
 				 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
 				 SA_NOT_COPY_HDR);
+
+	BUG_ON(ha >=3D HASH_ALG_MAX_CNT);
+	sa->sa_contents =3D crypto4xx_sa_hash_tbl[0][ha];
 	ctx->direction =3D DIR_INBOUND;
-	sa->sa_contents =3D SA_HASH160_CONTENTS;
-	sa_in =3D (struct dynamic_sa_hash160 *) ctx->sa_in;
-	/* Need to zero hash digest in SA */
-	memset(sa_in->inner_digest, 0, sizeof(sa_in->inner_digest));
-	memset(sa_in->outer_digest, 0, sizeof(sa_in->outer_digest));
-	sa_in->state_ptr =3D ctx->state_record_dma_addr;
+	memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
+		(void *)&ctx->state_record_dma_addr, 4);
 	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
=20
 	return 0;
@@ -260,7 +1305,7 @@ int crypto4xx_hash_update(struct ahash_request =
*req)
=20
 	return crypto4xx_build_pd(&req->base, ctx, req->src,
 				  (struct scatterlist *) req->result,
-				  req->nbytes, NULL, 0);
+				  req->nbytes, NULL, 0, NULL, 0);
 }
=20
 int crypto4xx_hash_final(struct ahash_request *req)
@@ -278,16 +1323,431 @@ int crypto4xx_hash_digest(struct ahash_request =
*req)
=20
 	return crypto4xx_build_pd(&req->base, ctx, req->src,
 				  (struct scatterlist *) req->result,
-				  req->nbytes, NULL, 0);
+				  req->nbytes, NULL, 0, NULL, 0);
 }
=20
 /**
  * SHA1 Algorithm
  */
+
+int crypto4xx_md5_alg_init(struct crypto_tfm *tfm)
+{
+	return crypto4xx_hash_alg_init(tfm, SA_HASH128_LEN, SA_HASH_ALG_MD5,
+				       SA_HASH_MODE_HASH);
+}
+
+int crypto4xx_hash_hmac_setkey(struct crypto_ahash *hash,
+				      const u8 *key,
+				      unsigned int keylen,
+				      unsigned int sa_len,
+				      unsigned char ha,
+				      unsigned char hm,
+				      unsigned int max_keylen)
+{
+	struct crypto_tfm	*tfm =3D crypto_ahash_tfm(hash);
+	struct crypto_alg	*alg	 =3D tfm->__crt_alg;
+	struct crypto4xx_alg   *my_alg   =3D crypto_alg_to_crypto4xx_alg(alg);
+	struct crypto4xx_ctx	*ctx =3D crypto_tfm_ctx(tfm);
+	struct dynamic_sa_ctl *sa;
+	int bs 	=3D crypto_tfm_alg_blocksize(tfm);
+	int ds 	=3D crypto_ahash_digestsize(hash);
+	int rc;
+
+	ctx->dev =3D my_alg->dev;
+
+	if (keylen > max_keylen) {
+		crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -1;
+	}
+
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		crypto4xx_free_sa(ctx);
+
+	/* Create SA */
+	rc =3D crypto4xx_alloc_sa(ctx, sa_len);
+	if (rc)
+		return rc;
+
+	if (ctx->state_record_dma_addr =3D=3D 0) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc)
+			goto err;
+	}
+
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+
+	/*
+	 * Setup hash algorithm and hash mode
+	 */
+	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+				 SA_NO_HEADER_PROC,
+				 ha, SA_CIPHER_ALG_NULL, SA_PAD_TYPE_ZERO,
+				 SA_OP_GROUP_BASIC, SA_OPCODE_HASH,
+				 DIR_INBOUND);
+	set_dynamic_sa_command_1(sa, 0, hm,
+				 CRYPTO_FEEDBACK_MODE_NO_FB,
+				 SA_EXTENDED_SN_OFF,
+				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+				 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+				 SA_NOT_COPY_HDR);
+
+	BUG_ON(ha >=3D HASH_ALG_MAX_CNT);
+	sa->sa_contents =3D crypto4xx_sa_hash_tbl[0][ha];
+	ctx->direction =3D DIR_INBOUND;
+	memcpy((ctx->sa_in) + get_dynamic_sa_offset_state_ptr_field(ctx),
+	       (void *)&ctx->state_record_dma_addr, 4);
+
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+	rc =3D crypto4xx_pre_compute_hmac(ctx, (void *)key, keylen, bs, ha, =
ds);
+	if (rc) {
+		printk(KERN_ERR "Hmac Initial Digest Calculation failed\n");
+		goto err;
+	}
+
+	ctx->hash_final =3D 1;
+	ctx->is_hash =3D 1;
+
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	sa->sa_command_0.bf.dir =3D DIR_OUTBOUND;
+
+	return 0;
+err:
+	crypto4xx_free_sa(ctx);
+	return rc;
+}
+
+int crypto4xx_md5_hmac_setkey(struct crypto_ahash *hash, const u8 *key,
+			      unsigned int keylen)
+{
+	return crypto4xx_hash_hmac_setkey(hash, key, keylen, SA_HASH128_LEN,
+					  SA_HASH_ALG_MD5, SA_HASH_MODE_HMAC,
+					  256);
+}
+
+/**
+ * SHA1 and SHA2 Algorithm
+ *
+ */
 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);
 }
=20
+int crypto4xx_sha1_hmac_setkey(struct crypto_ahash *hash, const u8 =
*key,
+			       unsigned int keylen)
+{
+	return crypto4xx_hash_hmac_setkey(hash, key, keylen, SA_HASH160_LEN,
+					  SA_HASH_ALG_SHA1, SA_HASH_MODE_HMAC,
+					  256);
+}
+
+int crypto4xx_sha2_alg_init(struct crypto_tfm *tfm)
+{
+	int ds =3D crypto_ahash_digestsize(__crypto_ahash_cast(tfm));
+	u8 ha;
+
+	switch (ds) {
+	default:
+	case 256/8:
+		ha =3D SA_HASH_ALG_SHA256;
+		break;
+	case 224/8:
+		ha =3D SA_HASH_ALG_SHA224;
+		break;
+	case 512/8:
+		ha =3D SA_HASH_ALG_SHA512;
+		break;
+	case 384/8:
+		ha =3D SA_HASH_ALG_SHA384;
+		break;
+	}
+	BUG_ON(ha >=3D HASH_ALG_MAX_CNT);
+
+	return crypto4xx_hash_alg_init(tfm,
+				       crypto4xx_sa_hash_tbl[2][ha], ha, 0);
+}
+
+int crypto4xx_sha2_hmac_setkey(struct crypto_ahash *hash,
+				      const u8 *key,
+				      unsigned int keylen)
+{
+	int ds =3D crypto_ahash_digestsize(hash);
+	unsigned char ha;
+
+	switch (ds) {
+	default:
+	case 256/8:
+		ha =3D SA_HASH_ALG_SHA256;
+		break;
+	case 224/8:
+		ha =3D SA_HASH_ALG_SHA224;
+		break;
+	case 512/8:
+		ha =3D SA_HASH_ALG_SHA512;
+		break;
+	case 384/8:
+		ha =3D SA_HASH_ALG_SHA384;
+		break;
+	}
+	BUG_ON(ha >=3D HASH_ALG_MAX_CNT);
+
+	return crypto4xx_hash_hmac_setkey(hash, key, keylen,
+					  crypto4xx_sa_hash_tbl[2][ha],
+					  ha,
+					  SA_HASH_MODE_HMAC,
+					  512);
+}
+
+/**
+ * AES-XCBC-MAC Algorithm
+ *
+ */
+int crypto4xx_xcbc_digest(const unsigned char *key,
+			  unsigned int keylen,
+			  u8 *sa_hash, int bs)
+{
+	struct scatterlist 	sg[1];
+	struct crypto_blkcipher *aes_tfm =3D NULL;
+	struct blkcipher_desc 	desc;
+	int rc;
+	u8 *digest;
+
+	/* Load pre-computed key value into SA */
+	aes_tfm =3D crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(aes_tfm)) {
+		rc =3D PTR_ERR(aes_tfm);
+		printk(KERN_ERR "failed to load transform"
+				" for ecb(aes) error %d\n", rc);
+		goto err_alg;
+	}
+	desc.tfm    =3D aes_tfm;
+	desc.flags  =3D 0;
+	rc =3D crypto_blkcipher_setkey(desc.tfm, key, keylen);
+	if (rc) {
+		printk(KERN_ERR  "failed to load key error %d\n", rc);
+		goto err_alg;
+	}
+	digest =3D  kmalloc(16, GFP_KERNEL);
+	if (digest =3D=3D NULL) {
+		rc =3D -ENOMEM;
+		goto err_alg;
+	}
+
+	memset(digest, 0x01, bs);
+	sg_init_one(&sg[0], digest, bs);
+	rc =3D crypto_blkcipher_encrypt(&desc, sg, sg, bs);
+	if (rc < 0) {
+		printk(KERN_ERR "failed to hash key error %d\n", rc);
+		goto err_alg;
+	}
+
+	crypto4xx_memcpy_le((void *) sa_hash, digest, bs);
+
+	memset(digest, 0x02, bs);
+	sg_init_one(&sg[0], digest, bs);
+	rc =3D crypto_blkcipher_encrypt(&desc, sg, sg, bs);
+	if (rc < 0) {
+		printk(KERN_ERR "failed to hash key error %d\n", rc);
+		goto err_alg;
+	}
+
+	sa_hash +=3D 32;
+	crypto4xx_memcpy_le((void *) sa_hash, digest, bs);
+
+	memset(digest, 0x03, bs);
+	sg_init_one(&sg[0], digest, bs);
+	rc =3D crypto_blkcipher_encrypt(&desc, sg, sg, bs);
+	if (rc < 0) {
+		printk(KERN_ERR "failed to hash key error %d\n", rc);
+		goto err_alg;
+	}
+
+	sa_hash +=3D 16;
+	crypto4xx_memcpy_le((void *) sa_hash, digest, bs);
+
+	crypto_free_blkcipher(aes_tfm);
+
+	return 0;
+err_alg:
+	if (aes_tfm)
+		crypto_free_blkcipher(aes_tfm);
+	return rc;
+}
+
+int crypto4xx_xcbc_setkey(struct crypto_ahash *hash,
+				      const u8 *key,
+				      unsigned int keylen)
+{
+	struct crypto_tfm    	*tfm =3D crypto_ahash_tfm(hash);
+	struct crypto4xx_ctx 	*ctx =3D crypto_tfm_ctx(tfm);
+	int bs =3D crypto_tfm_alg_blocksize(tfm);
+	struct dynamic_sa_ctl *sa;
+	u8 *sa_hash;
+	int rc =3D 0;
+
+	if (keylen !=3D 128/8) {
+		crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		 crypto4xx_free_sa(ctx);
+
+	/* Create SA */
+	rc =3D crypto4xx_alloc_sa(ctx, SA_AES128_XCBC_MAC_LEN);
+	if (rc)
+		return rc;
=20
+	if (ctx->state_record_dma_addr =3D=3D 0) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc) {
+			rc =3D -ENOMEM;
+			goto err;
+		}
+	}
+
+	ctx->direction =3D DIR_INBOUND;
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	/*
+	 * Setup hash algorithm and hash mode
+	 */
+	sa->sa_contents =3D SA_AES128_XCBC_MAC_CONTENTS;
+	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+				 SA_NO_HEADER_PROC,
+				 SA_HASH_ALG_AES_XCBC_MAC_128,
+				 SA_CIPHER_ALG_NULL, SA_PAD_TYPE_ZERO,
+				 SA_OP_GROUP_BASIC, SA_OPCODE_HASH,
+				 DIR_INBOUND);
+	set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH,
+				 CRYPTO_FEEDBACK_MODE_NO_FB,
+				 SA_EXTENDED_SN_OFF,
+				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+				 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+				 SA_NOT_COPY_HDR);
+	crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx),
+			    key, keylen);
+
+	memcpy((void *)(ctx->sa_in +
+			get_dynamic_sa_offset_state_ptr_field(ctx)),
+		(void *)&ctx->state_record_dma_addr, 4);
+	ctx->is_hash =3D 1;
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+	sa_hash =3D (u8 *)(&(((struct dynamic_sa_aes128_xcbc_mac *)
+			ctx->sa_in)->inner_digest));
+	rc =3D crypto4xx_xcbc_digest(key, keylen, sa_hash, bs);
+	if (rc) {
+		printk(KERN_ERR "XCBC Digest Calculation Failed %d\n", rc);
+		goto err;
+	}
+
+	ctx->is_hash =3D 1;
+	ctx->hash_final =3D 1;
+	ctx->pd_ctl =3D 0x11;
+
+	ctx->direction =3D DIR_INBOUND;
+
+	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_out;
+	sa->sa_command_0.bf.dir =3D DIR_OUTBOUND;
+
+	return 0;
+err:
+	crypto4xx_free_sa(ctx);
+	return rc;
+}
+
+/**
+ * Kasumi F9 - Hash Algorithms
+ *
+ */
+int crypto4xx_kasumi_f9_setkey(struct crypto_ahash *hash,
+			       const u8 *key, unsigned int keylen)
+{
+	struct crypto_tfm	*tfm =3D crypto_ahash_tfm(hash);
+	struct crypto4xx_ctx	*ctx =3D crypto_tfm_ctx(tfm);
+	int 	rc;
+	struct dynamic_sa_ctl *sa;
+
+	if (keylen !=3D 16) {
+		crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	/* Create SA */
+	if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+		 crypto4xx_free_sa(ctx);
+
+	rc =3D crypto4xx_alloc_sa(ctx, SA_KASUMI_F9_LEN);
+	if (rc)
+		return rc;
+
+	if (ctx->state_record_dma_addr =3D=3D 0) {
+		rc =3D crypto4xx_alloc_state_record(ctx);
+		if (rc) {
+			crypto4xx_free_sa(ctx);
+			return rc;
+		}
+	}
+
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+	/*
+	 * Setup hash algorithm and hash mode
+	 */
+	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+				 SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+				 SA_NO_HEADER_PROC, SA_HASH_ALG_KASUMI_f9,
+				 SA_CIPHER_ALG_NULL, SA_PAD_TYPE_ZERO,
+				 SA_OP_GROUP_BASIC, SA_OPCODE_HASH,
+				 DIR_INBOUND);
+	set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH,
+				 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+				 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+				 SA_NOT_COPY_HDR);
+	sa->sa_contents =3D SA_KASUMI_F9_CONTENTS;
+
+	ctx->direction =3D DIR_INBOUND;
+	memcpy((void *)(ctx->sa_in +
+			get_dynamic_sa_offset_state_ptr_field(ctx)),
+			(void *)&ctx->state_record_dma_addr, 4);
+
+	crypto4xx_memcpy_le(ctx->sa_in +
+			get_dynamic_sa_offset_inner_digest(ctx), key, keylen);
+	ctx->offset_to_sr_ptr =3D get_dynamic_sa_offset_state_ptr_field(ctx);
+	ctx->is_hash =3D 1;
+	ctx->hash_final =3D 1;
+	ctx->pd_ctl =3D 0x11;
+	ctx->bypass =3D 4;
+
+	return 0;
+}
+
+int crypto4xx_kasumi_f9_digest(struct ahash_request *req)
+{
+	struct crypto4xx_ctx *ctx =3D crypto_tfm_ctx(req->base.tfm);
+	struct scatterlist *src =3D req->src;
+	struct dynamic_sa_ctl *sa;
+	dma_addr_t addr;
+
+	/*
+	 * We have prepended count/fresh/direction/reserv total
+	 * 16byte before the plaintext
+	 * so, need to modify the length.
+	 * We doing so, to make use of tcrypt.c's hash_test.
+	 */
+	sa =3D (struct dynamic_sa_ctl *) ctx->sa_in;
+
+	addr =3D dma_map_page(NULL, sg_page(src), src->offset,
+			    src->length, DMA_TO_DEVICE);
+	crypto4xx_memcpy_le((void *)sa +
+			get_dynamic_sa_offset_outer_digest(ctx),
+			phys_to_virt(addr), 12);
+
+	return crypto4xx_build_pd(&req->base, ctx, req->src,
+				  (struct scatterlist *)req->result,
+				  req->nbytes, NULL, 0, NULL, 0);
+}
diff --git a/drivers/crypto/amcc/crypto4xx_core.c =
b/drivers/crypto/amcc/crypto4xx_core.c
index 4c0dfb2..0fef1f2 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -28,13 +28,18 @@
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/highmem.h>
 #include <asm/dcr.h>
 #include <asm/dcr-regs.h>
 #include <asm/cacheflush.h>
 #include <crypto/internal/hash.h>
 #include <crypto/algapi.h>
 #include <crypto/aes.h>
+#include <crypto/des.h>
 #include <crypto/sha.h>
+#include <crypto/ctr.h>
 #include "crypto4xx_reg_def.h"
 #include "crypto4xx_core.h"
 #include "crypto4xx_sa.h"
@@ -153,6 +158,8 @@ void crypto4xx_free_sa(struct crypto4xx_ctx *ctx)
=20
 	ctx->sa_in_dma_addr =3D 0;
 	ctx->sa_out_dma_addr =3D 0;
+	ctx->sa_in =3D NULL;
+	ctx->sa_out =3D NULL;
 	ctx->sa_len =3D 0;
 }
=20
@@ -178,6 +185,31 @@ void crypto4xx_free_state_record(struct =
crypto4xx_ctx *ctx)
 	ctx->state_record_dma_addr =3D 0;
 }
=20
+u32 crypto4xx_alloc_arc4_state_record(struct crypto4xx_ctx *ctx)
+{
+	ctx->arc4_state_record =3D =
dma_alloc_coherent(ctx->dev->core_dev->device,
+			sizeof(struct arc4_sr),
+			&ctx->arc4_state_record_dma_addr,
+			GFP_ATOMIC);
+	if (!ctx->arc4_state_record_dma_addr)
+		return -ENOMEM;
+
+	memset(ctx->arc4_state_record, 0, sizeof(struct arc4_sr));
+
+	return 0;
+}
+
+void crypto4xx_free_arc4_state_record(struct crypto4xx_ctx *ctx)
+{
+	if (ctx->arc4_state_record !=3D NULL) {
+		dma_free_coherent(ctx->dev->core_dev->device,
+				  sizeof(struct arc4_sr),
+				  ctx->arc4_state_record,
+				  ctx->arc4_state_record_dma_addr);
+	}
+	ctx->arc4_state_record_dma_addr =3D 0;
+}
+
 /**
  * alloc memory for the gather ring
  * no need to alloc buf for the ring
@@ -528,7 +560,7 @@ static u32 crypto4xx_fill_one_page(struct =
crypto4xx_device *dev,
 			(*idx)++;
=20
 		return 0;
-    }
+	}
 }
=20
 static void crypto4xx_copy_pkt_to_dst(struct crypto4xx_device *dev,
@@ -591,9 +623,25 @@ static u32 crypto4xx_copy_digest_to_dst(struct =
pd_uinfo *pd_uinfo,
 	struct sa_state_record *state_record =3D
 				(struct sa_state_record *) pd_uinfo->sr_va;
=20
-	if (sa->sa_command_0.bf.hash_alg =3D=3D SA_HASH_ALG_SHA1) {
-		memcpy((void *) pd_uinfo->dest_va, state_record->save_digest,
-		       SA_HASH_ALG_SHA1_DIGEST_SIZE);
+	switch (sa->sa_command_0.bf.hash_alg) {
+	case SA_HASH_ALG_KASUMI_f9:
+		crypto4xx_memcpy_le((void *)pd_uinfo->dest_va,
+				     (u8 *)state_record->save_digest, 8);
+		break;
+	case SA_HASH_ALG_AES_XCBC_MAC_128:
+		crypto4xx_memcpy_le((void *)pd_uinfo->dest_va,
+				     (u8 *) state_record->save_digest, 16);
+		break;
+	case SA_HASH_ALG_MD5:
+		crypto4xx_memcpy_le((void *)pd_uinfo->dest_va,
+				     (u8 *) state_record->save_digest,
+				     SA_HASH_ALG_MD5_DIGEST_SIZE);
+		break;
+	default:
+		memcpy((void *)pd_uinfo->dest_va,
+			state_record->save_digest,
+			crypto4xx_sa_hash_tbl[1][sa->sa_command_0.bf.hash_alg]);
+		break;
 	}
=20
 	return 0;
@@ -618,6 +666,57 @@ static void crypto4xx_ret_sg_desc(struct =
crypto4xx_device *dev,
 	}
 }
=20
+void crypto4xx_append_icv_to_end(struct crypto4xx_device *dev,
+				 struct scatterlist *dst,
+				 struct sa_state_record *sr,
+				 u32 offset,
+				 u32 len)
+{
+	struct scatterlist *sg;
+	int i =3D 0;
+	u32 cp_len;
+	dma_addr_t addr;
+
+	sg =3D &dst[i];
+	while (len) {
+		while (sg->length < offset) {
+			offset -=3D sg->length;
+			i++;
+			sg =3D &sg[i];
+		}
+		/* at here, icv could be in this sg,
+		* or icv could be in the next sg
+		*/
+		if (sg->length > offset) {
+			/* icv should be in middle of this sg */
+			addr =3D dma_map_page(dev->core_dev->device, sg_page(sg),
+					    sg->offset,
+					    sg->length, DMA_TO_DEVICE);
+			cp_len =3D (sg->length-offset >=3D len) ? len :
+					sg->length-offset;
+			len -=3D cp_len;
+			crypto4xx_memcpy_le((u32 *)(phys_to_virt(addr)
+					+ offset),
+					(u8 *)sr->save_digest, cp_len);
+		} else {
+			/* start from begin of next sg*/
+			i++;
+			sg =3D &sg[i];
+			offset =3D 0;
+			addr =3D dma_map_page(dev->core_dev->device, sg_page(sg),
+					    sg->offset,
+					    sg->length, DMA_FROM_DEVICE);
+			cp_len =3D (sg->length >=3D len) ? len : sg->length;
+			len -=3D cp_len;
+			crypto4xx_memcpy_le((u32 *) (phys_to_virt(addr)
+					+ offset),
+					(u8 *) sr->save_digest, cp_len);
+		}
+		i++;
+		sg =3D &sg[i];
+	}
+}
+
 static u32 crypto4xx_ablkcipher_done(struct crypto4xx_device *dev,
 				     struct pd_uinfo *pd_uinfo,
 				     struct ce_pd *pd)
@@ -664,18 +763,67 @@ static u32 crypto4xx_ahash_done(struct =
crypto4xx_device *dev,
 	return 0;
 }
=20
-static u32 crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)
+static u32 crypto4xx_aead_done(struct crypto4xx_device *dev,
+			struct pd_uinfo *pd_uinfo,
+			struct ce_pd *pd)
+{
+	struct aead_request *aead_req;
+	struct crypto4xx_ctx *ctx;
+	struct scatterlist *dst;
+	dma_addr_t addr;
+	struct crypto_aead *aead;
+
+	aead_req =3D container_of(pd_uinfo->async_req,
+				struct aead_request, base);
+	aead =3D crypto_aead_reqtfm(aead_req);
+	ctx  =3D crypto_tfm_ctx(aead_req->base.tfm);
+
+	if (pd_uinfo->using_sd) {
+		crypto4xx_copy_pkt_to_dst(dev, pd, pd_uinfo,
+					  pd->pd_ctl_len.bf.pkt_len,
+					  aead_req->dst);
+	} else {
+		dst =3D pd_uinfo->dest_va;
+		addr =3D dma_map_page(dev->core_dev->device, sg_page(dst),
+				    dst->offset,
+				    dst->length, DMA_FROM_DEVICE);
+	}
+
+	if (ctx->append_icv !=3D 0) {
+		dst =3D pd_uinfo->dest_va;
+		crypto4xx_append_icv_to_end(dev, dst,
+					    (struct sa_state_record *)
+					    pd_uinfo->sr_va,
+					    aead_req->cryptlen,
+					    crypto_aead_authsize(aead));
+	}
+	crypto4xx_ret_sg_desc(dev, pd_uinfo);
+	/* call user provided callback function x */
+	if (aead_req->base.complete !=3D NULL)
+		aead_req->base.complete(&aead_req->base, 0);
+
+	return 0;
+}
+
+u32 crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)
 {
 	struct ce_pd *pd;
 	struct pd_uinfo *pd_uinfo;
=20
 	pd =3D  dev->pdr + sizeof(struct ce_pd)*idx;
 	pd_uinfo =3D dev->pdr_uinfo + sizeof(struct pd_uinfo)*idx;
+
 	if (crypto_tfm_alg_type(pd_uinfo->async_req->tfm) =3D=3D
+			CRYPTO_ALG_TYPE_AEAD)
+		return crypto4xx_aead_done(dev, pd_uinfo, pd);
+	else if (crypto_tfm_alg_type(pd_uinfo->async_req->tfm) =3D=3D
 			CRYPTO_ALG_TYPE_ABLKCIPHER)
 		return crypto4xx_ablkcipher_done(dev, pd_uinfo, pd);
-	else
+	else if (crypto_tfm_alg_type(pd_uinfo->async_req->tfm) =3D=3D
+			CRYPTO_ALG_TYPE_AHASH)
 		return crypto4xx_ahash_done(dev, pd_uinfo);
+
+	return 0;
 }
=20
 /**
@@ -777,12 +925,15 @@ u32 crypto4xx_build_pd(struct crypto_async_request =
*req,
 		       struct scatterlist *src,
 		       struct scatterlist *dst,
 		       unsigned int datalen,
+		       struct scatterlist *assoc,
+		       u32 aad_len,
 		       void *iv, u32 iv_len)
 {
 	struct crypto4xx_device *dev =3D ctx->dev;
 	dma_addr_t addr, pd_dma, sd_dma, gd_dma;
 	struct dynamic_sa_ctl *sa;
 	struct scatterlist *sg;
+	struct scatterlist *aad;
 	struct ce_gd *gd;
 	struct ce_pd *pd;
 	u32 num_gd, num_sd;
@@ -792,13 +943,18 @@ u32 crypto4xx_build_pd(struct crypto_async_request =
*req,
 	unsigned long flags;
 	struct pd_uinfo *pd_uinfo =3D NULL;
 	unsigned int nbytes =3D datalen, idx;
-	unsigned int ivlen =3D 0;
 	u32 gd_idx =3D 0;
+	unsigned int aadlen =3D 0;
=20
 	/* figure how many gd is needed */
-	num_gd =3D get_sg_count(src, datalen);
-	if (num_gd =3D=3D 1)
-		num_gd =3D 0;
+	if (aad_len) {
+		num_gd =3D get_sg_count(assoc, aad_len) +
+				get_sg_count(src, datalen);
+	} else {
+		num_gd =3D get_sg_count(src, datalen);
+		if (num_gd =3D=3D 1)
+			num_gd =3D 0;
+	}
=20
 	/* figure how many sd is needed */
 	if (sg_is_last(dst) || ctx->is_hash) {
@@ -855,7 +1011,6 @@ u32 crypto4xx_build_pd(struct crypto_async_request =
*req,
 	pd_uinfo->num_sd =3D num_sd;
=20
 	if (iv_len || ctx->is_hash) {
-		ivlen =3D iv_len;
 		pd->sa =3D pd_uinfo->sa_pa;
 		sa =3D (struct dynamic_sa_ctl *) pd_uinfo->sa_va;
 		if (ctx->direction =3D=3D DIR_INBOUND)
@@ -866,8 +1021,26 @@ u32 crypto4xx_build_pd(struct crypto_async_request =
*req,
 		memcpy((void *) sa + ctx->offset_to_sr_ptr,
 			&pd_uinfo->sr_pa, 4);
=20
-		if (iv_len)
-			crypto4xx_memcpy_le(pd_uinfo->sr_va, iv, iv_len);
+		if (iv_len) {
+			if (ctx->ctr_aes) {
+				/* First the nonce */
+				memcpy(pd_uinfo->sr_va, ctx->state_record,
+				       CTR_RFC3686_NONCE_SIZE);
+				/* Copy the IV that is passed through
+				 * each operation
+				 */
+				crypto4xx_memcpy_le(pd_uinfo->sr_va +
+					CTR_RFC3686_NONCE_SIZE, iv, iv_len);
+			} else
+				crypto4xx_memcpy_le(pd_uinfo->sr_va,
+						iv, iv_len);
+		}
+		if (ctx->is_gcm || ctx->ctr_aes) {
+			u32 seq =3D 1;
+			/*For GCM and CTR(AES) algs adding the counter value*/
+			crypto4xx_memcpy_le(pd_uinfo->sr_va + 12,
+					    (void *)&seq,  4);
+		}
 	} else {
 		if (ctx->direction =3D=3D DIR_INBOUND) {
 			pd->sa =3D ctx->sa_in_dma_addr;
@@ -888,6 +1061,35 @@ u32 crypto4xx_build_pd(struct crypto_async_request =
*req,
 		/* enable gather */
 		sa->sa_command_0.bf.gather =3D 1;
 		idx =3D 0;
+		if (aad_len) {
+			aadlen =3D aad_len;
+			aad =3D assoc;
+			/* walk the sg, and setup gather array for aad*/
+			while (aadlen) {
+				sg =3D &aad[idx];
+				addr =3D dma_map_page(dev->core_dev->device,
+						sg_page(sg), sg->offset,
+						sg->length, DMA_TO_DEVICE);
+
+				gd->ptr =3D addr;
+				gd->ctl_len.len =3D sg->length;
+				gd->ctl_len.done =3D 0;
+				gd->ctl_len.ready =3D 1;
+
+				if (sg->length >=3D aadlen)
+					break;
+
+				aadlen -=3D sg->length;
+
+				gd_idx =3D get_next_gd(gd_idx);
+				gd =3D crypto4xx_get_gdp(dev, &gd_dma, gd_idx);
+				idx++;
+			}
+			/* prepare gd for src */
+			gd_idx =3D get_next_gd(gd_idx);
+			gd =3D crypto4xx_get_gdp(dev, &gd_dma, gd_idx);
+		}
+		idx =3D 0;
 		src =3D &src[0];
 		/* walk the sg, and setup gather array */
 		while (nbytes) {
@@ -972,9 +1174,10 @@ u32 crypto4xx_build_pd(struct crypto_async_request =
*req,
 		}
 	}
=20
-	sa->sa_command_1.bf.hash_crypto_offset =3D 0;
+	sa->sa_command_1.bf.hash_crypto_offset =3D (aad_len >> 2);
 	pd->pd_ctl.w =3D ctx->pd_ctl;
-	pd->pd_ctl_len.w =3D 0x00400000 | (ctx->bypass << 24) | datalen;
+	pd->pd_ctl_len.w =3D 0x00400000 | (ctx->bypass << 24) |
+			(datalen + aad_len);
 	pd_uinfo->state =3D PD_ENTRY_INUSE;
 	wmb();
 	/* write any value to push engine to read a pd */
@@ -997,11 +1200,15 @@ static int crypto4xx_alg_init(struct crypto_tfm =
*tfm)
 	ctx->sa_in_dma_addr =3D 0;
 	ctx->sa_out_dma_addr =3D 0;
 	ctx->sa_len =3D 0;
+	ctx->is_gcm =3D 0;
+	ctx->append_icv =3D 0;
=20
 	if (alg->cra_type =3D=3D &crypto_ablkcipher_type)
 		tfm->crt_ablkcipher.reqsize =3D sizeof(struct crypto4xx_ctx);
 	else if (alg->cra_type =3D=3D &crypto_ahash_type)
 		tfm->crt_ahash.reqsize =3D sizeof(struct crypto4xx_ctx);
+	else if (alg->cra_type =3D=3D &crypto_aead_type)
+		tfm->crt_aead.reqsize =3D sizeof(struct crypto4xx_ctx);
=20
 	return 0;
 }
@@ -1105,6 +1312,88 @@ static irqreturn_t =
crypto4xx_ce_interrupt_handler(int irq, void *data)
  * Supported Crypto Algorithms
  */
 struct crypto_alg crypto4xx_alg[] =3D {
+		/* Crypto DES ECB, CBC,  modes */
+
+	{.cra_name 		=3D "cbc(des)",
+	 .cra_driver_name 	=3D "ppc4xx-cbc-des",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D DES_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+		.ablkcipher =3D {
+				.min_keysize 	=3D DES_KEY_SIZE,
+				.max_keysize 	=3D DES_KEY_SIZE,
+				.ivsize 	=3D DES_BLOCK_SIZE,
+				.setkey 	=3D crypto4xx_setkey_3des_cbc,
+				.encrypt 	=3D crypto4xx_encrypt,
+				.decrypt 	=3D crypto4xx_decrypt,
+			}
+		}
+	},
+	{.cra_name 		=3D "ecb(des)",
+	 .cra_driver_name 	=3D "ppc4xx-ecb-des",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D DES_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D DES_KEY_SIZE,
+				.max_keysize 	=3D DES_KEY_SIZE,
+				.setkey 	=3D crypto4xx_setkey_3des_ecb,
+				.encrypt 	=3D crypto4xx_encrypt,
+				.decrypt 	=3D crypto4xx_decrypt,
+			}
+		}
+	},
+
+	/* Crypto 3DES ECB, CBC, CFB, and OFB modes */
+	{.cra_name 		=3D "cbc(des3_ede)",
+	 .cra_driver_name 	=3D "ppc4xx-cbc-3des",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D DES3_EDE_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D DES3_EDE_KEY_SIZE,
+				.max_keysize 	=3D DES3_EDE_KEY_SIZE,
+				.ivsize 	=3D DES3_EDE_BLOCK_SIZE,
+				.setkey 	=3D crypto4xx_setkey_3des_cbc,
+				.encrypt 	=3D crypto4xx_encrypt,
+				.decrypt 	=3D crypto4xx_decrypt,
+			}
+		}
+	},
+	{.cra_name 		=3D "ecb(des3_ede)",
+	 .cra_driver_name 	=3D "ppc4xx-ecb-3des",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D DES3_EDE_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D DES3_EDE_KEY_SIZE,
+				.max_keysize 	=3D DES3_EDE_KEY_SIZE,
+				.setkey 	=3D crypto4xx_setkey_3des_ecb,
+				.encrypt 	=3D crypto4xx_encrypt,
+				.decrypt 	=3D crypto4xx_decrypt,
+			}
+		}
+	},
 	/* Crypto AES modes */
 	{
 		.cra_name 	=3D "cbc(aes)",
@@ -1127,25 +1416,495 @@ struct crypto_alg crypto4xx_alg[] =3D {
 			}
 		}
 	},
-	/* Hash SHA1 */
-	{
-		.cra_name	=3D "sha1",
-		.cra_driver_name =3D "sha1-ppc4xx",
-		.cra_priority	=3D CRYPTO4XX_CRYPTO_PRIORITY,
-		.cra_flags	=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
-		.cra_blocksize	=3D SHA1_BLOCK_SIZE,
-		.cra_ctxsize	=3D sizeof(struct crypto4xx_ctx),
-		.cra_alignmask	=3D 0,
-		.cra_type	=3D &crypto_ahash_type,
-		.cra_init	=3D crypto4xx_sha1_alg_init,
-		.cra_module	=3D THIS_MODULE,
-		.cra_u		=3D {
+	{.cra_name 		=3D "ofb(aes)",
+	 .cra_driver_name 	=3D "ppc4xx-ofb-aes",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize		=3D AES_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D AES_MIN_KEY_SIZE,
+				.max_keysize 	=3D AES_MAX_KEY_SIZE,
+				.ivsize 	=3D AES_BLOCK_SIZE,
+				.setkey 	=3D crypto4xx_setkey_aes_ofb,
+				.encrypt 	=3D crypto4xx_encrypt,
+				.decrypt 	=3D crypto4xx_decrypt,
+			}
+		}
+	},
+	{.cra_name 		=3D "cfb(aes)",
+	 .cra_driver_name 	=3D "ppc4xx-cfb-aes",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize		=3D AES_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D AES_MIN_KEY_SIZE,
+				.max_keysize 	=3D AES_MAX_KEY_SIZE,
+				.ivsize 	=3D AES_BLOCK_SIZE,
+				.setkey 	=3D crypto4xx_setkey_aes_cfb,
+				.encrypt 	=3D crypto4xx_encrypt,
+				.decrypt 	=3D crypto4xx_decrypt,
+			}
+		}
+	},
+	/* Crypto AES ECB, CBC, CTR, GCM, CCM, and GMAC modes */
+	{.cra_name 		=3D "ecb(aes)",
+	 .cra_driver_name 	=3D "ppc4xx-ecb-aes",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D AES_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D AES_MIN_KEY_SIZE,
+				.max_keysize 	=3D AES_MAX_KEY_SIZE,
+				.setkey 	=3D crypto4xx_setkey_aes_ecb,
+				.encrypt 	=3D crypto4xx_encrypt,
+				.decrypt 	=3D crypto4xx_decrypt,
+			}
+		}
+	},
+	{.cra_name 		=3D "rfc3686(ctr(aes))",
+	 .cra_driver_name 	=3D "ppc4xx-ctr-aes",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D CTR_RFC3686_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type		=3D &crypto_ablkcipher_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D AES_MIN_KEY_SIZE,
+				.max_keysize 	=3D AES_MAX_KEY_SIZE,
+				.ivsize 	=3D CTR_RFC3686_BLOCK_SIZE,
+				.setkey 	=3D crypto4xx_setkey_aes_ctr,
+				.encrypt 	=3D crypto4xx_encrypt_ctr,
+				.decrypt 	=3D crypto4xx_decrypt_ctr,
+			}
+		}
+	},
+	/* AEAD Algorithms */
+	{.cra_name 		=3D "gcm(aes)",
+	 .cra_driver_name 	=3D "ppc4xx-gcm-aes",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D AES_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_aead_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.aead =3D {
+				.maxauthsize	=3D 16,
+				.ivsize 	=3D 12,
+				.setkey 	=3D crypto4xx_setkey_aes_gcm,
+				.setauthsize	=3D crypto4xx_setauthsize_aes,
+				.encrypt 	=3D crypto4xx_encrypt_aes_gcm,
+				.decrypt 	=3D crypto4xx_decrypt_aes_gcm,
+				.givencrypt	=3D crypto4xx_givencrypt_aes_gcm,
+				.givdecrypt	=3D crypto4xx_givdecrypt_aes_gcm,
+			}
+		}
+	},
+	{.cra_name 		=3D "ccm(aes)",
+	 .cra_driver_name 	=3D "ppc4xx-ccm-aes",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D AES_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_aead_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.aead =3D {
+				.ivsize 	=3D AES_BLOCK_SIZE,
+				.maxauthsize	=3D 16,
+				.setkey		=3D crypto4xx_setkey_aes_ccm,
+				.setauthsize	=3D crypto4xx_setauthsize_aes,
+				.encrypt	=3D crypto4xx_encrypt_aes_ccm,
+				.decrypt	=3D crypto4xx_decrypt_aes_ccm,
+				.givencrypt	=3D crypto4xx_givencrypt_aes_ccm,
+				.givdecrypt	=3D crypto4xx_givdecrypt_aes_ccm,
+			}
+		}
+	},
+	/* Hash MD5 */
+	{.cra_name 		=3D "md5",
+	 .cra_driver_name 	=3D "ppc4xx-md5",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D 64,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_init 		=3D crypto4xx_md5_alg_init,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize 	=3D SA_HASH_ALG_MD5_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+			}
+		}
+	},
+	/* Hash MD5-HMAC */
+	{.cra_name 		=3D "hmac(md5)",
+	 .cra_driver_name 	=3D "ppc4xx-hmac-md5",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D 64,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize	=3D SA_HASH_ALG_MD5_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+				.setkey		=3D crypto4xx_md5_hmac_setkey,
+			}
+		}
+	},
+	/* Hash SHA1, SHA2 and HMAC */
+	{.cra_name 		=3D "sha1",
+	 .cra_driver_name 	=3D "ppc4xx-sha1",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA1_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type   		=3D &crypto_ahash_type,
+	 .cra_init 		=3D crypto4xx_sha1_alg_init,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u  		=3D {
+			.ahash =3D {
+				.digestsize	=3D SHA1_DIGEST_SIZE,
+				.init   	=3D crypto4xx_hash_init,
+				.update 	=3D crypto4xx_hash_update,
+				.final  	=3D crypto4xx_hash_final,
+				.digest 	=3D crypto4xx_hash_digest,
+				}
+		}
+	},
+	{.cra_name 		=3D "hmac(sha1)",
+	 .cra_driver_name 	=3D "ppc4xx-hmac-sha1",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA1_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type   		=3D &crypto_ahash_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u  		=3D {
 			.ahash =3D {
 				.digestsize 	=3D SHA1_DIGEST_SIZE,
+				.init   	=3D crypto4xx_hash_init,
+				.update 	=3D crypto4xx_hash_update,
+				.final  	=3D crypto4xx_hash_final,
+				.digest 	=3D crypto4xx_hash_digest,
+				.setkey 	=3D crypto4xx_sha1_hmac_setkey,
+			}
+		}
+	},
+
+	{.cra_name 		=3D "sha224",
+	 .cra_driver_name 	=3D "ppc4xx-sha224",
+	 .cra_priority		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA224_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_init 		=3D crypto4xx_sha2_alg_init,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize	=3D SHA224_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+			}
+		}
+	},
+	{.cra_name 		=3D "hmac(sha224)",
+	 .cra_driver_name 	=3D "ppc4xx-hmac-sha224",
+	 .cra_priority		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA224_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize 	=3D SHA224_DIGEST_SIZE,
+				.init   	=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+				.setkey		=3D crypto4xx_sha2_hmac_setkey,
+			}
+		}
+	},
+	{.cra_name 		=3D "sha256",
+	 .cra_driver_name 	=3D "ppc4xx-sha256",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA256_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_init 		=3D crypto4xx_sha2_alg_init,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize	=3D SHA256_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+			}
+		}
+	},
+	{.cra_name 		=3D "hmac(sha256)",
+	 .cra_driver_name 	=3D "ppc4xx-hmac-sha256",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA256_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize	=3D SHA256_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+				.setkey		=3D crypto4xx_sha2_hmac_setkey,
+			}
+		}
+	},
+	{.cra_name 		=3D "sha384",
+	 .cra_driver_name 	=3D "ppc4xx-sha384",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA384_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_init 		=3D crypto4xx_sha2_alg_init,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize	=3D SHA384_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+			}
+		}
+	},
+	{.cra_name 		=3D "hmac(sha384)",
+	 .cra_driver_name 	=3D "ppc4xx-hmac-sha384",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA384_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize	=3D SHA384_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update 	=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+				.setkey		=3D crypto4xx_sha2_hmac_setkey,
+			}
+		}
+	},
+	{.cra_name 		=3D "sha512",
+	 .cra_driver_name 	=3D "ppc4xx-sha512",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA512_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_init 		=3D crypto4xx_sha2_alg_init,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize 	=3D SHA512_DIGEST_SIZE,
+				.init		=3D crypto4xx_hash_init,
+				.update		=3D crypto4xx_hash_update,
+				.final 		=3D crypto4xx_hash_final,
+				.digest		=3D crypto4xx_hash_digest,
+			}
+		}
+	},
+	{.cra_name 		=3D "hmac(sha512)",
+	 .cra_driver_name 	=3D "ppc4xx-hmac-sha512",
+	 .cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	 .cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	 .cra_blocksize 	=3D SHA512_BLOCK_SIZE,
+	 .cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	 .cra_alignmask 	=3D 0,
+	 .cra_type 		=3D &crypto_ahash_type,
+	 .cra_module 		=3D THIS_MODULE,
+	 .cra_u 		=3D {
+			.ahash =3D {
+				.digestsize 	=3D SHA512_DIGEST_SIZE,
 				.init		=3D crypto4xx_hash_init,
 				.update		=3D crypto4xx_hash_update,
+				.final		=3D crypto4xx_hash_final,
+				.digest 	=3D crypto4xx_hash_digest,
+				.setkey 	=3D crypto4xx_sha2_hmac_setkey,
+			}
+		}
+	},
+	/* Hash XCBC, GHASH, and Kasumi F9 */
+	{.cra_name 		=3D "xcbc(aes)",
+	.cra_driver_name	=3D "ppc4xx-xcbc-aes",
+	.cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	.cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	.cra_blocksize 	=3D AES_BLOCK_SIZE,
+	.cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	.cra_alignmask 	=3D 0,
+	.cra_type 		=3D &crypto_ahash_type,
+	.cra_module 		=3D THIS_MODULE,
+	.cra_u 			=3D {
+			.ahash =3D {
+				.digestsize 	=3D 16,
+				.init   	=3D crypto4xx_hash_init,
+				.update 	=3D crypto4xx_hash_update,
 				.final  	=3D crypto4xx_hash_final,
 				.digest 	=3D crypto4xx_hash_digest,
+				.setkey 	=3D crypto4xx_xcbc_setkey,
+			}
+		}
+	},
+	/* Crypto Kasumi and Kasumi F8 */
+	{.cra_name 		=3D "kasumi",
+	.cra_driver_name 	=3D "ppc4xx-kasumi",
+	.cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	.cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		=3D KASUMI_BLOCK_SIZE,
+	.cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	.cra_alignmask 	=3D 0,
+	.cra_type 		=3D &crypto_ablkcipher_type,
+	.cra_module 		=3D THIS_MODULE,
+	.cra_u 			=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D KASUMI_KEY_SIZE,
+				.max_keysize 	=3D KASUMI_KEY_SIZE,
+				.ivsize 	=3D KASUMI_BLOCK_SIZE,
+				.setkey 	=3D crypto4xx_setkey_kasumi_p,
+				.encrypt	=3D crypto4xx_encrypt,
+				.decrypt	=3D crypto4xx_decrypt,
+			}
+		}
+	},
+	{
+	.cra_name 		=3D "f8(kasumi)",
+	.cra_driver_name 	=3D "ppc4xx-f8-kasumi",
+	.cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	.cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		=3D KASUMI_BLOCK_SIZE,
+	.cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	.cra_alignmask 	=3D 0,
+	.cra_type 		=3D &crypto_ablkcipher_type,
+	.cra_module 		=3D THIS_MODULE,
+	.cra_u 			=3D {
+			.ablkcipher =3D {
+				.min_keysize	=3D KASUMI_KEY_SIZE,
+				.max_keysize	=3D KASUMI_KEY_SIZE,
+				.ivsize		=3D KASUMI_BLOCK_SIZE,
+				.setkey		=3D crypto4xx_setkey_kasumi_f8,
+				.encrypt	=3D crypto4xx_encrypt_kasumi_f8,
+				.decrypt	=3D crypto4xx_decrypt_kasumi_f8,
+			}
+		}
+	},
+	{.cra_name 		=3D "f9(kasumi)",
+	.cra_driver_name 	=3D "ppc4xx-f9-kasumi",
+	.cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	.cra_flags 		=3D CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		=3D KASUMI_BLOCK_SIZE,
+	.cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	.cra_alignmask		=3D 0,
+	.cra_type 		=3D &crypto_ahash_type,
+	.cra_module 		=3D THIS_MODULE,
+	.cra_u			=3D {
+			.ahash =3D {
+			.digestsize 	=3D 8,
+			.init   	=3D crypto4xx_hash_init,
+			.update 	=3D crypto4xx_hash_update,
+			.final  	=3D crypto4xx_hash_final,
+			.digest 	=3D crypto4xx_kasumi_f9_digest,
+			.setkey 	=3D crypto4xx_kasumi_f9_setkey,
+			}
+		}
+	},
+	/* Crypto ARC4 - stateless */
+	{.cra_name 		=3D "ecb(arc4)",
+	.cra_driver_name 	=3D "ppc4xx-arc4",
+	.cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	.cra_flags 		=3D CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize 		=3D 1,
+	.cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	.cra_alignmask 		=3D 0,
+	.cra_type 		=3D &crypto_ablkcipher_type,
+	.cra_module 		=3D THIS_MODULE,
+	.cra_u 			=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D 1,
+				.max_keysize 	=3D 16,
+				.setkey 	=3D crypto4xx_setkey_arc4,
+				.encrypt	=3D crypto4xx_arc4_encrypt,
+				.decrypt	=3D crypto4xx_arc4_decrypt,
+			}
+		}
+	},
+	/* Crypto ARC4 - statefull */
+	{.cra_name 		=3D "cbc(arc4)",
+	.cra_driver_name 	=3D "ppc4xx-arc4",
+	.cra_priority 		=3D CRYPTO4XX_CRYPTO_PRIORITY,
+	.cra_flags 		=3D CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		=3D 1,
+	.cra_ctxsize 		=3D sizeof(struct crypto4xx_ctx),
+	.cra_alignmask 		=3D 0,
+	.cra_type		=3D &crypto_ablkcipher_type,
+	.cra_module 		=3D THIS_MODULE,
+	.cra_u 			=3D {
+			.ablkcipher =3D {
+				.min_keysize 	=3D 1,
+				.max_keysize	=3D 16,
+				.setkey		=3D crypto4xx_setkey_arc4,
+				.encrypt 	=3D crypto4xx_arc4_encrypt,
+				.decrypt	=3D crypto4xx_arc4_decrypt,
 			}
 		}
 	},
@@ -1275,7 +2034,6 @@ static int __exit crypto4xx_remove(struct =
of_device *ofdev)
 	crypto4xx_unregister_alg(core_dev->dev);
 	/* Free all allocated memory */
 	crypto4xx_stop_all(core_dev);
-
 	return 0;
 }
=20
diff --git a/drivers/crypto/amcc/crypto4xx_core.h =
b/drivers/crypto/amcc/crypto4xx_core.h
index 1ef1034..f3d04b6 100644
--- a/drivers/crypto/amcc/crypto4xx_core.h
+++ b/drivers/crypto/amcc/crypto4xx_core.h
@@ -116,6 +116,8 @@ struct crypto4xx_ctx {
 	dma_addr_t sa_in_dma_addr;
 	void *sa_out;
 	dma_addr_t sa_out_dma_addr;
+	void *arc4_state_record;
+	dma_addr_t arc4_state_record_dma_addr;
 	void *state_record;
 	dma_addr_t state_record_dma_addr;
 	u32 sa_len;
@@ -125,7 +127,11 @@ struct crypto4xx_ctx {
 	u32 save_iv;
 	u32 pd_ctl_len;
 	u32 pd_ctl;
+	u32 append_icv;
+	u32 is_gcm;
+	u32 ctr_aes;
 	u32 bypass;
+	u32 init_arc4;
 	u32 is_hash;
 	u32 hash_final;
 };
@@ -154,9 +160,12 @@ extern u32 crypto4xx_alloc_sa_rctx(struct =
crypto4xx_ctx *ctx,
 extern void crypto4xx_free_sa_rctx(struct crypto4xx_ctx *rctx);
 extern void crypto4xx_free_ctx(struct crypto4xx_ctx *ctx);
 extern u32 crypto4xx_alloc_state_record(struct crypto4xx_ctx *ctx);
+extern u32 crypto4xx_alloc_arc4_state_record(struct crypto4xx_ctx =
*ctx);
+extern void crypto4xx_free_arc4_state_record(struct crypto4xx_ctx =
*ctx);
 extern u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx =
*ctx);
 extern u32 get_dynamic_sa_offset_key_field(struct crypto4xx_ctx *ctx);
 extern u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx *ctx);
+u32 get_dynamic_sa_offset_arc4_state_ptr(struct crypto4xx_ctx *ctx);
 extern void crypto4xx_memcpy_le(unsigned int *dst,
 				const unsigned char *buf, int len);
 extern u32 crypto4xx_build_pd(struct crypto_async_request *req,
@@ -164,9 +173,15 @@ extern u32 crypto4xx_build_pd(struct =
crypto_async_request *req,
 			      struct scatterlist *src,
 			      struct scatterlist *dst,
 			      unsigned int datalen,
+			      struct scatterlist *assoc,
+			      u32 aad_len,
 			      void *iv, u32 iv_len);
 extern int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher,
 				    const u8 *key, unsigned int keylen);
+extern int crypto4xx_setkey_3des_cbc(struct crypto_ablkcipher *cipher,
+				     const u8 *key, unsigned int keylen);
+extern int crypto4xx_setkey_3des_ecb(struct crypto_ablkcipher *cipher,
+				     const u8 *key, unsigned int keylen);
 extern int crypto4xx_encrypt(struct ablkcipher_request *req);
 extern int crypto4xx_decrypt(struct ablkcipher_request *req);
 extern int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
@@ -174,4 +189,81 @@ extern int crypto4xx_hash_digest(struct =
ahash_request *req);
 extern int crypto4xx_hash_final(struct ahash_request *req);
 extern int crypto4xx_hash_update(struct ahash_request *req);
 extern int crypto4xx_hash_init(struct ahash_request *req);
+extern int crypto4xx_md5_alg_init(struct crypto_tfm *tfm);
+extern int crypto4xx_hash_hmac_setkey(struct crypto_ahash *hash,
+			       const u8 *key,
+			       unsigned int keylen,
+			       unsigned int sa_len,
+			       unsigned char ha,
+			       unsigned char hm,
+			       unsigned int max_keylen);
+extern int crypto4xx_md5_hmac_setkey(struct crypto_ahash *hash, const =
u8 *key,
+			      unsigned int keylen);
+extern int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
+extern int crypto4xx_sha2_alg_init(struct crypto_tfm *tfm);
+extern int crypto4xx_sha2_hmac_setkey(struct crypto_ahash *hash,
+			       const u8 *key,
+			       unsigned int keylen);
+extern int crypto4xx_sha1_hmac_setkey(struct crypto_ahash *hash, const =
u8 *key,
+			       unsigned int keylen);
+extern u32 get_dynamic_sa_offset_inner_digest(struct crypto4xx_ctx =
*ctx);
+extern u32 get_dynamic_sa_offset_outer_digest(struct crypto4xx_ctx =
*ctx);
+extern int crypto4xx_pre_compute_hmac(struct crypto4xx_ctx *ctx,
+			       void *key,
+			       unsigned int keylen,
+			       unsigned int bs,
+			       unsigned char ha,
+			       unsigned char digs);
+int crypto4xx_setkey_aes_ecb(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen);
+int crypto4xx_setkey_aes_ofb(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen);
+int crypto4xx_setkey_aes_cfb(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen);
+int crypto4xx_setkey_aes_ctr(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen);
+int crypto4xx_setkey_aes_gcm(struct crypto_aead *cipher,
+			     const u8 *key, unsigned int keylen);
+int crypto4xx_setkey_aes_ccm(struct crypto_aead *cipher,
+			     const u8 *key, unsigned int keylen);
+
+int crypto4xx_encrypt_aes_gcm(struct aead_request *req);
+int crypto4xx_decrypt_aes_gcm(struct aead_request *req);
+int crypto4xx_encrypt_aes_ccm(struct aead_request *req);
+int crypto4xx_decrypt_aes_ccm(struct aead_request *req);
+int crypto4xx_encrypt_ctr(struct ablkcipher_request *req);
+int crypto4xx_decrypt_ctr(struct ablkcipher_request *req);
+int crypto4xx_setauthsize_aes(struct crypto_aead *ciper,
+			      unsigned int authsize);
+int crypto4xx_givencrypt_aes_ccm(struct aead_givcrypt_request *req);
+int crypto4xx_givencrypt_aes_gcm(struct aead_givcrypt_request *req);
+int crypto4xx_givdecrypt_aes_ccm(struct aead_givcrypt_request *req);
+int crypto4xx_givdecrypt_aes_gcm(struct aead_givcrypt_request *req);
+int crypto4xx_setkey_kasumi_f8(struct crypto_ablkcipher *cipher,
+			       const u8 *key,
+			       unsigned int keylen);
+
+int crypto4xx_encrypt_kasumi_f8(struct ablkcipher_request *req);
+int crypto4xx_decrypt_kasumi_f8(struct ablkcipher_request *req);
+int crypto4xx_setkey_kasumi_p(struct crypto_ablkcipher *cipher,
+			      const u8 *key,
+			      unsigned int keylen);
+int crypto4xx_kasumi_f9_digest(struct ahash_request *req);
+int crypto4xx_kasumi_f9_setkey(struct crypto_ahash *hash,
+			       const u8 *key, unsigned int keylen);
+int crypto4xx_xcbc_setkey(struct crypto_ahash *hash,
+			  const u8 *key,
+			  unsigned int keylen);
+int crypto4xx_setkey_arc4(struct crypto_ablkcipher *cipher,
+			  const u8 *key, unsigned int keylen);
+int crypto4xx_arc4_decrypt(struct ablkcipher_request *req);
+int crypto4xx_arc4_encrypt(struct ablkcipher_request *req);
+u32 crypto4xx_alloc_arc4_state_record(struct crypto4xx_ctx *ctx);
+int crypto4xx_setauthsize_aes_ccm(struct crypto_aead *ciper,
+				  unsigned int authsize);
+
+/* From crypto/md5.c */
+extern void md5_get_immediate_hash(struct crypto_tfm *tfm, u8 *data);
+extern unsigned int crypto4xx_sa_hash_tbl[3][6];
+
 #endif
diff --git a/drivers/crypto/amcc/crypto4xx_sa.c =
b/drivers/crypto/amcc/crypto4xx_sa.c
index 466fd94..fa4ff7a 100644
--- a/drivers/crypto/amcc/crypto4xx_sa.c
+++ b/drivers/crypto/amcc/crypto4xx_sa.c
@@ -84,6 +84,119 @@ u32 get_dynamic_sa_offset_state_ptr_field(struct =
crypto4xx_ctx *ctx)
 	return sizeof(struct dynamic_sa_ctl) + offset * 4;
 }
=20
+u32 get_dynamic_sa_offset_arc4_state_ptr(struct crypto4xx_ctx *ctx)
+{
+	u32 offset;
+	union dynamic_sa_contents cts;
+
+	if (ctx->direction =3D=3D DIR_INBOUND)
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
+	else
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
+	offset =3D 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
+		+ cts.bf.state_ptr
+		+ cts.bf.arc4_ij_ptr;
+
+	return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
+u32 get_dynamic_sa_offset_inner_digest(struct crypto4xx_ctx *ctx)
+{
+	u32 offset;
+	union dynamic_sa_contents cts;
+
+	if (ctx->direction =3D=3D DIR_INBOUND)
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
+	else
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
+	offset =3D cts.bf.key_size;
+
+	return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
+u32 get_dynamic_sa_offset_outer_digest(struct crypto4xx_ctx *ctx)
+{
+	u32 offset;
+	union dynamic_sa_contents cts;
+
+	if (ctx->direction =3D=3D DIR_INBOUND)
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
+	else
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
+
+	offset =3D cts.bf.key_size
+		+ cts.bf.inner_size;
+
+	return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
+u32 get_dynamic_sa_offset_spi(struct crypto4xx_ctx *ctx)
+{
+	u32 offset;
+	union dynamic_sa_contents cts;
+
+	if (ctx->direction =3D=3D DIR_INBOUND)
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
+	else
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
+
+	offset =3D cts.bf.key_size
+		+ cts.bf.inner_size
+		+ cts.bf.outer_size;
+
+	return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
+u32 get_dynamic_sa_offset_seq_num(struct crypto4xx_ctx *ctx)
+{
+	u32 offset;
+	union dynamic_sa_contents cts;
+
+	if (ctx->direction =3D=3D DIR_INBOUND)
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
+	else
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
+
+	offset =3D cts.bf.key_size
+		+ cts.bf.inner_size
+		+ cts.bf.outer_size
+		+ cts.bf.spi;
+	return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
+u32 get_dynamic_sa_offset_seq_num_mask(struct crypto4xx_ctx *ctx)
+{
+	u32 offset;
+	union dynamic_sa_contents cts;
+
+	if (ctx->direction =3D=3D DIR_INBOUND)
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
+	else
+		cts.w =3D ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
+
+	offset =3D cts.bf.key_size
+		+ cts.bf.inner_size
+		+ cts.bf.outer_size
+		+ cts.bf.spi
+		+ cts.bf.seq_num0
+		+ cts.bf.seq_num1;
+
+	return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
 u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx *ctx)
 {
 	union dynamic_sa_contents cts;
@@ -92,6 +205,7 @@ u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx *ctx)
 		cts.w =3D ((struct dynamic_sa_ctl *) ctx->sa_in)->sa_contents;
 	else
 		cts.w =3D ((struct dynamic_sa_ctl *) ctx->sa_out)->sa_contents;
+
 	return (cts.bf.iv0 + cts.bf.iv1 + cts.bf.iv2 + cts.bf.iv3) * 4;
 }
=20
diff --git a/drivers/crypto/amcc/crypto4xx_sa.h =
b/drivers/crypto/amcc/crypto4xx_sa.h
index 4b83ed7..5a1e308 100644
--- a/drivers/crypto/amcc/crypto4xx_sa.h
+++ b/drivers/crypto/amcc/crypto4xx_sa.h
@@ -50,12 +50,42 @@ union dynamic_sa_contents {
 	u32 w;
 } __attribute__((packed));
=20
+#define SA_OPCODE_ESP                   	0
+#define SA_OPCODE_AH                    	1
+#define SA_OPCODE_SSL                   	4
+#define SA_OPCODE_TLS                   	5
+#define SA_OPCODE_SRTP                  	7
+#define SA_OPCODE_DTLS                  	1
+#define SA_OPCODE_TLS1_1                	6
+
+#define SA_OP_GROUP_BASIC               	0
+#define SA_OP_GROUP_PROTOCOL            	1
+#define SA_OP_GROUP_EXTEND_PROTOCOL     	3
+
+#define SA_OPCODE_EXT_PROT_DTLS         	1
+#define SA_OPCODE_EXT_PROT_MACSEC       	2
+#define SA_OPCODE_EXT_PROT_SSL          	4
+#define SA_OPCODE_EXT_PROT_TLS10        	5
+#define SA_OPCODE_EXT_PROT_TLS11        	6
+
 #define DIR_OUTBOUND				0
 #define DIR_INBOUND				1
-#define SA_OP_GROUP_BASIC			0
 #define SA_OPCODE_ENCRYPT			0
 #define SA_OPCODE_DECRYPT			0
+#define SA_OPCODE_ENCRYPT_HASH          	1
+#define SA_OPCODE_HASH_DECRYPT			1
 #define SA_OPCODE_HASH				3
+#define SA_OPCODE_HASH_ENCRYPT          	4
+#define SA_OPCODE_DECRYPT_HASH			4
+
+#define SA_OPCODE_ESP                   	0
+#define SA_OPCODE_AH                    	1
+#define SA_OPCODE_SSL                   	4
+#define SA_OPCODE_TLS                   	5
+#define SA_OPCODE_SRTP                  	7
+#define SA_OPCODE_DTLS                  	1
+#define SA_OPCODE_TLS1_1                	6
+
 #define SA_CIPHER_ALG_DES			0
 #define SA_CIPHER_ALG_3DES			1
 #define SA_CIPHER_ALG_ARC4			2
@@ -65,8 +95,17 @@ union dynamic_sa_contents {
=20
 #define SA_HASH_ALG_MD5				0
 #define SA_HASH_ALG_SHA1			1
+#define SA_HASH_ALG_SHA224              	2
+#define SA_HASH_ALG_SHA256              	3
+#define SA_HASH_ALG_SHA384              	4
+#define SA_HASH_ALG_SHA512              	5
+#define HASH_ALG_MAX_CNT			6
+#define SA_HASH_ALG_AES_XCBC_MAC_128    	8
+#define SA_HASH_ALG_KASUMI_f9           	9
+#define SA_HASH_ALG_GHASH			12
+#define SA_HASH_ALG_GMAC        		13
+#define SA_HASH_ALG_CBC_MAC			14
 #define SA_HASH_ALG_NULL			15
-#define SA_HASH_ALG_SHA1_DIGEST_SIZE		20
=20
 #define SA_LOAD_HASH_FROM_SA			0
 #define SA_LOAD_HASH_FROM_STATE			2
@@ -87,6 +126,16 @@ union dynamic_sa_contents {
 #define SA_HEADER_PROC				1
 #define SA_NO_HEADER_PROC			0
=20
+#define SA_HASH_ALG_MD5_DIGEST_SIZE		16
+#define SA_HASH_ALG_SHA1_DIGEST_SIZE		20
+#define SA_HASH_ALG_SHA224_DIGEST_SIZE		28
+#define SA_HASH_ALG_SHA256_DIGEST_SIZE		32
+#define SA_HASH_ALG_SHA384_DIGEST_SIZE		48
+#define SA_HASH_ALG_SHA512_DIGEST_SIZE		64
+
+
+#define CRYPTO4XX_MAC_ALGS	{ "md5", "sha1", \
+				"sha224", "sha256", "sha384", "sha512" }
 union sa_command_0 {
 	struct {
 		u32 scatter:1;
@@ -111,7 +160,13 @@ union sa_command_0 {
 } __attribute__((packed));
=20
 #define CRYPTO_MODE_ECB				0
+#define CRYPTO_MODE_KASUMI			0
 #define CRYPTO_MODE_CBC				1
+#define CRYPTO_MODE_OFB                  	2
+#define CRYPTO_MODE_CFB                  	3
+#define CRYPTO_MODE_AES_CTR              	4
+#define CRYPTO_MODE_KASUMI_f8            	4
+#define CRYPTO_MODE_AES_ICM              	5
=20
 #define CRYPTO_FEEDBACK_MODE_NO_FB		0
 #define CRYPTO_FEEDBACK_MODE_64BIT_OFB		0
@@ -124,7 +179,7 @@ union sa_command_0 {
 #define SA_AES_KEY_LEN_256			4
=20
 #define SA_REV2					1
-/**
+/*
  * The follow defines bits sa_command_1
  * In Basic hash mode  this bit define simple hash or hmac.
  * In IPsec mode, this bit define muting control.
@@ -177,13 +232,46 @@ struct dynamic_sa_ctl {
 /**
  * State Record for Security Association (SA)
  */
-struct  sa_state_record {
+struct sa_state_record {
 	u32 save_iv[4];
 	u32 save_hash_byte_cnt[2];
 	u32 save_digest[16];
 } __attribute__((packed));
=20
 /**
+ * Arc4 State Record for Security Association (SA)
+ */
+struct arc4_sr {
+	u32 arc4_state[64];
+} __attribute__((packed));
+
+/**
+ * Security Association (SA) for DES
+ */
+struct dynamic_sa_des {
+	struct dynamic_sa_ctl  ctrl;
+	u32 key[2];
+	u32 iv[2];
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_DES_LEN		(sizeof(struct dynamic_sa_des)/4)
+#define SA_DES_CONTENTS         0x26000022
+
+/**
+ * Security Association (SA) for 3DES
+ */
+struct dynamic_sa_3des {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[6];
+	u32 iv[2]; /* for CBC, OFC, and CFB mode */
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_3DES_LEN		(sizeof(struct dynamic_sa_3des)/4)
+#define SA_3DES_CONTENTS        0x26000062
+
+/**
  * Security Association (SA) for AES128
  *
  */
@@ -194,11 +282,10 @@ struct dynamic_sa_aes128 {
 	u32 state_ptr;
 	u32 reserved;
 } __attribute__((packed));
-
 #define SA_AES128_LEN		(sizeof(struct dynamic_sa_aes128)/4)
 #define SA_AES128_CONTENTS	0x3e000042
=20
-/*
+/**
  * Security Association (SA) for AES192
  */
 struct dynamic_sa_aes192 {
@@ -208,7 +295,6 @@ struct dynamic_sa_aes192 {
 	u32 state_ptr;
 	u32 reserved;
 } __attribute__((packed));
-
 #define SA_AES192_LEN		(sizeof(struct dynamic_sa_aes192)/4)
 #define SA_AES192_CONTENTS	0x3e000062
=20
@@ -228,6 +314,19 @@ struct dynamic_sa_aes256 {
 #define SA_AES_CONTENTS		0x3e000002
=20
 /**
+ * Security Association (SA) for HASH128: HMAC-MD5
+ */
+struct dynamic_sa_hash128 {
+	struct dynamic_sa_ctl ctrl;
+	u32 inner_digest[4];
+	u32 outer_digest[4];
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_HASH128_LEN		(sizeof(struct dynamic_sa_hash128)/4)
+#define SA_HASH128_CONTENTS     0x20008402
+
+/**
  * Security Association (SA) for HASH160: HMAC-SHA1
  */
 struct dynamic_sa_hash160 {
@@ -240,4 +339,228 @@ struct dynamic_sa_hash160 {
 #define SA_HASH160_LEN		(sizeof(struct dynamic_sa_hash160)/4)
 #define SA_HASH160_CONTENTS     0x2000a502
=20
+/**
+ * Security Association (SA) for HASH256: HMAC-SHA224, HMAC-SHA256
+ */
+struct dynamic_sa_hash256 {
+	struct dynamic_sa_ctl ctrl;
+	u32 inner_digest[8];
+	u32 outer_digest[8];
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_HASH256_LEN		(sizeof(struct dynamic_sa_hash256)/4)
+#define SA_HASH256_CONTENTS     0x20010802
+
+/*
+ * Security Association (SA) for HASH512: HMAC-SHA512
+ */
+struct dynamic_sa_hash512 {
+	struct dynamic_sa_ctl ctrl;
+	u32 inner_digest[16];
+	u32 outer_digest[16];
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_HASH512_LEN		(sizeof(struct dynamic_sa_hash512)/4)
+#define SA_HASH512_CONTENTS     0x20021002
+
+/**
+ * Security Association (SA) for AES128_XCBC_MAC
+ */
+struct dynamic_sa_aes128_xcbc_mac {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[4];
+	u32 inner_digest[8];
+	u32 outer_digest[8];
+	u32 iv[4]; /* for CBC, OFC, and CFB mode */
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_AES128_XCBC_MAC_LEN	(sizeof(struct =
dynamic_sa_aes128_xcbc_mac)/4)
+#define SA_AES128_XCBC_MAC_CONTENTS     0x3e010842
+
+/**
+ * Security Association (SA) for AES128_GCM
+ */
+struct dynamic_sa_aes128_gcm {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[4];
+	u32 inner_digest[4];
+	u32 outer_digest[4];
+	u32 spi;
+	u32 seq;
+	u32 iv[4]; /* for CBC, OFC, and CFB mode */
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_AES128_GCM_LEN	(sizeof(struct dynamic_sa_aes128_gcm)/4)
+#define SA_AES128_GCM_CONTENTS          0x3e0c8442
+
+/**
+ * Security Association (SA) for AES192_XCBC_MAC
+ */
+struct dynamic_sa_aes192_xcbc_mac {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[6];
+	u32 inner_digest[8];
+	u32 outer_digest[8];
+	u32 iv[4]; /* for CBC, OFC, and CFB mode */
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_AES192_XCBC_MAC_LEN	(sizeof(struct =
dynamic_sa_aes192_xcbc_mac)/4)
+#define SA_AES192_XCBC_MAC_CONTENTS     0x3e010862
+
+/**
+ * Security Association (SA) for AES192_GCM
+ */
+struct dynamic_sa_aes192_gcm {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[6];
+	u32 inner_digest[4];
+	u32 outer_digest[4];
+	u32 spi;
+	u32 seq;
+	u32 iv[4]; /* for CBC, OFC, and CFB mode */
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_AES192_GCM_LEN	(sizeof(struct dynamic_sa_aes192_gcm)/4)
+#define SA_AES192_GCM_CONTENTS          0x3e0c8462
+
+
+/**
+ * Security Association (SA) for AES256_XCBC_MAC
+ */
+struct dynamic_sa_aes256_xcbc_mac {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[8];
+	u32 inner_digest[8];
+	u32 outer_digest[8];
+	u32 iv[4]; /* for CBC, OFC, and CFB mode */
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_AES256_XCBC_MAC_LEN	(sizeof(struct =
dynamic_sa_aes256_xcbc_mac)/4)
+#define SA_AES256_XCBC_MAC_CONTENTS     0x3e010882
+
+/**
+ * Security Association (SA) for AES256_GCM
+ */
+struct dynamic_sa_aes256_gcm {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[8];
+	u32 inner_digest[4];
+	u32 outer_digest[4];
+	u32 spi;
+	u32 seq;
+	u32 iv[4]; /* for CBC, OFC, and CFB mode */
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_AES256_GCM_LEN	(sizeof(struct dynamic_sa_aes256_gcm)/4)
+#define SA_AES256_GCM_CONTENTS          0x3e0c8482
+#define SA_AES_GCM_CONTENTS          0x3e0c8402
+
+/**
+ * Security Association (SA) for Kasumi
+ */
+struct dynamic_sa_kasumi {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[4];
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_KASUMI_LEN		(sizeof(struct dynamic_sa_kasumi)/4)
+#define SA_KASUMI_CONTENTS              0x20000042
+
+/**
+ * Security Association (SA) for Kasumi f8
+ */
+struct dynamic_sa_kasumi_f8 {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[4];
+	u32 iv[2];
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_KASUMI_F8_LEN	(sizeof(struct dynamic_sa_kasumi_f8)/4)
+#define SA_KASUMI_F8_CONTENTS           0x26000042
+
+#define KASUMI_BLOCK_SIZE 8
+#define KASUMI_KEY_SIZE   16
+
+/**
+ * Security Association (SA) for Kasumi f8
+ */
+struct dynamic_sa_kasumi_f9 {
+	struct dynamic_sa_ctl ctrl;
+	u32 inner_digest[4];
+	u32 outter_digest[3];
+	u32 state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_KASUMI_F9_LEN	(sizeof(struct dynamic_sa_kasumi_f9)/4)
+#define SA_KASUMI_F9_CONTENTS           0x20006402
+
+/**
+ * Security Association (SA) for AES256 CCM
+ */
+struct dynamic_sa_aes256_ccm {
+	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_CCM_LEN	(sizeof(struct dynamic_sa_aes256_ccm)/4)
+#define SA_AES256_CCM_CONTENTS      0x3e000082
+#define SA_AES_CCM_CONTENTS      0x3e000002
+
+/**
+ * Security Association (SA) for AES192 CCM
+ */
+struct dynamic_sa_aes192_ccm {
+	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_CCM_LEN           (sizeof(struct =
dynamic_sa_aes192_ccm)/4)
+#define SA_AES192_CCM_CONTENTS      0x3e000062
+
+/**
+ * Security Association (SA) for AES128 CCM
+ */
+struct dynamic_sa_aes128_ccm {
+	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_CCM_LEN	(sizeof(struct dynamic_sa_aes128_ccm)/4)
+#define SA_AES128_CCM_CONTENTS      0x3e000042
+
+/**
+ * Security Association (SA) for ARC4
+ */
+struct arc4_ij_ptr {
+	u32 rsv:16;
+	u32 j:8;
+	u32 i:8;
+} __attribute__((packed));
+
+struct dynamic_sa_arc4 {
+	struct dynamic_sa_ctl ctrl;
+	u32 key[4];
+	struct arc4_ij_ptr ij;
+	u32 arc4_state_ptr;
+	u32 reserved;
+} __attribute__((packed));
+#define SA_ARC4_LEN		(sizeof(struct dynamic_sa_arc4)/4)
+#define SA_ARC4_CONTENTS        0xc0000042
+
 #endif
diff --git a/include/crypto/sha.h b/include/crypto/sha.h
index c0ccc2b..8894c2f 100644
--- a/include/crypto/sha.h
+++ b/include/crypto/sha.h
@@ -62,4 +62,11 @@
 #define SHA512_H6	0x1f83d9abfb41bd6bULL
 #define SHA512_H7	0x5be0cd19137e2179ULL
=20
+/* From crypto/sha1_generic.c */
+void sha1_get_immediate_hash(struct crypto_tfm *tfm, u8 *data);
+/* From crypto/sha256_generic.c */
+void sha256_get_immediate_hash(struct crypto_tfm *tfm, u8 *data);
+/* From crypto/sha512_generic.c */
+void sha512_get_immediate_hash(struct crypto_tfm *tfm, u8 *data);
+
 #endif
--=20
1.5.5

^ permalink raw reply related

* Re: [PATCH v4] zone_reclaim is always 0 by default
From: Andrew Morton @ 2009-06-09 19:47 UTC (permalink / raw)
  To: Robin Holt
  Cc: riel, cl, linux-mm, mel, yanmin.zhang, linux-kernel, linuxppc-dev,
	holt, kosaki.motohiro, linux-ia64, fengguang.wu
In-Reply-To: <20090609120213.GA18753@attica.americas.sgi.com>

On Tue, 9 Jun 2009 07:02:14 -0500
Robin Holt <holt@sgi.com> wrote:

> On Tue, Jun 09, 2009 at 11:37:55AM +0100, Mel Gorman wrote:
> > On Tue, Jun 09, 2009 at 04:55:07AM -0500, Robin Holt wrote:
> > > On Mon, Jun 08, 2009 at 12:50:48PM +0100, Mel Gorman wrote:
> > > 
> > > Let me start by saying I agree completely with everything you wrote and
> > > still disagree with this patch, but was willing to compromise and work
> > > around this for our upcoming x86_64 machine by putting a "value add"
> > > into our packaging of adding a sysctl that turns reclaim back on.
> > > 
> > 
> > To be honest, I'm more leaning towards a NACK than an ACK on this one. I
> > don't support enough NUMA machines to feel strongly enough about it but
> > unconditionally setting zone_reclaim_mode to 0 on x86-64 just because i7's
> > might be there seems ill-advised to me and will have other consequences for
> > existing more traditional x86-64 NUMA machines.
> 
> I was sort-of planning on coming up with an x86_64 arch specific function
> for setting zone_reclaim_mode, but didn't like the direction things
> were going.
> 
> Something to the effect of...
> --- 20090609.orig/mm/page_alloc.c       2009-06-09 06:51:34.000000000 -0500
> +++ 20090609/mm/page_alloc.c    2009-06-09 06:55:00.160762069 -0500
> @@ -2326,12 +2326,7 @@ static void build_zonelists(pg_data_t *p
>         while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
>                 int distance = node_distance(local_node, node);
>  
> -               /*
> -                * If another node is sufficiently far away then it is better
> -                * to reclaim pages in a zone before going off node.
> -                */
> -               if (distance > RECLAIM_DISTANCE)
> -                       zone_reclaim_mode = 1;
> +               zone_reclaim_mode = arch_zone_reclaim_mode(distance);
>  
>                 /*
>                  * We don't want to pressure a particular node.
> 
> And then letting each arch define an arch_zone_reclaim_mode().  If other
> values are needed in the determination, we would add parameters to
> reflect this.
> 
> For ia64, add
> 
> static inline ia64_zone_reclaim_mode(int distance)
> {
> 	if (distance > 15)
> 		return 1;
> }
> 
> #define	arch_zone_reclaim_mode(_d)	ia64_zone_reclaim_mode(_d)
> 
> 
> Then, inside x86_64_zone_reclaim_mode(), I could make it something like
> 	if (distance > 40 || is_uv_system())
> 		return 1;
> 
> In the end, I didn't think this fight was worth fighting given how ugly
> this felt.  Upon second thought, I am beginning to think it is not that
> bad, but I also don't think it is that good either.
> 

We've done worse before now...

Is it not possible to work out at runtime whether zone reclaim mode is
beneficial?

Given that zone_reclaim_mode is settable from initscripts, why all the
fuss?

Is anyone testing RECLAIM_WRITE and RECLAIM_SWAP, btw?

The root cause of this problem: having something called "mode".  Any
time we put a "mode" in the kernel, we get in a mess trying to work out
when to set it and to what.

I think I'll drop this patch for now.

^ permalink raw reply

* [PATCH] powerpc/mpc52xx/mtd: fix mtd-ram access for 16-bit Local Plus Bus
From: Albrecht Dreß @ 2009-06-09 19:46 UTC (permalink / raw)
  To: grant.likely, dwmw2; +Cc: Linux PPC Development

[-- Attachment #1: Type: text/plain, Size: 4539 bytes --]

Hi all,

this patch adds support for RAM chips connected to the Local Plus Bus  
of a MPC5200B in 16-bit mode.  As no single byte write accesses are  
allowed by the bus in this mode, a byte write has to be split into a  
word read - modify - write sequence (mpc52xx_memcpy2lpb16, as  
fix/extension for memcpy_toio; note that memcpy_fromio *does* work just  
fine).  It has been tested in conjunction with Wolfram Sang's mtd-ram  
[1] and Sascha Hauer's jffs unaligned access [2] patches on 2.6.29.1,  
with a Renesas static RAM connected in 16-bit "Large Flash" mode.

[1]  
<http://lists.ozlabs.org/pipermail/linuxppc-dev/2009-June/072794.html>
[2] <http://article.gmane.org/gmane.linux.drivers.mtd/21521>

Signed-off-by: Albrecht Dreß <albrecht.dress@arcor.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: linuxppc-dev@ozlabs.org

---

diff -u  
linux-2.6.29.1.orig/arch/powerpc/platforms/52xx/mpc52xx_common.c  
linux-2.6.29.1/arch/powerpc/platforms/52xx/mpc52xx_common.c
--- linux-2.6.29.1.orig/arch/powerpc/platforms/52xx/mpc52xx_common.c     
2009-04-02 22:55:27.000000000 +0200
+++ linux-2.6.29.1/arch/powerpc/platforms/52xx/mpc52xx_common.c  
2009-06-09 21:16:22.000000000 +0200
@@ -225,3 +225,59 @@

         while (1);
  }
+
+/**
+ * mpc52xx_memcpy2lpb16: copy data to the Local Plus Bus in 16-bit  
mode which
+ * doesn't allow byte accesses
+ */
+void
+mpc52xx_memcpy2lpb16(volatile void __iomem *dest, const void *src,
+                    unsigned long n)
+{
+       void *vdest = (void __force *) dest;
+
+       __asm__ __volatile__ ("sync" : : : "memory");
+
+       if (((unsigned long) vdest & 1) != 0) {
+               u8 buf[2];
+
+               *(u16 *)buf = *((volatile u16 *)(vdest - 1));
+               buf[1] = *((u8 *)src);
+               *((volatile u16 *)(vdest - 1)) = *(u16 *)buf;
+               src++;
+               vdest++;
+               n--;
+       }
+
+       /* looks weird, but helps the optimiser... */
+       if (n >= 4) {
+               unsigned long chunks = n >> 2;
+               volatile u32 * _dst = (volatile u32 *)(vdest - 4);
+               volatile u32 * _src = (volatile u32 *)(src - 4);
+
+               vdest += chunks << 2;
+               src += chunks << 2;
+               do {
+                       *++_dst = *++_src;
+               } while (--chunks);
+               n &= 3;
+       }
+
+       if (n >= 2) {
+               *((volatile u16 *)vdest) = *((volatile u16 *)src);
+               src += 2;
+               vdest += 2;
+               n -= 2;
+       }
+
+       if (n > 0) {
+               u8 buf[2];
+
+               *(u16 *)buf = *((volatile u16 *)vdest);
+               buf[0] = *((u8 *)src);
+               *((volatile u16 *)vdest) = *(u16 *)buf;
+       }
+
+       __asm__ __volatile__ ("sync" : : : "memory");
+}
+EXPORT_SYMBOL(mpc52xx_memcpy2lpb16);
diff -u linux-2.6.29.1.orig/arch/powerpc/include/asm/mpc52xx.h  
linux-2.6.29.1/arch/powerpc/include/asm/mpc52xx.h
--- linux-2.6.29.1.orig/arch/powerpc/include/asm/mpc52xx.h       
2009-04-02 22:55:27.000000000 +0200
+++ linux-2.6.29.1/arch/powerpc/include/asm/mpc52xx.h   2009-06-09  
21:14:31.000000000 +0200
@@ -274,6 +274,8 @@
  extern void mpc52xx_map_common_devices(void);
  extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv);
  extern void mpc52xx_restart(char *cmd);
+extern void mpc52xx_memcpy2lpb16(volatile void __iomem *dest, const  
void *src,
+                                unsigned long n);

  /* mpc52xx_pic.c */
  extern void mpc52xx_init_irq(void);
diff -u linux-2.6.29.1.orig/include/linux/mtd/map.h  
linux-2.6.29.1/include/linux/mtd/map.h
--- linux-2.6.29.1.orig/include/linux/mtd/map.h 2009-04-02  
22:55:27.000000000 +0200
+++ linux-2.6.29.1/include/linux/mtd/map.h      2009-06-08  
14:28:05.000000000 +0200
@@ -13,6 +13,9 @@
  #include <asm/unaligned.h>
  #include <asm/system.h>
  #include <asm/io.h>
+#ifdef CONFIG_PPC_MPC52xx
+#include <asm/mpc52xx.h>
+#endif

  #ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
  #define map_bankwidth(map) 1
@@ -417,6 +420,11 @@

  static inline void inline_map_copy_to(struct map_info *map, unsigned  
long to, const void *from, ssize_t len)
  {
+#ifdef CONFIG_PPC_MPC52xx
+       if (map->bankwidth == 2)
+               mpc52xx_memcpy2lpb16(map->virt + to, from, len);
+       else
+#endif
         memcpy_toio(map->virt + to, from, len);
  }


[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH -next] powerpc/85xx: Add support for X-ES MPC85xx boards
From: Kumar Gala @ 2009-06-09 19:43 UTC (permalink / raw)
  To: Nate Case; +Cc: linuxppc-dev
In-Reply-To: <1244573639.29684.1536.camel@localhost.localdomain>


On Jun 9, 2009, at 1:53 PM, Nate Case wrote:

> On Mon, 2009-06-08 at 17:52 -0500, Kumar Gala wrote:
>>> +static void xes_mpc85xx_configure_l1(void)
>>> +{
> [snip]
>>
>> I'd prefer we move this into __setup_cpu_e500v1/__setup_cpu_e500v2 so
>> its done for all processors regardless of platform.
>
> How does something like this look?  Let me know and I can test and
> submit it separately.
>
> - Nate
>
> diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/ 
> powerpc/kernel/cpu_setup_fsl_booke.S
> index eb4b9ad..546804f 100644
> --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> @@ -17,6 +17,34 @@
> #include <asm/cputable.h>
> #include <asm/ppc_asm.h>
>
> +_GLOBAL(__e500_icache_enable)

I'd prefer we test to see if the cache is enabled and if it is just  
return

> +	mfspr	r3, SPRN_L1CSR1
> +	oris	r3, r3, L1CSR1_CPE@h
> +	ori	r3, r3, (L1CSR1_ICFI | L1CSR1_ICE)
> +	mtspr	SPRN_L1CSR1, r3		/* Enable I-Cache */
> +	isync
> +	blr
> +
> +_GLOBAL(__e500_dcache_enable)

I'd prefer we test to see if the cache is enabled and if it is just  
return
>
> +	msync
> +	isync
> +	li	r3, 0
> +	mtspr	SPRN_L1CSR0, r3		/* Disable */
> +	msync
> +	isync
> +	li	r3, L1CSR0_DCFI

should probably flash reset the locks as well.

>
> +	mtspr	SPRN_L1CSR0, r3		/* Invalidate */
> +	msync
> +	isync
> +	mfspr	r3, SPRN_L1CSR0
> +	oris	r3, r3, L1CSR0_CPE@h
> +	ori	r3, r3, (L1CSR0_DCFI | L1CSR0_DCE)
> +	msync
> +	isync
> +	mtspr	SPRN_L1CSR0, r3		/* Enable */
> +	isync
> +	blr
> +
> _GLOBAL(__setup_cpu_e20

^ permalink raw reply

* Re: [BUILD FAILURE 01/04] Next June 04:PPC64 randconfig [drivers/staging/comedi/drivers.o]
From: Geert Uytterhoeven @ 2009-06-09 18:54 UTC (permalink / raw)
  To: subrata
  Cc: sachinp, fmhess, sfr, linux-kernel, Linuxppc-dev, Ian Abbott,
	linux-next, paulus, Greg KH, Geert.Uytterhoeven, David Miller
In-Reply-To: <1244572446.5497.32.camel@subratamodak.linux.ibm.com>

On Tue, Jun 9, 2009 at 20:34, Subrata Modak<subrata@linux.vnet.ibm.com> wro=
te:
> On Tue, 2009-06-09 at 13:50 +1000, Benjamin Herrenschmidt wrote:
>> On Sun, 2009-06-07 at 20:06 +0530, Subrata Modak wrote:
>> > On Sat, 2009-06-06 at 09:36 -0400, Frank Mori Hess wrote:
>> > > On Saturday 06 June 2009, Greg KH wrote:
>> > > > Frank and Ian, any thoughts about the vmap call in the
>> > > > comedi_buf_alloc() call? =C2=A0Why is it using PAGE_KERNEL_NOCACHE=
, and what
>> > > > is the prealloc_buf buffer used for?
>> > >
>> > > It is a circular buffer used to hold data streaming either to or fro=
m a
>> > > board (for example when producing an analog output waveform). =C2=A0=
Reads and
>> > > writes to the device files read/write to the circular buffer, plus a=
 few
>> > > drivers do dma directly to/from it. =C2=A0I personally don't have a =
problem
>> > > with requiring drivers to have their own dma buffers and making them=
 copy
>> > > data between their private dma buffers and the main circular buffer.=
 =C2=A0I
>> > > guess the original design wanted to support zero-copy dma.
>> >
>> > Great to hear that. How about a patch that solves my build problem on
>> > PPC64(the problem seems to be existing for long) ?
>>
>> In any case, doing PAGE_KERNEL_NOCACHE for DMA memory is incorrect on
>> many architectures. So at this stage, there's no much option but ifdef I
>> suspect for now until this is fixed properly.
>
> Ok. But, i am not sure whether Greg will agree to this. If, Ok, is the
> following patch i sent earlier Ok ?
>
> http://lkml.org/lkml/2009/6/5/462,

Your patch helps powerpc only. Compilation is still broken on most
other architectures.

>> It does make sense to want to have some memory like that shared between
>> user space and DMA, though I don't know what the right approach that
>> works on all archs is at this stage. Worth asking the Alsa guys, I think
>> they have similar issues :-)
>>
>> But doing double buffering might do the trick fine for now.

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k=
.org

In personal conversations with technical people, I call myself a hacker. Bu=
t
when I'm talking to journalists I just say "programmer" or something like t=
hat.
							    -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH -next] powerpc/85xx: Add support for X-ES MPC85xx boards
From: Nate Case @ 2009-06-09 18:53 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <2AF4BA69-D05A-4D2E-BD32-5E1C93ACF445@kernel.crashing.org>

On Mon, 2009-06-08 at 17:52 -0500, Kumar Gala wrote:
> > +static void xes_mpc85xx_configure_l1(void)
> > +{
[snip]
> 
> I'd prefer we move this into __setup_cpu_e500v1/__setup_cpu_e500v2 so  
> its done for all processors regardless of platform.

How does something like this look?  Let me know and I can test and
submit it separately.

- Nate

diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index eb4b9ad..546804f 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -17,6 +17,34 @@
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
 
+_GLOBAL(__e500_icache_enable)
+	mfspr	r3, SPRN_L1CSR1
+	oris	r3, r3, L1CSR1_CPE@h
+	ori	r3, r3, (L1CSR1_ICFI | L1CSR1_ICE)
+	mtspr	SPRN_L1CSR1, r3		/* Enable I-Cache */
+	isync
+	blr
+
+_GLOBAL(__e500_dcache_enable)
+	msync
+	isync
+	li	r3, 0
+	mtspr	SPRN_L1CSR0, r3		/* Disable */
+	msync
+	isync
+	li	r3, L1CSR0_DCFI
+	mtspr	SPRN_L1CSR0, r3		/* Invalidate */
+	msync
+	isync
+	mfspr	r3, SPRN_L1CSR0
+	oris	r3, r3, L1CSR0_CPE@h
+	ori	r3, r3, (L1CSR0_DCFI | L1CSR0_DCE)
+	msync
+	isync
+	mtspr	SPRN_L1CSR0, r3		/* Enable */
+	isync
+	blr
+
 _GLOBAL(__setup_cpu_e200)
 	/* enable dedicated debug exception handling resources (Debug APU) */
 	mfspr	r3,SPRN_HID0
@@ -25,7 +53,16 @@ _GLOBAL(__setup_cpu_e200)
 	b	__setup_e200_ivors
 _GLOBAL(__setup_cpu_e500v1)
 _GLOBAL(__setup_cpu_e500v2)
-	b	__setup_e500_ivors
+	mflr	r4
+	bl	__e500_icache_enable
+	bl	__e500_dcache_enable
+	bl	__setup_e500_ivors
+	mtlr	r4
+	blr
 _GLOBAL(__setup_cpu_e500mc)
-	b	__setup_e500mc_ivors
-
+	mflr	r4
+	bl	__e500_icache_enable
+	bl	__e500_dcache_enable
+	bl	__setup_e500mc_ivors
+	mtlr	r4
+	blr

^ permalink raw reply related

* Re: [BUILD FAILURE 02/04] Next June 04:PPC64 randconfig [drivers/usb/host/ohci-hcd.o]
From: Subrata Modak @ 2009-06-09 18:36 UTC (permalink / raw)
  To: linux-usb, David Brownell, Arnd Bergmann
  Cc: Sachin P Sant, Randy Dunlap, David Brownell, Roman Weissgaerber,
	Stephen Rothwell, Linux-Kernel, Linuxppc-dev, Linux-Next, kernel
In-Reply-To: <20090605182651.24094.36577.sendpatchset@elm3a191.beaverton.ibm.com>

On Fri, 2009-06-05 at 13:26 -0500, Subrata Modak wrote:
> >On Thu, 2009-06-04 at 10:07 -0400, Jon Smirl wrote:
> >On Thu, Jun 4, 2009 at 9:31 AM, Subrata Modak
> > <subrata@linux.vnet.ibm.com> wrote:
> > > CC      drivers/usb/host/ohci-hcd.o
> > > In file included from drivers/usb/host/ohci-hcd.c:1060:
> > > drivers/usb/host/ohci-ppc-of.c:242:2: error: #error "No endianess selected for ppc-of-ohci"
> > > make[3]: *** [drivers/usb/host/ohci-hcd.o] Error 1
> > > make[2]: *** [drivers/usb/host] Error 2
> > > make[1]: *** [drivers/usb] Error 2
> > > make: *** [drivers] Error 2
> > >
> > > I reported this earlier, and there were some discussions:
> > > http://groups.google.co.kr/group/linux.kernel/browse_thread/thread/edff9d5572d3d225
> > 
> > Proposed patch by Arnd should fix this. It has not been merged.
> > http://lkml.org/lkml/2009/4/22/49
> 
> Correct, it fixes the issue. However, since few changes might have gone
> to the Kconfig, the patch does not apply cleanly. Below is the patch, just
> a retake of the earlier one, but on the latest code. 
> 
> David,
> 
> Can you please pickup the following patch ?

David,

Is it you who will be merging this patch. Or, do i need to send it to
somebody else ?

Regards--
Subrata

> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>,
> Resent-by: Subrata Modak <subrata@linux.vnet.ibm.com>
> ---
> 
> --- linux-2.6.30-rc8/drivers/usb/host/Kconfig.orig	2009-06-05 10:31:30.000000000 -0500
> +++ linux-2.6.30-rc8/drivers/usb/host/Kconfig	2009-06-05 10:37:53.000000000 -0500
> @@ -181,26 +181,26 @@ config USB_OHCI_HCD_PPC_SOC
>  	  Enables support for the USB controller on the MPC52xx or
>  	  STB03xxx processor chip.  If unsure, say Y.
> 
> -config USB_OHCI_HCD_PPC_OF
> -	bool "OHCI support for PPC USB controller on OF platform bus"
> -	depends on USB_OHCI_HCD && PPC_OF
> -	default y
> -	---help---
> -	  Enables support for the USB controller PowerPC present on the
> -	  OpenFirmware platform bus.
> -
>  config USB_OHCI_HCD_PPC_OF_BE
> -	bool "Support big endian HC"
> -	depends on USB_OHCI_HCD_PPC_OF
> -	default y
> +	bool "OHCI support for OF platform bus (big endian)"
> +	depends on USB_OHCI_HCD && PPC_OF
>  	select USB_OHCI_BIG_ENDIAN_DESC
>  	select USB_OHCI_BIG_ENDIAN_MMIO
> +	---help---
> +	Enables support for big-endian USB controllers present on the
> +	OpenFirmware platform bus.
> 
>  config USB_OHCI_HCD_PPC_OF_LE
> -	bool "Support little endian HC"
> -	depends on USB_OHCI_HCD_PPC_OF
> -	default n
> +	bool "OHCI support for OF platform bus (little endian)"
> +	depends on USB_OHCI_HCD && PPC_OF
>  	select USB_OHCI_LITTLE_ENDIAN
> +	---help---
> +	Enables support for little-endian USB controllers present on the
> +	OpenFirmware platform bus.
> +
> +	config USB_OHCI_HCD_PPC_OF
> +	bool
> +	default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
> 
>  config USB_OHCI_HCD_PCI
>  	bool "OHCI support for PCI-bus USB controllers"
> 
> ---
> Regards--
> Subrata
> >

^ permalink raw reply

* Re: [BUILD FAILURE 01/04] Next June 04:PPC64 randconfig [drivers/staging/comedi/drivers.o]
From: Subrata Modak @ 2009-06-09 18:34 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Greg KH
  Cc: sachinp, fmhess, sfr, linux-kernel, Linuxppc-dev, Ian Abbott,
	linux-next, paulus, Geert.Uytterhoeven, geert, David Miller
In-Reply-To: <1244519418.5235.2.camel@pasglop>

On Tue, 2009-06-09 at 13:50 +1000, Benjamin Herrenschmidt wrote:
> On Sun, 2009-06-07 at 20:06 +0530, Subrata Modak wrote:
> > On Sat, 2009-06-06 at 09:36 -0400, Frank Mori Hess wrote:
> > > On Saturday 06 June 2009, Greg KH wrote:
> > > > Frank and Ian, any thoughts about the vmap call in the
> > > > comedi_buf_alloc() call?  Why is it using PAGE_KERNEL_NOCACHE, and what
> > > > is the prealloc_buf buffer used for?
> > > 
> > > It is a circular buffer used to hold data streaming either to or from a 
> > > board (for example when producing an analog output waveform).  Reads and 
> > > writes to the device files read/write to the circular buffer, plus a few 
> > > drivers do dma directly to/from it.  I personally don't have a problem 
> > > with requiring drivers to have their own dma buffers and making them copy 
> > > data between their private dma buffers and the main circular buffer.  I 
> > > guess the original design wanted to support zero-copy dma.
> > 
> > Great to hear that. How about a patch that solves my build problem on
> > PPC64(the problem seems to be existing for long) ? 
> 
> In any case, doing PAGE_KERNEL_NOCACHE for DMA memory is incorrect on
> many architectures. So at this stage, there's no much option but ifdef I
> suspect for now until this is fixed properly.

Ok. But, i am not sure whether Greg will agree to this. If, Ok, is the
following patch i sent earlier Ok ?

http://lkml.org/lkml/2009/6/5/462,

Regards--
Subrata

> 
> It does make sense to want to have some memory like that shared between
> user space and DMA, though I don't know what the right approach that
> works on all archs is at this stage. Worth asking the Alsa guys, I think
> they have similar issues :-)
> 
> But doing double buffering might do the trick fine for now.
> 
> Cheers,
> Ben.
> 
> 
> 
> 

^ permalink raw reply

* "Info threads" hangs in Linux-2.6.29 with KGDBOE
From: srikanth krishnakar @ 2009-06-09 18:08 UTC (permalink / raw)
  To: kgdb-bugreport; +Cc: Jason Wessel

[-- Attachment #1: Type: text/plain, Size: 2064 bytes --]

Hi All,

*ISSUE *: "*Info threads*" hangs in KGDBOE
Kernel : Linux-2.6.29
Bug found in Architectures: PowerPC (ppc32), x86
-------

While trying to run kernel* Linux-2.6.29* on* PowerPC* Xilinx target
with *KGDBOE
*enabled.  Further issues arise when I run  "*info threads*" after
connecting to the target. following is the error:

(gdb) target remote udp:10.161.2.35:6443

warning: The remote protocol may be unreliable over UDP.

Some events may be lost, rendering further debugging impossible.

Remote debugging using udp:10.161.2.35:6443

kgdb_breakpoint () at kernel/kgdb.c:1803

1803            arch_kgdb_breakpoint();

(gdb) info threads
[New Thread -2]
[New Thread 2]
[New Thread 3]
[New Thread 4]
[New Thread 5]
[New Thread 6]
[New Thread 59]
[New Thread 67]
[New Thread 101]
[New Thread 102]
[New Thread 103]
[New Thread 104]
[New Thread 105]
 14 Thread 105 (nfsiod)  __switch_to (prev=<value optimized out>,
new=0xcf89c100) at arch/powerpc/kernel/process.c:411
 13 Thread 104 (aio/0)  __switch_to (prev=<value optimized out>,
new=0xcf82f4e0) at arch/powerpc/kernel/process.c:411
 12 Thread 103 (kswapd0)  __switch_to (prev=<value optimized out>,
new=0xcf82f4e0) at arch/powerpc/kernel/process.c:411
 11 Thread 102 (pdflush)  __switch_to (prev=<value optimized out>,
new=0xcf82e880) at arch/powerpc/kernel/process.c:411
 10 Thread 101 (pdflush)  Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...

Finally kernel dies, after these error messages. This issue is not found
till Linux-2.6.28.10 kernel version, KGDBOE works fine in x86 & PowerPC. Now
the bug is seen in x86 (32bit) and PowerPC from kernel version Linux-2.6.29

Hope this should not be raw_smp_processor_id issue ! The CPU ID returned in
both arch's is 0.  Which patch in netpoll* or any net device has caused this
issue.

One more thing to notice in x86 or PowerPC the kernel dies exactly after
reply of four threads/packets.


Thanks,
Srikanth Krishnakar

[-- Attachment #2: Type: text/html, Size: 2831 bytes --]

^ permalink raw reply

* Re: SD card over (xilinx_)SPI, timeout error while CID
From: Joachim Foerster @ 2009-06-09 17:26 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: lorenz, dbrownell, john.linn, joachim
In-Reply-To: <1244216069.21470.12.camel@localhost>

Hi,

On Fri, 2009-06-05 at 17:34 +0200, Joachim Foerster wrote:
> we have a very strange problem with SD-card-over-SPI support using
> 2.6.29.4 on our custom PowerPC 405 (Virtex-4 FX FPGA) based board. To
> summarize the problem in one sentence: mmc_spi gets a timeout (error
> -110) after sending MMC command "CMD10" (CID, card identification?).

The problem seems to be these DMA transfers/methods (?), which are used
by mmc_spi, if spi->master->dev.parent->dma_mask is non-NULL in
mmc_spi_probe() .
We detected the problem in form of kind of "data loss/corruption" in
mmc_spi_readbytes() after spi_sync() is called. Data is received
correctly by xilinx_spi (and thus by spi_sync())!

Background: The CMD10 is the first "bigger" ;-) (16 bytes) block
transfer, where mmc_spi waits for the token 0xfe by calling
mmc_spi_skip() in the end and later on receives these 16 bytes. But the
token seems to be "lost/corrupted" and thus a timeout occurs.

For now our dirty workaround is, to remove DMA support by commenting out
the "if (spi->master->dev.parent->dma_mask)" block in mmc_spi_probe().

Note, that in the old 2.6.26+arch/ppc this dma_mask is NULL - so DMA
code is never activated in mmc_spi_probe()!

Conclusion: Either DMA code in mmc_spi has a bug OR dma_*() functions
have a bug OR the device tree setup code should not assign a dma_mask to
xilinx_spi devices?

Any hints? Where do we have to look in case there is something wrong in
device tree setup?

 Joachim

^ permalink raw reply

* Re: [PATCH v4] zone_reclaim is always 0 by default
From: Mel Gorman @ 2009-06-09 14:38 UTC (permalink / raw)
  To: KOSAKI Motohiro
  Cc: Rik van Riel, Christoph Lameter, linux-mm, Zhang, Yanmin, LKML,
	linuxppc-dev, Robin Holt, linux-ia64, Andrew Morton, Wu Fengguang
In-Reply-To: <20090609211721.DD9A.A69D9226@jp.fujitsu.com>

On Tue, Jun 09, 2009 at 10:48:34PM +0900, KOSAKI Motohiro wrote:
> Hi
> 
> sorry for late responce. my e-mail reading speed is very slow ;-)
> 
> First, Could you please read past thread?
> I think many topic of this mail are already discussed.
> 

I think I caught them all but the horrible fact of the matter is that
whether zone_reclaim_mode should be 1 or 0 on NUMA machines is "it depends".
There are arguements for both and no clear winner.

> 
> > On Thu, Jun 04, 2009 at 07:23:15PM +0900, KOSAKI Motohiro wrote:
> > > 
> > > Current linux policy is, zone_reclaim_mode is enabled by default if the machine
> > > has large remote node distance. it's because we could assume that large distance
> > > mean large server until recently.
> > > 
> > 
> > We don't make assumptions about the server being large, small or otherwise. The
> > affinity tables reporting a distance of 20 or more is saying "remote memory
> > has twice the latency of local memory". This is true irrespective of workload
> > and implies that going off-node has a real penalty regardless of workload.
> 
> No.
> Now, we talk about off-node allocation vs unnecessary file cache dropping.
> IOW, off-node allocation vs disk access.
> 

Even if we used GFP flags to identify the file pages, there is no guarantee
that we are taking the correct action to keep "relevant" pages in memory.

> Then, the worth doesn't only depend on off-node distance, but also depend on
> workload IO tendency and IO speed.
> 
> Fujitsu has 64 core ia64 HPC box, zone-reclaim sometimes made performance
> degression although its box. 
> 

I bet if it was 0, that the off-node accesses would somewtimes make
"performance degression" as well :(

> So, I don't think this problem is small vs large machine issue.
> nor i7 issue.
> high-speed P2P CPU integrated memory controller expose old issue.
> 
> 
> > > In general, workload depended configration shouldn't put into default settings.
> > > 
> > > However, current code is long standing about two year. Highest POWER and IA64 HPC machine
> > > (only) use this setting.
> > > 
> > > Thus, x86 and almost rest architecture change default setting, but Only power and ia64
> > > remain current configuration for backward-compatibility.
> > > 
> > 
> > What about if it's x86-64-based NUMA but it's not i7 based. There, the
> > NUMA distances might really mean something and that zone_reclaim behaviour
> > is desirable.
> 
> hmmm..
> I don't hope ignore AMD, I think it's common characterastic of P2P and
> integrated memory controller machine.
> 
> Also, I don't hope detect CPU family or similar, because we need update
> such code evey when Intel makes new cpu.
> 
> Can we detect P2P interconnect machine? I'm not sure.
> 

I've no idea. It's not just I7 because some of the AMD chips will have
integrated memory controllers as well. We were somewhat depending on the
affinity information providing the necessary information.

> > I think if we're going down the road of setting the default, it shouldn't be
> > per-architecture defaults as such. Other choices for addressing this might be;
> > 
> > 1. Make RECLAIM_DISTANCE a variable on x86. Set it to 20 by default, and 5
> >    (or some other sensible figure) on i7
> > 
> > 2. There should be a per-arch modifier callback for the affinity
> >    distances. If the x86 code detects the CPU is an i7, it can reduce the
> >    reported latencies to be more in line with expected reality.
> > 
> > 3. Do not use zone_reclaim() for file-backed data if more than 20% of memory
> >    overall is free. The difficulty is figuring out if the allocation is for
> >    file pages.
> > 
> > 4. Change zone_reclaim_mode default to mean "do your best to figure it
> >    out". Patch 1 would default large distances to 1 to see what happens.
> >    Then apply a heuristic when in figure-it-out mode and using reclaim_mode == 1
> > 
> > 	If we have locally reclaimed 2% of the nodes memory in file pages
> > 	within the last 5 seconds when >= 20% of total physical memory was
> > 	free, then set the reclaim_mode to 0 on the assumption the node is
> > 	mostly caching pages and shouldn't be reclaimed to avoid excessive IO
> > 
> > Option 1 would appear to be the most straight-forward but option 2
> > should be doable. Option 3 and 4 could turn into a rats nest and I would
> > consider those approaches a bit more drastic.
> 
> hmhm. 
> I think the key-point of option 1 and 2 are proper hardware detecting way.
> 
> option 3 and 4 are more prefere idea to me. I like workload adapted heuristic.
> but you already pointed out its hard, because page-allocator don't know
> allocation purpose ;)
> 

Option 3 may be undoable. Even if the allocations are tagged as "this is
a file-backed allocation", we have no way of detecting how important
that is to the overall workload. Option 4 would be the preference. It's
a heuristic that might let us down, but the administrator can override
it and fix the reclaim_mode in the event we get it wrong.

> 
> > > @@ -10,6 +10,12 @@ struct device_node;
> > >  
> > >  #include <asm/mmzone.h>
> > >  
> > > +/*
> > > + * Distance above which we begin to use zone reclaim
> > > + */
> > > +#define RECLAIM_DISTANCE 20
> > > +
> > > +
> > 
> > Where is the ia-64-specific modifier to RECAIM_DISTANCE?
> 
> 
> arch/ia64/include/asm/topology.h has
> 
> 	/*
> 	 * Distance above which we begin to use zone reclaim
> 	 */
> 	#define RECLAIM_DISTANCE 15
> 
> 
> I don't think distance==15 is machine independent proper definition.
> but there is long lived definition ;)
> 
> 
> 
> 

-- 
Mel Gorman
Part-time Phd Student                          Linux Technology Center
University of Limerick                         IBM Dublin Software Lab

^ permalink raw reply

* Re: [Powerpc/SLQB] Next June 06 : BUG during scsi initialization
From: Nick Piggin @ 2009-06-09 14:19 UTC (permalink / raw)
  To: Sachin Sant; +Cc: Stephen Rothwell, Pekka J Enberg, linux-next, linuxppc-dev
In-Reply-To: <4A2D001E.5060802@in.ibm.com>

On Mon, Jun 08, 2009 at 05:42:14PM +0530, Sachin Sant wrote:
> Pekka J Enberg wrote:
> >Hi Sachin,
> __slab_alloc_page: nid=2, cache_node=c0000000de01ba00, cache_list=c0000000de01ba00
> __slab_alloc_page: nid=2, cache_node=c0000000de01bd00, cache_list=c0000000de01bd00
> __slab_alloc_page: nid=2, cache_node=c0000000de01ba00, cache_lisBUG: spinlock bad magic on CPU#1, modprobe/62
>  lock: c0000000008c4280, .magic: 7dcc61f0, .owner:  || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT/724596736, .owner_cpu: 4095
> Call Trace:
> [c0000000c7da36d0] [c0000000000116e0] .show_stack+0x6c/0x16c (unreliable)
> [c0000000c7da3780] [c000000000365bcc] .spin_bug+0xb0/0xd4
> [c0000000c7da3810] [c000000000365e94] ._raw_spin_lock+0x48/0x184
> [c0000000c7da38b0] [c0000000005de4f8] ._spin_lock+0x10/0x24
> [c0000000c7da3920] [c000000000141240] .__slab_alloc_page+0x410/0x4b4
> [c0000000c7da39e0] [c000000000142804] .kmem_cache_alloc+0x13c/0x21c
> [c0000000c7da3aa0] [c0000000001431dc] .kmem_cache_create+0x294/0x2a8
> [c0000000c7da3b90] [d000000000ea1438] .scsi_init_queue+0x38/0x170 [scsi_mod]
> [c0000000c7da3c20] [d000000000ea1334] .init_scsi+0x1c/0xe8 [scsi_mod]
> [c0000000c7da3ca0] [c0000000000092c0] .do_one_initcall+0x80/0x19c
> [c0000000c7da3d90] [c0000000000c09c8] .SyS_init_module+0xe0/0x244
> [c0000000c7da3e30] [c000000000008534] syscall_exit+0x0/0x40

I can't really work it out. It seems to be the kmem_cache_cache which has
a problem, but there have already been lots of caches created and even
this samw cache_node already used right beforehand with no problem.

Unless a CPU or node comes up or something right at this point or the
caller is scheduled onto a different CPU... oopses seem to all
have CPU#1, wheras boot CPU is probably #0 (these CPUs are node 0
and memory is only on node 1 and 2 where there are no CPUs if I read
correctly).

I still can't see the reason for the failure, but can you try this
patch please and show dmesg?

---
 mm/slqb.c |   34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

Index: linux-2.6/mm/slqb.c
===================================================================
--- linux-2.6.orig/mm/slqb.c
+++ linux-2.6/mm/slqb.c
@@ -963,6 +963,7 @@ static struct slqb_page *allocate_slab(s
 
 	flags |= s->allocflags;
 
+	flags &= ~0x2000;
 	page = (struct slqb_page *)alloc_pages_node(node, flags, s->order);
 	if (!page)
 		return NULL;
@@ -1357,6 +1358,8 @@ static noinline void *__slab_alloc_page(
 	unsigned int colour;
 	void *object;
 
+	if (gfpflags & 0x2000)
+		printk("SLQB: __slab_alloc_page cpu=%d request node=%d\n", smp_processor_id(), node);
 	c = get_cpu_slab(s, smp_processor_id());
 	colour = c->colour_next;
 	c->colour_next += s->colour_off;
@@ -1374,6 +1377,8 @@ static noinline void *__slab_alloc_page(
 	if (unlikely(!page))
 		return page;
 
+	if (gfpflags & 0x2000)
+		printk("SLQB: __slab_alloc_page cpu=%d,nid=%d request node=%d page node=%d\n", smp_processor_id(), numa_node_id(), node, slqb_page_to_nid(page));
 	if (!NUMA_BUILD || likely(slqb_page_to_nid(page) == numa_node_id())) {
 		struct kmem_cache_cpu *c;
 		int cpu = smp_processor_id();
@@ -1382,6 +1387,7 @@ static noinline void *__slab_alloc_page(
 		l = &c->list;
 		page->list = l;
 
+		printk("SLQB: __slab_alloc_page spin_lock(%p)\n", &l->page_lock);
 		spin_lock(&l->page_lock);
 		l->nr_slabs++;
 		l->nr_partial++;
@@ -1398,6 +1404,8 @@ static noinline void *__slab_alloc_page(
 		l = &n->list;
 		page->list = l;
 
+		printk("SLQB: __slab_alloc_page spin_lock(%p)\n", &n->list_lock);
+		printk("SLQB: __slab_alloc_page spin_lock(%p)\n", &l->page_lock);
 		spin_lock(&n->list_lock);
 		spin_lock(&l->page_lock);
 		l->nr_slabs++;
@@ -1411,6 +1419,7 @@ static noinline void *__slab_alloc_page(
 #endif
 	}
 	VM_BUG_ON(!object);
+	printk("SLQB: __slab_alloc_page OK\n");
 	return object;
 }
 
@@ -1440,6 +1449,8 @@ static void *__remote_slab_alloc_node(st
 	struct kmem_cache_list *l;
 	void *object;
 
+	if (gfpflags & 0x2000)
+		printk("SLQB: __remote_slab_alloc_node cpu=%d request node=%d\n", smp_processor_id(), node);
 	n = s->node_slab[node];
 	if (unlikely(!n)) /* node has no memory */
 		return NULL;
@@ -1541,7 +1552,11 @@ static __always_inline void *slab_alloc(
 
 again:
 	local_irq_save(flags);
+	if (gfpflags & 0x2000)
+		printk("SLQB: slab_alloc cpu=%d,nid=%d request node=%d\n", smp_processor_id(), numa_node_id(), node);
 	object = __slab_alloc(s, gfpflags, node);
+	if (gfpflags & 0x2000)
+		printk("SLQB: slab_alloc cpu=%d return=%p\n", smp_processor_id(), object);
 	local_irq_restore(flags);
 
 	if (unlikely(slab_debug(s)) && likely(object)) {
@@ -2869,9 +2884,12 @@ void __init kmem_cache_init(void)
 #endif
 
 #ifdef CONFIG_SMP
+	printk("SLQB: kmem_cache_init possible CPUs: ");
 	for_each_possible_cpu(i) {
 		struct kmem_cache_cpu *c;
 
+		printk("%d ", i);
+
 		c = &per_cpu(kmem_cache_cpus, i);
 		init_kmem_cache_cpu(&kmem_cache_cache, c);
 		kmem_cache_cache.cpu_slab[i] = c;
@@ -2886,14 +2904,18 @@ void __init kmem_cache_init(void)
 		kmem_node_cache.cpu_slab[i] = c;
 #endif
 	}
+	printk("\n");
 #else
 	init_kmem_cache_cpu(&kmem_cache_cache, &kmem_cache_cache.cpu_slab);
 #endif
 
 #ifdef CONFIG_NUMA
-	for_each_node_state(i, N_NORMAL_MEMORY) {
+	printk("SLQB: kmem_cache_init possible nodes: ");
+	for_each_node_state(i, N_POSSIBLE) {
 		struct kmem_cache_node *n;
 
+		printk("%d ", i);
+
 		n = &per_cpu(kmem_cache_nodes, i);
 		init_kmem_cache_node(&kmem_cache_cache, n);
 		kmem_cache_cache.node_slab[i] = n;
@@ -2906,6 +2928,7 @@ void __init kmem_cache_init(void)
 		init_kmem_cache_node(&kmem_node_cache, n);
 		kmem_node_cache.node_slab[i] = n;
 	}
+	printk("\n");
 #endif
 
 	/* Caches that are not of the two-to-the-power-of size */
@@ -3040,12 +3063,17 @@ struct kmem_cache *kmem_cache_create(con
 	if (!kmem_cache_create_ok(name, size, align, flags))
 		goto err;
 
-	s = kmem_cache_alloc(&kmem_cache_cache, GFP_KERNEL);
+	printk("SLQB: kmem_cache_create %s size=%d align=%d flags=%lx\n", name, (int)size, (int)align, flags);
+
+	s = kmem_cache_alloc(&kmem_cache_cache, GFP_KERNEL|0x2000);
 	if (!s)
 		goto err;
 
-	if (kmem_cache_open(s, name, size, align, flags, ctor, 1))
+	printk("SLQB: kmem_cache_create %s kmem_cache allocated\n", name);
+	if (kmem_cache_open(s, name, size, align, flags, ctor, 1)) {
+		printk("SLQB: kmem_cache_create %s kmem_cache opened\n", name);
 		return s;
+	}
 
 	kmem_cache_free(&kmem_cache_cache, s);
 

^ permalink raw reply

* [PATCH 2.6.31] ehca: Tolerate dynamic memory operations and huge pages
From: Hannes Hering @ 2009-06-09 13:59 UTC (permalink / raw)
  To: rdreier; +Cc: alexs, linux-kernel, ewg, linuxppc-dev, raisch, ossrosch

This patch implements toleration of dynamic memory operations and 16 GB
gigantic pages. On module load the driver walks through available system
memory, checks for available memory ranges and then registers the kernel
internal memory region accordingly. The translation of address ranges is
implemented via a 3-level busmap.

Signed-off-by: Hannes Hering <hering2@de.ibm.com>

---
This patch is built and tested against infiniband.git. Please apply for 2.6.31.

Regards

Hannes

Index: infiniband/drivers/infiniband/hw/ehca/ehca_main.c
===================================================================
--- infiniband.orig/drivers/infiniband/hw/ehca/ehca_main.c	2009-06-09 14:20:37.000000000 +0200
+++ infiniband/drivers/infiniband/hw/ehca/ehca_main.c	2009-06-09 14:20:47.000000000 +0200
@@ -52,7 +52,7 @@
 #include "ehca_tools.h"
 #include "hcp_if.h"
 
-#define HCAD_VERSION "0026"
+#define HCAD_VERSION "0027"
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
@@ -506,6 +506,7 @@
 	shca->ib_device.detach_mcast	    = ehca_detach_mcast;
 	shca->ib_device.process_mad	    = ehca_process_mad;
 	shca->ib_device.mmap		    = ehca_mmap;
+	shca->ib_device.dma_ops		    = &ehca_dma_mapping_ops;
 
 	if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
 		shca->ib_device.uverbs_cmd_mask |=
@@ -1028,17 +1029,23 @@
 		goto module_init1;
 	}
 
+	ret = ehca_create_busmap();
+	if (ret) {
+		ehca_gen_err("Cannot create busmap.");
+		goto module_init2;
+	}
+
 	ret = ibmebus_register_driver(&ehca_driver);
 	if (ret) {
 		ehca_gen_err("Cannot register eHCA device driver");
 		ret = -EINVAL;
-		goto module_init2;
+		goto module_init3;
 	}
 
 	ret = register_memory_notifier(&ehca_mem_nb);
 	if (ret) {
 		ehca_gen_err("Failed registering memory add/remove notifier");
-		goto module_init3;
+		goto module_init4;
 	}
 
 	if (ehca_poll_all_eqs != 1) {
@@ -1053,9 +1060,12 @@
 
 	return 0;
 
-module_init3:
+module_init4:
 	ibmebus_unregister_driver(&ehca_driver);
 
+module_init3:
+	ehca_destroy_busmap();
+
 module_init2:
 	ehca_destroy_slab_caches();
 
@@ -1073,6 +1083,8 @@
 
 	unregister_memory_notifier(&ehca_mem_nb);
 
+	ehca_destroy_busmap();
+
 	ehca_destroy_slab_caches();
 
 	ehca_destroy_comp_pool();
Index: infiniband/drivers/infiniband/hw/ehca/ehca_mrmw.c
===================================================================
--- infiniband.orig/drivers/infiniband/hw/ehca/ehca_mrmw.c	2009-06-09 14:20:37.000000000 +0200
+++ infiniband/drivers/infiniband/hw/ehca/ehca_mrmw.c	2009-06-09 14:20:47.000000000 +0200
@@ -53,6 +53,39 @@
 /* max number of rpages (per hcall register_rpages) */
 #define MAX_RPAGES 512
 
+/* DMEM toleration management */
+#define EHCA_SECTSHIFT        SECTION_SIZE_BITS
+#define EHCA_SECTSIZE          (1UL << EHCA_SECTSHIFT)
+#define EHCA_HUGEPAGESHIFT     34
+#define EHCA_HUGEPAGE_SIZE     (1UL << EHCA_HUGEPAGESHIFT)
+#define EHCA_HUGEPAGE_PFN_MASK ((EHCA_HUGEPAGE_SIZE - 1) >> PAGE_SHIFT)
+#define EHCA_INVAL_ADDR        0xFFFFFFFFFFFFFFFFULL
+#define EHCA_DIR_INDEX_SHIFT 13                   /* 8k Entries in 64k block */
+#define EHCA_TOP_INDEX_SHIFT (EHCA_DIR_INDEX_SHIFT * 2)
+#define EHCA_MAP_ENTRIES (1 << EHCA_DIR_INDEX_SHIFT)
+#define EHCA_TOP_MAP_SIZE (0x10000)               /* currently fixed map size */
+#define EHCA_DIR_MAP_SIZE (0x10000)
+#define EHCA_ENT_MAP_SIZE (0x10000)
+#define EHCA_INDEX_MASK (EHCA_MAP_ENTRIES - 1)
+#define EHCA_REG_MR 0
+#define EHCA_REG_BUSMAP_MR (~0)
+
+static unsigned long ehca_mr_len;
+/*
+ * Memory map data structures
+ */
+struct ehca_dir_bmap {
+	u64 ent[EHCA_MAP_ENTRIES];
+};
+struct ehca_top_bmap {
+	struct ehca_dir_bmap *dir[EHCA_MAP_ENTRIES];
+};
+struct ehca_bmap {
+	struct ehca_top_bmap *top[EHCA_MAP_ENTRIES];
+};
+
+static struct ehca_bmap *ehca_bmap;
+
 static struct kmem_cache *mr_cache;
 static struct kmem_cache *mw_cache;
 
@@ -68,6 +101,8 @@
 #define EHCA_MR_PGSHIFT1M  20
 #define EHCA_MR_PGSHIFT16M 24
 
+static u64 ehca_map_vaddr(void *caddr);
+
 static u32 ehca_encode_hwpage_size(u32 pgsize)
 {
 	int log = ilog2(pgsize);
@@ -135,7 +170,8 @@
 			goto get_dma_mr_exit0;
 		}
 
-		ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE,
+		ret = ehca_reg_maxmr(shca, e_maxmr,
+				     (void *)ehca_map_vaddr((void *)KERNELBASE),
 				     mr_access_flags, e_pd,
 				     &e_maxmr->ib.ib_mr.lkey,
 				     &e_maxmr->ib.ib_mr.rkey);
@@ -251,7 +287,7 @@
 
 		ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
 				  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
-				  &e_mr->ib.ib_mr.rkey);
+				  &e_mr->ib.ib_mr.rkey, EHCA_REG_MR);
 		if (ret) {
 			ib_mr = ERR_PTR(ret);
 			goto reg_phys_mr_exit1;
@@ -370,7 +406,7 @@
 
 	ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
 			  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
-			  &e_mr->ib.ib_mr.rkey);
+			  &e_mr->ib.ib_mr.rkey, EHCA_REG_MR);
 	if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) {
 		ehca_warn(pd->device, "failed to register mr "
 			  "with hwpage_size=%llx", hwpage_size);
@@ -794,7 +830,7 @@
 	ret = ehca_reg_mr(shca, e_fmr, NULL,
 			  fmr_attr->max_pages * (1 << fmr_attr->page_shift),
 			  mr_access_flags, e_pd, &pginfo,
-			  &tmp_lkey, &tmp_rkey);
+			  &tmp_lkey, &tmp_rkey, EHCA_REG_MR);
 	if (ret) {
 		ib_fmr = ERR_PTR(ret);
 		goto alloc_fmr_exit1;
@@ -983,6 +1019,10 @@
 
 /*----------------------------------------------------------------------*/
 
+static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca,
+				   struct ehca_mr *e_mr,
+				   struct ehca_mr_pginfo *pginfo);
+
 int ehca_reg_mr(struct ehca_shca *shca,
 		struct ehca_mr *e_mr,
 		u64 *iova_start,
@@ -991,7 +1031,8 @@
 		struct ehca_pd *e_pd,
 		struct ehca_mr_pginfo *pginfo,
 		u32 *lkey, /*OUT*/
-		u32 *rkey) /*OUT*/
+		u32 *rkey, /*OUT*/
+		int reg_busmap)
 {
 	int ret;
 	u64 h_ret;
@@ -1015,7 +1056,11 @@
 
 	e_mr->ipz_mr_handle = hipzout.handle;
 
-	ret = ehca_reg_mr_rpages(shca, e_mr, pginfo);
+	if (reg_busmap)
+		ret = ehca_reg_bmap_mr_rpages(shca, e_mr, pginfo);
+	else
+		ret = ehca_reg_mr_rpages(shca, e_mr, pginfo);
+
 	if (ret)
 		goto ehca_reg_mr_exit1;
 
@@ -1316,7 +1361,7 @@
 		e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
 
 		ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
-				  e_pd, pginfo, lkey, rkey);
+				  e_pd, pginfo, lkey, rkey, EHCA_REG_MR);
 		if (ret) {
 			u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
 			memcpy(&e_mr->flags, &(save_mr.flags),
@@ -1409,7 +1454,7 @@
 	ret = ehca_reg_mr(shca, e_fmr, NULL,
 			  (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
 			  e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
-			  &tmp_rkey);
+			  &tmp_rkey, EHCA_REG_MR);
 	if (ret) {
 		u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
 		memcpy(&e_fmr->flags, &(save_mr.flags),
@@ -1478,6 +1523,90 @@
 } /* end ehca_reg_smr() */
 
 /*----------------------------------------------------------------------*/
+static inline void *ehca_calc_sectbase(int top, int dir, int idx)
+{
+	unsigned long ret = idx;
+	ret |= dir << EHCA_DIR_INDEX_SHIFT;
+	ret |= top << EHCA_TOP_INDEX_SHIFT;
+	return abs_to_virt(ret << SECTION_SIZE_BITS);
+}
+
+#define ehca_bmap_valid(entry) \
+	((u64)entry != (u64)EHCA_INVAL_ADDR)
+
+static u64 ehca_reg_mr_section(int top, int dir, int idx, u64 *kpage,
+			       struct ehca_shca *shca, struct ehca_mr *mr,
+			       struct ehca_mr_pginfo *pginfo)
+{
+	u64 h_ret = 0;
+	unsigned long page = 0;
+	u64 rpage = virt_to_abs(kpage);
+	int page_count;
+
+	void *sectbase = ehca_calc_sectbase(top, dir, idx);
+	if ((unsigned long)sectbase & (pginfo->hwpage_size - 1)) {
+		ehca_err(&shca->ib_device, "reg_mr_section will probably fail:"
+					   "hwpage_size does not fit to "
+					   "section start address");
+	}
+	page_count = EHCA_SECTSIZE / pginfo->hwpage_size;
+
+	while (page < page_count) {
+		u64 rnum;
+		for (rnum = 0; (rnum < MAX_RPAGES) && (page < page_count);
+		     rnum++) {
+			void *pg = sectbase + ((page++) * pginfo->hwpage_size);
+			kpage[rnum] = virt_to_abs(pg);
+		}
+
+		h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, mr,
+			ehca_encode_hwpage_size(pginfo->hwpage_size),
+			0, rpage, rnum);
+
+		if ((h_ret != H_SUCCESS) && (h_ret != H_PAGE_REGISTERED)) {
+			ehca_err(&shca->ib_device, "register_rpage_mr failed");
+			return h_ret;
+		}
+	}
+	return h_ret;
+}
+
+static u64 ehca_reg_mr_sections(int top, int dir, u64 *kpage,
+				struct ehca_shca *shca, struct ehca_mr *mr,
+				struct ehca_mr_pginfo *pginfo)
+{
+	u64 hret = H_SUCCESS;
+	int idx;
+
+	for (idx = 0; idx < EHCA_MAP_ENTRIES; idx++) {
+		if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]->ent[idx]))
+			continue;
+
+		hret = ehca_reg_mr_section(top, dir, idx, kpage, shca, mr,
+					   pginfo);
+		if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+				return hret;
+	}
+	return hret;
+}
+
+static u64 ehca_reg_mr_dir_sections(int top, u64 *kpage, struct ehca_shca *shca,
+				    struct ehca_mr *mr,
+				    struct ehca_mr_pginfo *pginfo)
+{
+	u64 hret = H_SUCCESS;
+	int dir;
+
+	for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) {
+		if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
+			continue;
+
+		hret = ehca_reg_mr_sections(top, dir, kpage, shca, mr, pginfo);
+		if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+				return hret;
+	}
+	return hret;
+}
 
 /* register internal max-MR to internal SHCA */
 int ehca_reg_internal_maxmr(
@@ -1495,6 +1624,11 @@
 	u32 num_hwpages;
 	u64 hw_pgsize;
 
+	if (!ehca_bmap) {
+		ret = -EFAULT;
+		goto ehca_reg_internal_maxmr_exit0;
+	}
+
 	e_mr = ehca_mr_new();
 	if (!e_mr) {
 		ehca_err(&shca->ib_device, "out of memory");
@@ -1504,8 +1638,8 @@
 	e_mr->flags |= EHCA_MR_FLAG_MAXMR;
 
 	/* register internal max-MR on HCA */
-	size_maxmr = (u64)high_memory - PAGE_OFFSET;
-	iova_start = (u64 *)KERNELBASE;
+	size_maxmr = ehca_mr_len;
+	iova_start = (u64 *)ehca_map_vaddr((void *)KERNELBASE);
 	ib_pbuf.addr = 0;
 	ib_pbuf.size = size_maxmr;
 	num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
@@ -1524,7 +1658,7 @@
 
 	ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
 			  &pginfo, &e_mr->ib.ib_mr.lkey,
-			  &e_mr->ib.ib_mr.rkey);
+			  &e_mr->ib.ib_mr.rkey, EHCA_REG_BUSMAP_MR);
 	if (ret) {
 		ehca_err(&shca->ib_device, "reg of internal max MR failed, "
 			 "e_mr=%p iova_start=%p size_maxmr=%llx num_kpages=%x "
@@ -2077,8 +2211,8 @@
 		     u64 *iova_start)
 {
 	/* a MR is treated as max-MR only if it fits following: */
-	if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
-	    (iova_start == (void *)KERNELBASE)) {
+	if ((size == ehca_mr_len) &&
+	    (iova_start == (void *)ehca_map_vaddr((void *)KERNELBASE))) {
 		ehca_gen_dbg("this is a max-MR");
 		return 1;
 	} else
@@ -2184,3 +2318,350 @@
 	if (mw_cache)
 		kmem_cache_destroy(mw_cache);
 }
+
+static inline int ehca_init_top_bmap(struct ehca_top_bmap *ehca_top_bmap,
+				     int dir)
+{
+	if (!ehca_bmap_valid(ehca_top_bmap->dir[dir])) {
+		ehca_top_bmap->dir[dir] =
+			kmalloc(sizeof(struct ehca_dir_bmap), GFP_KERNEL);
+		if (!ehca_top_bmap->dir[dir])
+			return -ENOMEM;
+		/* Set map block to 0xFF according to EHCA_INVAL_ADDR */
+		memset(ehca_top_bmap->dir[dir], 0xFF, EHCA_ENT_MAP_SIZE);
+	}
+	return 0;
+}
+
+static inline int ehca_init_bmap(struct ehca_bmap *ehca_bmap, int top, int dir)
+{
+	if (!ehca_bmap_valid(ehca_bmap->top[top])) {
+		ehca_bmap->top[top] =
+			kmalloc(sizeof(struct ehca_top_bmap), GFP_KERNEL);
+		if (!ehca_bmap->top[top])
+			return -ENOMEM;
+		/* Set map block to 0xFF according to EHCA_INVAL_ADDR */
+		memset(ehca_bmap->top[top], 0xFF, EHCA_DIR_MAP_SIZE);
+	}
+	return ehca_init_top_bmap(ehca_bmap->top[top], dir);
+}
+
+static inline int ehca_calc_index(unsigned long i, unsigned long s)
+{
+	return (i >> s) & EHCA_INDEX_MASK;
+}
+
+void ehca_destroy_busmap(void)
+{
+	int top, dir;
+
+	if (!ehca_bmap)
+		return;
+
+	for (top = 0; top < EHCA_MAP_ENTRIES; top++) {
+		if (!ehca_bmap_valid(ehca_bmap->top[top]))
+			continue;
+		for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) {
+			if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
+				continue;
+
+			kfree(ehca_bmap->top[top]->dir[dir]);
+		}
+
+		kfree(ehca_bmap->top[top]);
+	}
+
+	kfree(ehca_bmap);
+	ehca_bmap = NULL;
+}
+
+static int ehca_update_busmap(unsigned long pfn, unsigned long nr_pages)
+{
+	unsigned long i, start_section, end_section;
+	int top, dir, idx;
+
+	if (!nr_pages)
+		return 0;
+
+	if (!ehca_bmap) {
+		ehca_bmap = kmalloc(sizeof(struct ehca_bmap), GFP_KERNEL);
+		if (!ehca_bmap)
+			return -ENOMEM;
+		/* Set map block to 0xFF according to EHCA_INVAL_ADDR */
+		memset(ehca_bmap, 0xFF, EHCA_TOP_MAP_SIZE);
+	}
+
+	start_section = phys_to_abs(pfn * PAGE_SIZE) / EHCA_SECTSIZE;
+	end_section = phys_to_abs((pfn + nr_pages) * PAGE_SIZE) / EHCA_SECTSIZE;
+	for (i = start_section; i < end_section; i++) {
+		int ret;
+		top = ehca_calc_index(i, EHCA_TOP_INDEX_SHIFT);
+		dir = ehca_calc_index(i, EHCA_DIR_INDEX_SHIFT);
+		idx = i & EHCA_INDEX_MASK;
+
+		ret = ehca_init_bmap(ehca_bmap, top, dir);
+		if (ret) {
+			ehca_destroy_busmap();
+			return ret;
+		}
+		ehca_bmap->top[top]->dir[dir]->ent[idx] = ehca_mr_len;
+		ehca_mr_len += EHCA_SECTSIZE;
+	}
+	return 0;
+}
+
+static int ehca_is_hugepage(unsigned long pfn)
+{
+	int page_order;
+
+	if (pfn & EHCA_HUGEPAGE_PFN_MASK)
+		return 0;
+
+	page_order = compound_order(pfn_to_page(pfn));
+	if (page_order + PAGE_SHIFT != EHCA_HUGEPAGESHIFT)
+		return 0;
+
+	return 1;
+}
+
+static int ehca_create_busmap_callback(unsigned long initial_pfn,
+				       unsigned long total_nr_pages, void *arg)
+{
+	int ret;
+	unsigned long pfn, start_pfn, end_pfn, nr_pages;
+
+	if ((total_nr_pages * PAGE_SIZE) < EHCA_HUGEPAGE_SIZE)
+		return ehca_update_busmap(initial_pfn, total_nr_pages);
+
+	/* Given chunk is >= 16GB -> check for hugepages */
+	start_pfn = initial_pfn;
+	end_pfn = initial_pfn + total_nr_pages;
+	pfn = start_pfn;
+
+	while (pfn < end_pfn) {
+		if (ehca_is_hugepage(pfn)) {
+			/* Add mem found in front of the hugepage */
+			nr_pages = pfn - start_pfn;
+			ret = ehca_update_busmap(start_pfn, nr_pages);
+			if (ret)
+				return ret;
+			/* Skip the hugepage */
+			pfn += (EHCA_HUGEPAGE_SIZE / PAGE_SIZE);
+			start_pfn = pfn;
+		} else
+			pfn += (EHCA_SECTSIZE / PAGE_SIZE);
+	}
+
+	/* Add mem found behind the hugepage(s)  */
+	nr_pages = pfn - start_pfn;
+	return ehca_update_busmap(start_pfn, nr_pages);
+}
+
+int ehca_create_busmap(void)
+{
+	int ret;
+
+	ehca_mr_len = 0;
+	ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, NULL,
+				   ehca_create_busmap_callback);
+	return ret;
+}
+
+static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca,
+				   struct ehca_mr *e_mr,
+				   struct ehca_mr_pginfo *pginfo)
+{
+	int top;
+	u64 hret, *kpage;
+
+	kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+	if (!kpage) {
+		ehca_err(&shca->ib_device, "kpage alloc failed");
+		return -ENOMEM;
+	}
+	for (top = 0; top < EHCA_MAP_ENTRIES; top++) {
+		if (!ehca_bmap_valid(ehca_bmap->top[top]))
+			continue;
+		hret = ehca_reg_mr_dir_sections(top, kpage, shca, e_mr, pginfo);
+		if ((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
+			break;
+	}
+
+	ehca_free_fw_ctrlblock(kpage);
+
+	if (hret == H_SUCCESS)
+		return 0; /* Everything is fine */
+	else {
+		ehca_err(&shca->ib_device, "ehca_reg_bmap_mr_rpages failed, "
+				 "h_ret=%lli e_mr=%p top=%x lkey=%x "
+				 "hca_hndl=%llx mr_hndl=%llx", hret, e_mr, top,
+				 e_mr->ib.ib_mr.lkey,
+				 shca->ipz_hca_handle.handle,
+				 e_mr->ipz_mr_handle.handle);
+		return ehca2ib_return_code(hret);
+	}
+}
+
+static u64 ehca_map_vaddr(void *caddr)
+{
+	int top, dir, idx;
+	unsigned long abs_addr, offset;
+	u64 entry;
+
+	if (!ehca_bmap)
+		return EHCA_INVAL_ADDR;
+
+	abs_addr = virt_to_abs(caddr);
+	top = ehca_calc_index(abs_addr, EHCA_TOP_INDEX_SHIFT + EHCA_SECTSHIFT);
+	if (!ehca_bmap_valid(ehca_bmap->top[top]))
+		return EHCA_INVAL_ADDR;
+
+	dir = ehca_calc_index(abs_addr, EHCA_DIR_INDEX_SHIFT + EHCA_SECTSHIFT);
+	if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
+		return EHCA_INVAL_ADDR;
+
+	idx = ehca_calc_index(abs_addr, EHCA_SECTSHIFT);
+
+	entry = ehca_bmap->top[top]->dir[dir]->ent[idx];
+	if (ehca_bmap_valid(entry)) {
+		offset = (unsigned long)caddr & (EHCA_SECTSIZE - 1);
+		return entry | offset;
+	} else
+		return EHCA_INVAL_ADDR;
+}
+
+static int ehca_dma_mapping_error(struct ib_device *dev, u64 dma_addr)
+{
+	return dma_addr == EHCA_INVAL_ADDR;
+}
+
+static u64 ehca_dma_map_single(struct ib_device *dev, void *cpu_addr,
+			       size_t size, enum dma_data_direction direction)
+{
+	if (cpu_addr)
+		return ehca_map_vaddr(cpu_addr);
+	else
+		return EHCA_INVAL_ADDR;
+}
+
+static void ehca_dma_unmap_single(struct ib_device *dev, u64 addr, size_t size,
+				  enum dma_data_direction direction)
+{
+	/* This is only a stub; nothing to be done here */
+}
+
+static u64 ehca_dma_map_page(struct ib_device *dev, struct page *page,
+			     unsigned long offset, size_t size,
+			     enum dma_data_direction direction)
+{
+	u64 addr;
+
+	if (offset + size > PAGE_SIZE)
+		return EHCA_INVAL_ADDR;
+
+	addr = ehca_map_vaddr(page_address(page));
+	if (!ehca_dma_mapping_error(dev, addr))
+		addr += offset;
+
+	return addr;
+}
+
+static void ehca_dma_unmap_page(struct ib_device *dev, u64 addr, size_t size,
+				enum dma_data_direction direction)
+{
+	/* This is only a stub; nothing to be done here */
+}
+
+static int ehca_dma_map_sg(struct ib_device *dev, struct scatterlist *sgl,
+			   int nents, enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i;
+
+	for_each_sg(sgl, sg, nents, i) {
+		u64 addr;
+		addr = ehca_map_vaddr(sg_virt(sg));
+		if (ehca_dma_mapping_error(dev, addr))
+			return 0;
+
+		sg->dma_address = addr;
+		sg->dma_length = sg->length;
+	}
+	return nents;
+}
+
+static void ehca_dma_unmap_sg(struct ib_device *dev, struct scatterlist *sg,
+			      int nents, enum dma_data_direction direction)
+{
+	/* This is only a stub; nothing to be done here */
+}
+
+static u64 ehca_dma_address(struct ib_device *dev, struct scatterlist *sg)
+{
+	return sg->dma_address;
+}
+
+static unsigned int ehca_dma_len(struct ib_device *dev, struct scatterlist *sg)
+{
+	return sg->length;
+}
+
+static void ehca_dma_sync_single_for_cpu(struct ib_device *dev, u64 addr,
+					 size_t size,
+					 enum dma_data_direction dir)
+{
+	dma_sync_single_for_cpu(dev->dma_device, addr, size, dir);
+}
+
+static void ehca_dma_sync_single_for_device(struct ib_device *dev, u64 addr,
+					    size_t size,
+					    enum dma_data_direction dir)
+{
+	dma_sync_single_for_device(dev->dma_device, addr, size, dir);
+}
+
+static void *ehca_dma_alloc_coherent(struct ib_device *dev, size_t size,
+				     u64 *dma_handle, gfp_t flag)
+{
+	struct page *p;
+	void *addr = NULL;
+	u64 dma_addr;
+
+	p = alloc_pages(flag, get_order(size));
+	if (p) {
+		addr = page_address(p);
+		dma_addr = ehca_map_vaddr(addr);
+		if (ehca_dma_mapping_error(dev, dma_addr)) {
+			free_pages((unsigned long)addr,	get_order(size));
+			return NULL;
+		}
+		if (dma_handle)
+			*dma_handle = dma_addr;
+		return addr;
+	}
+	return NULL;
+}
+
+static void ehca_dma_free_coherent(struct ib_device *dev, size_t size,
+				   void *cpu_addr, u64 dma_handle)
+{
+	if (cpu_addr && size)
+		free_pages((unsigned long)cpu_addr, get_order(size));
+}
+
+
+struct ib_dma_mapping_ops ehca_dma_mapping_ops = {
+	.mapping_error = ehca_dma_mapping_error,
+	.map_single = ehca_dma_map_single,
+	.unmap_single = ehca_dma_unmap_single,
+	.map_page = ehca_dma_map_page,
+	.unmap_page = ehca_dma_unmap_page,
+	.map_sg = ehca_dma_map_sg,
+	.unmap_sg = ehca_dma_unmap_sg,
+	.dma_address = ehca_dma_address,
+	.dma_len = ehca_dma_len,
+	.sync_single_for_cpu = ehca_dma_sync_single_for_cpu,
+	.sync_single_for_device = ehca_dma_sync_single_for_device,
+	.alloc_coherent = ehca_dma_alloc_coherent,
+	.free_coherent = ehca_dma_free_coherent,
+};
Index: infiniband/drivers/infiniband/hw/ehca/ehca_mrmw.h
===================================================================
--- infiniband.orig/drivers/infiniband/hw/ehca/ehca_mrmw.h	2009-06-09 14:20:37.000000000 +0200
+++ infiniband/drivers/infiniband/hw/ehca/ehca_mrmw.h	2009-06-09 14:20:47.000000000 +0200
@@ -50,7 +50,8 @@
 		struct ehca_pd *e_pd,
 		struct ehca_mr_pginfo *pginfo,
 		u32 *lkey,
-		u32 *rkey);
+		u32 *rkey,
+		int reg_busmap);
 
 int ehca_reg_mr_rpages(struct ehca_shca *shca,
 		       struct ehca_mr *e_mr,
@@ -118,4 +119,9 @@
 
 void ehca_mr_deletenew(struct ehca_mr *mr);
 
+int ehca_create_busmap(void);
+
+void ehca_destroy_busmap(void);
+
+extern struct ib_dma_mapping_ops ehca_dma_mapping_ops;
 #endif  /*_EHCA_MRMW_H_*/

^ permalink raw reply

* Re: [PATCH v4] zone_reclaim is always 0 by default
From: KOSAKI Motohiro @ 2009-06-09 13:48 UTC (permalink / raw)
  To: Mel Gorman
  Cc: Rik van Riel, Christoph Lameter, linux-mm, Zhang, Yanmin, LKML,
	linuxppc-dev, Robin Holt, kosaki.motohiro, linux-ia64,
	Andrew Morton, Wu Fengguang
In-Reply-To: <20090608115048.GA15070@csn.ul.ie>

Hi

sorry for late responce. my e-mail reading speed is very slow ;-)

First, Could you please read past thread?
I think many topic of this mail are already discussed.


> On Thu, Jun 04, 2009 at 07:23:15PM +0900, KOSAKI Motohiro wrote:
> > 
> > Current linux policy is, zone_reclaim_mode is enabled by default if the machine
> > has large remote node distance. it's because we could assume that large distance
> > mean large server until recently.
> > 
> 
> We don't make assumptions about the server being large, small or otherwise. The
> affinity tables reporting a distance of 20 or more is saying "remote memory
> has twice the latency of local memory". This is true irrespective of workload
> and implies that going off-node has a real penalty regardless of workload.

No.
Now, we talk about off-node allocation vs unnecessary file cache dropping.
IOW, off-node allocation vs disk access.

Then, the worth doesn't only depend on off-node distance, but also depend on
workload IO tendency and IO speed.

Fujitsu has 64 core ia64 HPC box, zone-reclaim sometimes made performance
degression although its box. 

So, I don't think this problem is small vs large machine issue.
nor i7 issue.
high-speed P2P CPU integrated memory controller expose old issue.


> > In general, workload depended configration shouldn't put into default settings.
> > 
> > However, current code is long standing about two year. Highest POWER and IA64 HPC machine
> > (only) use this setting.
> > 
> > Thus, x86 and almost rest architecture change default setting, but Only power and ia64
> > remain current configuration for backward-compatibility.
> > 
> 
> What about if it's x86-64-based NUMA but it's not i7 based. There, the
> NUMA distances might really mean something and that zone_reclaim behaviour
> is desirable.

hmmm..
I don't hope ignore AMD, I think it's common characterastic of P2P and
integrated memory controller machine.

Also, I don't hope detect CPU family or similar, because we need update
such code evey when Intel makes new cpu.

Can we detect P2P interconnect machine? I'm not sure.


> I think if we're going down the road of setting the default, it shouldn't be
> per-architecture defaults as such. Other choices for addressing this might be;
> 
> 1. Make RECLAIM_DISTANCE a variable on x86. Set it to 20 by default, and 5
>    (or some other sensible figure) on i7
> 
> 2. There should be a per-arch modifier callback for the affinity
>    distances. If the x86 code detects the CPU is an i7, it can reduce the
>    reported latencies to be more in line with expected reality.
> 
> 3. Do not use zone_reclaim() for file-backed data if more than 20% of memory
>    overall is free. The difficulty is figuring out if the allocation is for
>    file pages.
> 
> 4. Change zone_reclaim_mode default to mean "do your best to figure it
>    out". Patch 1 would default large distances to 1 to see what happens.
>    Then apply a heuristic when in figure-it-out mode and using reclaim_mode == 1
> 
> 	If we have locally reclaimed 2% of the nodes memory in file pages
> 	within the last 5 seconds when >= 20% of total physical memory was
> 	free, then set the reclaim_mode to 0 on the assumption the node is
> 	mostly caching pages and shouldn't be reclaimed to avoid excessive IO
> 
> Option 1 would appear to be the most straight-forward but option 2
> should be doable. Option 3 and 4 could turn into a rats nest and I would
> consider those approaches a bit more drastic.

hmhm. 
I think the key-point of option 1 and 2 are proper hardware detecting way.

option 3 and 4 are more prefere idea to me. I like workload adapted heuristic.
but you already pointed out its hard, because page-allocator don't know
allocation purpose ;)


> > @@ -10,6 +10,12 @@ struct device_node;
> >  
> >  #include <asm/mmzone.h>
> >  
> > +/*
> > + * Distance above which we begin to use zone reclaim
> > + */
> > +#define RECLAIM_DISTANCE 20
> > +
> > +
> 
> Where is the ia-64-specific modifier to RECAIM_DISTANCE?


arch/ia64/include/asm/topology.h has

	/*
	 * Distance above which we begin to use zone reclaim
	 */
	#define RECLAIM_DISTANCE 15


I don't think distance==15 is machine independent proper definition.
but there is long lived definition ;)

^ permalink raw reply

* Re: [PATCH v4] zone_reclaim is always 0 by default
From: Robin Holt @ 2009-06-09 12:02 UTC (permalink / raw)
  To: Mel Gorman
  Cc: Rik van Riel, Christoph Lameter, linux-mm, Zhang, Yanmin, LKML,
	linuxppc-dev, Robin Holt, KOSAKI Motohiro, linux-ia64,
	Andrew Morton, Wu Fengguang
In-Reply-To: <20090609103754.GN18380@csn.ul.ie>

On Tue, Jun 09, 2009 at 11:37:55AM +0100, Mel Gorman wrote:
> On Tue, Jun 09, 2009 at 04:55:07AM -0500, Robin Holt wrote:
> > On Mon, Jun 08, 2009 at 12:50:48PM +0100, Mel Gorman wrote:
> > 
> > Let me start by saying I agree completely with everything you wrote and
> > still disagree with this patch, but was willing to compromise and work
> > around this for our upcoming x86_64 machine by putting a "value add"
> > into our packaging of adding a sysctl that turns reclaim back on.
> > 
> 
> To be honest, I'm more leaning towards a NACK than an ACK on this one. I
> don't support enough NUMA machines to feel strongly enough about it but
> unconditionally setting zone_reclaim_mode to 0 on x86-64 just because i7's
> might be there seems ill-advised to me and will have other consequences for
> existing more traditional x86-64 NUMA machines.

I was sort-of planning on coming up with an x86_64 arch specific function
for setting zone_reclaim_mode, but didn't like the direction things
were going.

Something to the effect of...
--- 20090609.orig/mm/page_alloc.c       2009-06-09 06:51:34.000000000 -0500
+++ 20090609/mm/page_alloc.c    2009-06-09 06:55:00.160762069 -0500
@@ -2326,12 +2326,7 @@ static void build_zonelists(pg_data_t *p
        while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
                int distance = node_distance(local_node, node);
 
-               /*
-                * If another node is sufficiently far away then it is better
-                * to reclaim pages in a zone before going off node.
-                */
-               if (distance > RECLAIM_DISTANCE)
-                       zone_reclaim_mode = 1;
+               zone_reclaim_mode = arch_zone_reclaim_mode(distance);
 
                /*
                 * We don't want to pressure a particular node.

And then letting each arch define an arch_zone_reclaim_mode().  If other
values are needed in the determination, we would add parameters to
reflect this.

For ia64, add

static inline ia64_zone_reclaim_mode(int distance)
{
	if (distance > 15)
		return 1;
}

#define	arch_zone_reclaim_mode(_d)	ia64_zone_reclaim_mode(_d)


Then, inside x86_64_zone_reclaim_mode(), I could make it something like
	if (distance > 40 || is_uv_system())
		return 1;

In the end, I didn't think this fight was worth fighting given how ugly
this felt.  Upon second thought, I am beginning to think it is not that
bad, but I also don't think it is that good either.

Thanks,
Robin

^ permalink raw reply

* [PATCH] mpc83xx/usb.c: fix usb mux setup for mpc834x
From: Peter Korsgaard @ 2009-06-09 11:43 UTC (permalink / raw)
  To: galak, linuxppc-dev

usb0 and usb1 mux settings in the sicrl register were swapped (twice!)
in mpc834x_usb_cfg(), leading to various strange issues with fsl-ehci
and full speed devices.

The USB port config on mpc834x is done using 2 muxes: Port 0 is always
used for MPH port 0, and port 1 can either be used for MPH port 1 or DR
(unless DR uses TMDI phy or OTG, then it uses both ports) - See 8349 RM
figure 1-4..

mpc8349_usb_cfg() had this inverted for the DR, and it also had the bit
positions of the usb0 / usb1 mux settings swapped. It would basically
work if you specified port1 instead of port0 for the MPH controller (and
happened to use ULPI phys), which is what all the 834x dts have done,
even though that configuration is physically invalid.

Instead fix mpc8349_usb_cfg() and adjust the dts files to match reality.

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
---
 arch/powerpc/boot/dts/asp834x-redboot.dts |    2 +-
 arch/powerpc/boot/dts/mpc8349emitx.dts    |    2 +-
 arch/powerpc/boot/dts/mpc834x_mds.dts     |    2 +-
 arch/powerpc/boot/dts/sbc8349.dts         |    2 +-
 arch/powerpc/platforms/83xx/mpc83xx.h     |    4 ++--
 arch/powerpc/platforms/83xx/usb.c         |   10 +++++-----
 6 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/powerpc/boot/dts/asp834x-redboot.dts b/arch/powerpc/boot/dts/asp834x-redboot.dts
index 7da84fd..261d10c 100644
--- a/arch/powerpc/boot/dts/asp834x-redboot.dts
+++ b/arch/powerpc/boot/dts/asp834x-redboot.dts
@@ -167,7 +167,7 @@
 			interrupt-parent = <&ipic>;
 			interrupts = <39 0x8>;
 			phy_type = "ulpi";
-			port1;
+			port0;
 		};
 		/* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */
 		usb@23000 {
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 1ae38f0..e540d44 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -156,7 +156,7 @@
 			interrupt-parent = <&ipic>;
 			interrupts = <39 0x8>;
 			phy_type = "ulpi";
-			port1;
+			port0;
 		};
 
 		usb@23000 {
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index d9f0a23..a667fe7 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -153,7 +153,7 @@
 			interrupt-parent = <&ipic>;
 			interrupts = <39 0x8>;
 			phy_type = "ulpi";
-			port1;
+			port0;
 		};
 		/* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */
 		usb@23000 {
diff --git a/arch/powerpc/boot/dts/sbc8349.dts b/arch/powerpc/boot/dts/sbc8349.dts
index a36dbbc..c7e1c4b 100644
--- a/arch/powerpc/boot/dts/sbc8349.dts
+++ b/arch/powerpc/boot/dts/sbc8349.dts
@@ -144,7 +144,7 @@
 			interrupt-parent = <&ipic>;
 			interrupts = <39 0x8>;
 			phy_type = "ulpi";
-			port1;
+			port0;
 		};
 		/* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */
 		usb@23000 {
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
index 83cfe51..d1dc5b0 100644
--- a/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -22,8 +22,8 @@
 /* system i/o configuration register low */
 #define MPC83XX_SICRL_OFFS         0x114
 #define MPC834X_SICRL_USB_MASK     0x60000000
-#define MPC834X_SICRL_USB0         0x40000000
-#define MPC834X_SICRL_USB1         0x20000000
+#define MPC834X_SICRL_USB0         0x20000000
+#define MPC834X_SICRL_USB1         0x40000000
 #define MPC831X_SICRL_USB_MASK     0x00000c00
 #define MPC831X_SICRL_USB_ULPI     0x00000800
 #define MPC8315_SICRL_USB_MASK     0x000000fc
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c
index 11e1fac..f53eba3 100644
--- a/arch/powerpc/platforms/83xx/usb.c
+++ b/arch/powerpc/platforms/83xx/usb.c
@@ -51,21 +51,21 @@ int mpc834x_usb_cfg(void)
 					!strcmp(prop, "utmi_wide"))) {
 			sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
 			sicrh |= MPC834X_SICRH_USB_UTMI;
-			port1_is_dr = 1;
+			port0_is_dr = 1;
 		} else if (prop && !strcmp(prop, "serial")) {
 			dr_mode = of_get_property(np, "dr_mode", NULL);
 			if (dr_mode && !strcmp(dr_mode, "otg")) {
 				sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
-				port1_is_dr = 1;
+				port0_is_dr = 1;
 			} else {
-				sicrl |= MPC834X_SICRL_USB0;
+				sicrl |= MPC834X_SICRL_USB1;
 			}
 		} else if (prop && !strcmp(prop, "ulpi")) {
-			sicrl |= MPC834X_SICRL_USB0;
+			sicrl |= MPC834X_SICRL_USB1;
 		} else {
 			printk(KERN_WARNING "834x USB PHY type not supported\n");
 		}
-		port0_is_dr = 1;
+		port1_is_dr = 1;
 		of_node_put(np);
 	}
 	np = of_find_compatible_node(NULL, NULL, "fsl-usb2-mph");
-- 
1.6.2

^ permalink raw reply related

* Re: [PATCH v4] zone_reclaim is always 0 by default
From: Mel Gorman @ 2009-06-09 10:37 UTC (permalink / raw)
  To: Robin Holt
  Cc: Rik van Riel, Christoph Lameter, linux-mm, Zhang, Yanmin, LKML,
	linuxppc-dev, KOSAKI Motohiro, linux-ia64, Andrew Morton,
	Wu Fengguang
In-Reply-To: <20090609095507.GA9851@attica.americas.sgi.com>

On Tue, Jun 09, 2009 at 04:55:07AM -0500, Robin Holt wrote:
> On Mon, Jun 08, 2009 at 12:50:48PM +0100, Mel Gorman wrote:
> 
> Let me start by saying I agree completely with everything you wrote and
> still disagree with this patch, but was willing to compromise and work
> around this for our upcoming x86_64 machine by putting a "value add"
> into our packaging of adding a sysctl that turns reclaim back on.
> 

To be honest, I'm more leaning towards a NACK than an ACK on this one. I
don't support enough NUMA machines to feel strongly enough about it but
unconditionally setting zone_reclaim_mode to 0 on x86-64 just because i7's
might be there seems ill-advised to me and will have other consequences for
existing more traditional x86-64 NUMA machines.

> ...
> > > Index: b/arch/powerpc/include/asm/topology.h
> > > ===================================================================
> > > --- a/arch/powerpc/include/asm/topology.h
> > > +++ b/arch/powerpc/include/asm/topology.h
> > > @@ -10,6 +10,12 @@ struct device_node;
> > >  
> > >  #include <asm/mmzone.h>
> > >  
> > > +/*
> > > + * Distance above which we begin to use zone reclaim
> > > + */
> > > +#define RECLAIM_DISTANCE 20
> > > +
> > > +
> > 
> > Where is the ia-64-specific modifier to RECAIM_DISTANCE?
> 
> It was already defined as 15 in arch/ia64/include/asm/topology.h
> 

/me slaps self

thanks

-- 
Mel Gorman
Part-time Phd Student                          Linux Technology Center
University of Limerick                         IBM Dublin Software Lab

^ permalink raw reply

* Re: [PATCH v4] zone_reclaim is always 0 by default
From: Robin Holt @ 2009-06-09  9:55 UTC (permalink / raw)
  To: Mel Gorman
  Cc: Rik van Riel, Christoph Lameter, linux-mm, Zhang, Yanmin, LKML,
	linuxppc-dev, Robin Holt, KOSAKI Motohiro, linux-ia64,
	Andrew Morton, Wu Fengguang
In-Reply-To: <20090608115048.GA15070@csn.ul.ie>

On Mon, Jun 08, 2009 at 12:50:48PM +0100, Mel Gorman wrote:

Let me start by saying I agree completely with everything you wrote and
still disagree with this patch, but was willing to compromise and work
around this for our upcoming x86_64 machine by putting a "value add"
into our packaging of adding a sysctl that turns reclaim back on.

...
> > Index: b/arch/powerpc/include/asm/topology.h
> > ===================================================================
> > --- a/arch/powerpc/include/asm/topology.h
> > +++ b/arch/powerpc/include/asm/topology.h
> > @@ -10,6 +10,12 @@ struct device_node;
> >  
> >  #include <asm/mmzone.h>
> >  
> > +/*
> > + * Distance above which we begin to use zone reclaim
> > + */
> > +#define RECLAIM_DISTANCE 20
> > +
> > +
> 
> Where is the ia-64-specific modifier to RECAIM_DISTANCE?

It was already defined as 15 in arch/ia64/include/asm/topology.h

Thanks,
Robin

^ permalink raw reply

* Re: 2.6.30-rc6: Problem with an SSD disk on Freescale PowerPC mpc8315e-rdb, works fine on x86
From: Leon Woestenberg @ 2009-06-09  9:26 UTC (permalink / raw)
  To: Linux PPC, Kumar Gala, linux-ide, Ashish Kalra, Li Yang
In-Reply-To: <c384c5ea0906080759n24a66d21ob9076518cec41755@mail.gmail.com>

Adding the sata_fsl.c developers to the recipients:

On Mon, Jun 8, 2009 at 4:59 PM, Leon
Woestenberg<leon.woestenberg@gmail.com> wrote:
> Hello,
>
> using 2.6.30-rc6, I get the following problems when I read from a SSD
> disk, connected to the
> 3.0 Gb SATA controller of the MPC8315E SoC rev 1.0 running Linux 2.6.30-r=
c6.
>
> Below see the output from two dd read runs.
>
> The disk behaves fine on a x86 box.
>
> What I can do to (help) pin-point the problem?
>
> Regards,
>
> Leon.
>
>
> root@mpc8315e-rdb:~# dd if=3D/dev/sda of=3D/dev/null bs=3D4k
> ata2: exception Emask 0x10 SAct 0x0 SErr 0x0 action 0x2 frozen
> ata2.00: cmd c8/00:3e:1e:e0:01/00:00:00:00:00/e0 tag 0 dma 31744 in
> =A0 =A0 =A0 =A0 res 50/00:3e:e0:df:01/00:00:00:00:00/e0 Emask 0x1 (device=
 error)
> ata2.00: status: { DRDY }
> ata2: hard resetting link
> ata2: Signature Update detected @ 3528 msecs
> ata2: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
> ata2.00: configured for UDMA/133
> sd 1:0:0:0: [sda] Result: hostbyte=3D0x00 driverbyte=3D0x08
> sd 1:0:0:0: [sda] Sense Key : 0xb [current] [descriptor]
> Descriptor sense data with sense descriptors (in hex):
> =A0 =A0 =A0 =A072 0b 00 00 00 00 00 0c 00 0a 80 00 00 00 00 00
> =A0 =A0 =A0 =A000 01 df e0
> sd 1:0:0:0: [sda] ASC=3D0x0 ASCQ=3D0x0
> end_request: I/O error, dev sda, sector 122910
> __ratelimit: 52 callbacks suppressed
> Buffer I/O error on device sda, logical block 122910
> Buffer I/O error on device sda, logical block 122911
> Buffer I/O error on device sda, logical block 122912
> Buffer I/O error on device sda, logical block 122913
> Buffer I/O error on device sda, logical block 122914
> Buffer I/O error on device sda, logical block 122915
> Buffer I/O error on device sda, logical block 122916
> Buffer I/O error on device sda, logical block 122917
> Buffer I/O error on device sda, logical block 122918
> Buffer I/O error on device sda, logical block 122919
> ata2: EH complete
> dd: /dev/sda: Input/output error
>
>
> root@mpc8315e-rdb:~# dd if=3D/dev/sda of=3D/dev/null bs=3D4k
> ata2: exception Emask 0x10 SAct 0x0 SErr 0x0 action 0x2 frozen
> ata2.00: cmd c8/00:32:9a:6e:00/00:00:00:00:00/e0 tag 0 dma 25600 in
> =A0 =A0 =A0 =A0 res 50/00:3e:5c:6e:00/00:00:00:00:00/e0 Emask 0x1 (device=
 error)
> ata2.00: status: { DRDY }
> ata2: hard resetting link
> ata2: Signature Update detected @ 3528 msecs
> ata2: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
> ata2.00: configured for UDMA/133
> sd 1:0:0:0: [sda] Result: hostbyte=3D0x00 driverbyte=3D0x08
> sd 1:0:0:0: [sda] Sense Key : 0xb [current] [descriptor]
> Descriptor sense data with sense descriptors (in hex):
> =A0 =A0 =A0 =A072 0b 00 00 00 00 00 0c 00 0a 80 00 00 00 00 00
> =A0 =A0 =A0 =A000 00 6e 5c
> sd 1:0:0:0: [sda] ASC=3D0x0 ASCQ=3D0x0
> end_request: I/O error, dev sda, sector 28314
> __ratelimit: 52 callbacks suppressed
> Buffer I/O error on device sda, logical block 28314
> Buffer I/O error on device sda, logical block 28315
> Buffer I/O error on device sda, logical block 28316
> Buffer I/O error on device sda, logical block 28317
> Buffer I/O error on device sda, logical block 28318
> Buffer I/O error on device sda, logical block 28319
> Buffer I/O error on device sda, logical block 28320
> Buffer I/O error on device sda, logical block 28321
> Buffer I/O error on device sda, logical block 28322
> Buffer I/O error on device sda, logical block 28323
> ata2: EH complete
> dd: /dev/sda: Input/output error
>
>
> root@mpc8315e-rdb:~# uname -a
> Linux mpc8315e-rdb 2.6.30-rc6 #1 Mon Jun 8 15:54:00 CEST 2009 ppc unknown
>
> root@mpc8315e-rdb:~# hdparm -i /dev/sda
>
> /dev/sda:
>
> =A0Model=3DSolidata X SSD =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0, FwRev=3D0955 =A0 =A0, SerialNo=3D<...>
> =A0Config=3D{ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs }
> =A0RawCHS=3D16383/16/63, TrkSize=3D0, SectSize=3D0, ECCbytes=3D0
> =A0BuffType=3Dunknown, BuffSize=3D0kB, MaxMultSect=3D128, MultSect=3D?1?
> =A0CurCHS=3D16383/16/63, CurSects=3D16514064, LBA=3Dno
> =A0IORDY=3Dno, tPIO=3D{min:240,w/IORDY:120}
> =A0PIO modes: =A0pio0 pio3 pio4
> =A0UDMA modes: udma0 udma1 udma2 udma3 udma4 udma5
> =A0AdvancedPM=3Dyes: disabled (255) WriteCache=3Ddisabled
> =A0Drive conforms to: Unspecified: =A0ATA/ATAPI-4 ATA/ATAPI-5 ATA/ATAPI-6
> ATA/ATAPI-7
>
> =A0* signifies the current active mode
>
>
>
> --
> Leon
>



--=20
Leon

^ permalink raw reply

* Re: [BUILD FAILURE 01/04] Next June 04:PPC64 randconfig [drivers/staging/comedi/drivers.o]
From: Benjamin Herrenschmidt @ 2009-06-09  3:50 UTC (permalink / raw)
  To: subrata
  Cc: sachinp, fmhess, sfr, Greg KH, linux-kernel, Linuxppc-dev,
	Ian Abbott, linux-next, paulus, Geert.Uytterhoeven, geert,
	David Miller
In-Reply-To: <1244385405.5265.7.camel@subratamodak.linux.ibm.com>

On Sun, 2009-06-07 at 20:06 +0530, Subrata Modak wrote:
> On Sat, 2009-06-06 at 09:36 -0400, Frank Mori Hess wrote:
> > On Saturday 06 June 2009, Greg KH wrote:
> > > Frank and Ian, any thoughts about the vmap call in the
> > > comedi_buf_alloc() call?  Why is it using PAGE_KERNEL_NOCACHE, and what
> > > is the prealloc_buf buffer used for?
> > 
> > It is a circular buffer used to hold data streaming either to or from a 
> > board (for example when producing an analog output waveform).  Reads and 
> > writes to the device files read/write to the circular buffer, plus a few 
> > drivers do dma directly to/from it.  I personally don't have a problem 
> > with requiring drivers to have their own dma buffers and making them copy 
> > data between their private dma buffers and the main circular buffer.  I 
> > guess the original design wanted to support zero-copy dma.
> 
> Great to hear that. How about a patch that solves my build problem on
> PPC64(the problem seems to be existing for long) ? 

In any case, doing PAGE_KERNEL_NOCACHE for DMA memory is incorrect on
many architectures. So at this stage, there's no much option but ifdef I
suspect for now until this is fixed properly.

It does make sense to want to have some memory like that shared between
user space and DMA, though I don't know what the right approach that
works on all archs is at this stage. Worth asking the Alsa guys, I think
they have similar issues :-)

But doing double buffering might do the trick fine for now.

Cheers,
Ben.

^ permalink raw reply

* Re: sensors can't be detected on i2c-mpc
From: Grant Likely @ 2009-06-09  3:19 UTC (permalink / raw)
  To: Hide Saito; +Cc: linuxppc-dev, saito
In-Reply-To: <20090609.102054.125129248.saito@densan.co.jp>

On Mon, Jun 8, 2009 at 7:20 PM, Hide Saito<hsaito.ppc@gmail.com> wrote:
> sensors can't be detected on i2c-mpc
>
> Hi all,
>
> The sensors can't be detected on the built-in I2C interface on the Freescale's MPC processors on linux-2.6.29.
> If it is not yet fixed, I think that it is forgotten to set the following values in the class.
>
> Signed-off-by: Hideo Saito <hsaito.ppc@gmail.com>

Since i2c probing is hit and miss at best; Most MPCxxxx SPI busses get
the i2c bus topology out of the device tree file
(arch/powerpc/boot/dts/<board-name>.dts) and do not support probing.
If the i2c device you need is missing, then add a node to the .dts
file for the missing device (there are lots of examples of this in the
dts directory).

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* sensors can't be detected on i2c-mpc
From: Hide Saito @ 2009-06-09  1:20 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: saito

sensors can't be detected on i2c-mpc

Hi all,

The sensors can't be detected on the built-in I2C interface on the Freescale's MPC processors on linux-2.6.29.
If it is not yet fixed, I think that it is forgotten to set the following values in the class.

Signed-off-by: Hideo Saito <hsaito.ppc@gmail.com>
---
--- drivers/i2c/busses/i2c-mpc.c.org	2009-03-24 08:12:14.000000000 +0900
+++ drivers/i2c/busses/i2c-mpc.c	2009-06-04 08:50:34.000000000 +0900
@@ -304,16 +304,17 @@ static u32 mpc_functionality(struct i2c_
 
 static const struct i2c_algorithm mpc_algo = {
 	.master_xfer = mpc_xfer,
 	.functionality = mpc_functionality,
 };
 
 static struct i2c_adapter mpc_ops = {
 	.owner = THIS_MODULE,
+	.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
 	.name = "MPC adapter",
 	.algo = &mpc_algo,
 	.timeout = 1,
 };
 
 static int __devinit fsl_i2c_probe(struct of_device *op, const struct of_device_id *match)
 {
 	int result = 0;

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox