crypto: msm: Add support for FIPS complience

FIPS140-2 certification asks to do a Power on Known Answer tests on each
algorithm which is getting certified. This patch implements the self tests
and hardcoded test vectors.  Also, we need to verify the integrity of
kernel as soon as it boots up. This patch also adds an ioctl for
integrity test along with ioctl to query FIPS status (pass / fail) from
user land.
also, The piece of code is added for FIPS compliance DRBG under
drivers/char/hw_random
This change is already merged to KK mainline.

Change-Id: I7f3355602d5c2dfaefce0c0e4f9225fde0c5f485
Signed-off-by: Dinesh K Garg <dineshg@codeaurora.org>
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 68616b8..87938e0 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -254,6 +254,8 @@
 config HW_RANDOM_MSM
 	tristate "Qualcomm MSM Random Number Generator support"
 	depends on HW_RANDOM && ARCH_MSM
+	select CRYPTO_AES
+	select CRYPTO_ECB
 	default n
 	---help---
 	  This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c24305d..d0369fd 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -22,4 +22,4 @@
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
 obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
 obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
-obj-$(CONFIG_HW_RANDOM_MSM) += msm_rng.o
+obj-$(CONFIG_HW_RANDOM_MSM) += msm_rng.o fips_drbg.o ctr_drbg.o msm_fips_selftest.o
diff --git a/drivers/char/hw_random/ctr_drbg.c b/drivers/char/hw_random/ctr_drbg.c
new file mode 100644
index 0000000..d8da08e
--- /dev/null
+++ b/drivers/char/hw_random/ctr_drbg.c
@@ -0,0 +1,938 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <mach/msm_bus.h>
+#include <linux/qrng.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/string.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+
+#include "ctr_drbg.h"
+#include "fips_drbg.h"
+
+#define E_FAILURE 0Xffff
+#define E_SUCCESS 0
+
+#define AES128_KEY_SIZE   (16)
+#define AES128_BLOCK_SIZE (16)
+
+#define AES_TEXT_LENGTH (64)
+#define MAX_TEXT_LENGTH (2048)
+
+uint8_t df_initial_k[16] = "\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf";
+
+static void _crypto_cipher_test_complete(struct crypto_async_request *req,
+				int err)
+{
+	struct msm_ctr_tcrypt_result_s *res = NULL;
+
+	if (!req)
+		return;
+
+	res = req->data;
+	if (!res)
+		return;
+
+	if (err == -EINPROGRESS)
+		return;
+	res->err = err;
+	complete(&res->completion);
+}
+
+static int ctr_aes_init(struct ctr_drbg_ctx_s *ctx)
+{
+	int status = 0;
+
+	ctx->aes_ctx.tfm = crypto_alloc_ablkcipher("qcom-ecb(aes)", 0, 0);
+	if (IS_ERR(ctx->aes_ctx.tfm) || (NULL == ctx->aes_ctx.tfm)) {
+		pr_info("%s: qcom-ecb(aes) failed", __func__);
+		ctx->aes_ctx.tfm = crypto_alloc_ablkcipher("ecb(aes)", 0, 0);
+		pr_info("ctx->aes_ctx.tfm = %p\n", ctx->aes_ctx.tfm);
+		if (IS_ERR(ctx->aes_ctx.tfm) || (NULL == ctx->aes_ctx.tfm)) {
+			pr_err("%s: qcom-ecb(aes) failed\n", __func__);
+			status = -E_FAILURE;
+			goto out;
+		}
+	}
+
+	ctx->aes_ctx.req = ablkcipher_request_alloc(ctx->aes_ctx.tfm,
+							GFP_KERNEL);
+	if (IS_ERR(ctx->aes_ctx.req) || (NULL == ctx->aes_ctx.req)) {
+		pr_info("%s: Failed to allocate request.\n", __func__);
+		status = -E_FAILURE;
+		goto clr_tfm;
+	}
+
+	ablkcipher_request_set_callback(ctx->aes_ctx.req,
+				CRYPTO_TFM_REQ_MAY_BACKLOG,
+				_crypto_cipher_test_complete,
+				&ctx->aes_ctx.result);
+
+	memset(&ctx->aes_ctx.input, 0, sizeof(struct msm_ctr_buffer_s));
+	memset(&ctx->aes_ctx.output, 0, sizeof(struct msm_ctr_buffer_s));
+
+	/* Allocate memory. */
+	ctx->aes_ctx.input.virt_addr  = kmalloc(AES128_BLOCK_SIZE,
+						GFP_KERNEL | __GFP_DMA);
+	if (NULL == ctx->aes_ctx.input.virt_addr) {
+		pr_debug("%s: Failed to input memory.\n", __func__);
+		status = -E_FAILURE;
+		goto clr_req;
+	}
+	ctx->aes_ctx.output.virt_addr = kmalloc(AES128_BLOCK_SIZE,
+						GFP_KERNEL | __GFP_DMA);
+	if (NULL == ctx->aes_ctx.output.virt_addr) {
+		pr_debug("%s: Failed to output memory.\n", __func__);
+		status = -E_FAILURE;
+		goto clr_input;
+	}
+
+	/*--------------------------------------------------------------------
+	Set DF AES mode
+	----------------------------------------------------------------------*/
+	ctx->df_aes_ctx.tfm = crypto_alloc_ablkcipher("qcom-ecb(aes)", 0, 0);
+	if ((NULL == ctx->df_aes_ctx.tfm) || IS_ERR(ctx->df_aes_ctx.tfm)) {
+		pr_info("%s: qcom-ecb(aes) failed", __func__);
+		ctx->df_aes_ctx.tfm = crypto_alloc_ablkcipher("ecb(aes)", 0, 0);
+		if (IS_ERR(ctx->df_aes_ctx.tfm) ||
+			(NULL == ctx->df_aes_ctx.tfm)) {
+			pr_err("%s: ecb(aes) failed", __func__);
+			status = -E_FAILURE;
+			goto clr_output;
+		}
+	}
+
+	ctx->df_aes_ctx.req = ablkcipher_request_alloc(ctx->df_aes_ctx.tfm,
+							GFP_KERNEL);
+	if (IS_ERR(ctx->df_aes_ctx.req) || (NULL == ctx->df_aes_ctx.req)) {
+		pr_debug(": Failed to allocate request.\n");
+		status = -E_FAILURE;
+		goto clr_df_tfm;
+	}
+
+	ablkcipher_request_set_callback(ctx->df_aes_ctx.req,
+				CRYPTO_TFM_REQ_MAY_BACKLOG,
+				_crypto_cipher_test_complete,
+				&ctx->df_aes_ctx.result);
+
+	memset(&ctx->df_aes_ctx.input, 0, sizeof(struct msm_ctr_buffer_s));
+	memset(&ctx->df_aes_ctx.output, 0, sizeof(struct msm_ctr_buffer_s));
+
+	ctx->df_aes_ctx.input.virt_addr  = kmalloc(AES128_BLOCK_SIZE,
+						GFP_KERNEL | __GFP_DMA);
+	if (NULL == ctx->df_aes_ctx.input.virt_addr) {
+		pr_debug(": Failed to input memory.\n");
+		status = -E_FAILURE;
+		goto clr_df_req;
+	}
+
+	ctx->df_aes_ctx.output.virt_addr = kmalloc(AES128_BLOCK_SIZE,
+						GFP_KERNEL | __GFP_DMA);
+	if (NULL == ctx->df_aes_ctx.output.virt_addr) {
+		pr_debug(": Failed to output memory.\n");
+		status = -E_FAILURE;
+		goto clr_df_input;
+	}
+
+	goto out;
+
+clr_df_input:
+	if (ctx->df_aes_ctx.input.virt_addr) {
+		kzfree(ctx->df_aes_ctx.input.virt_addr);
+		ctx->df_aes_ctx.input.virt_addr = NULL;
+	}
+clr_df_req:
+	if (ctx->df_aes_ctx.req) {
+		ablkcipher_request_free(ctx->df_aes_ctx.req);
+		ctx->df_aes_ctx.req = NULL;
+	}
+clr_df_tfm:
+	if (ctx->df_aes_ctx.tfm) {
+			crypto_free_ablkcipher(ctx->df_aes_ctx.tfm);
+			ctx->df_aes_ctx.tfm = NULL;
+		}
+clr_output:
+	if (ctx->aes_ctx.output.virt_addr) {
+		kzfree(ctx->aes_ctx.output.virt_addr);
+		ctx->aes_ctx.output.virt_addr = NULL;
+	}
+clr_input:
+	if (ctx->aes_ctx.input.virt_addr) {
+		kzfree(ctx->aes_ctx.input.virt_addr);
+		ctx->aes_ctx.input.virt_addr = NULL;
+	}
+clr_req:
+	if (ctx->aes_ctx.req) {
+		ablkcipher_request_free(ctx->aes_ctx.req);
+		ctx->aes_ctx.req = NULL;
+	}
+clr_tfm:
+	if (ctx->aes_ctx.tfm) {
+		crypto_free_ablkcipher(ctx->aes_ctx.tfm);
+		ctx->aes_ctx.tfm = NULL;
+	}
+out:
+	return status;
+}
+
+/*
+ * Increments the V field in *ctx
+ */
+static void increment_V(struct ctr_drbg_ctx_s *ctx)
+{
+	unsigned sum = 1;
+	int i;
+	uint8_t *p = &ctx->seed.key_V.V[0];
+
+	/*
+	 * To make known answer tests work, this has to be done big_endian.
+	 * So we just do it by bytes.
+	 * since we are using AES-128, the key size is 16 bytes.
+	 */
+	for (i = 15; sum != 0 && i >= 0; --i) {
+		sum += p[i];
+		p[i] = (sum & 0xff);
+		sum >>= 8;
+	}
+
+	return;
+}
+
+/*
+ * The NIST update function.  It updates the key and V to new values
+ * (to prevent backtracking) and optionally stirs in data.  data may
+ * be null, otherwise *data is from 0 to 256 bits long.
+ * keysched is an optional keyschedule to use as an optimization.  It
+ * must be consistent with the key in *ctx.  No changes are made to
+ * *ctx until it is assured that there will be no failures.  Note that
+ * data_len is in bytes.  (That may not be offical NIST
+ * recommendation, but I do it anyway; they say "or equivalent" and
+ * this is equivalent enough.)
+ */
+static enum ctr_drbg_status_t
+update(struct ctr_drbg_ctx_s *ctx, const uint8_t *data, size_t data_len)
+{
+	uint8_t temp[32];
+	unsigned int i;
+	int rc;
+	struct scatterlist sg_in, sg_out;
+
+	for (i = 0; i < 2; ++i) {
+		increment_V(ctx);
+		init_completion(&ctx->aes_ctx.result.completion);
+
+		/*
+		 * Note: personalize these called routines for
+		 * specific testing.
+		 */
+		memcpy(ctx->aes_ctx.input.virt_addr,
+			ctx->seed.key_V.V,
+			CTR_DRBG_BLOCK_LEN_BYTES);
+
+		crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);
+
+		/* Encrypt some clear text! */
+
+		sg_init_one(&sg_in,
+			ctx->aes_ctx.input.virt_addr,
+			AES128_BLOCK_SIZE);
+		sg_init_one(&sg_out,
+			ctx->aes_ctx.output.virt_addr,
+			AES128_BLOCK_SIZE);
+		ablkcipher_request_set_crypt(ctx->aes_ctx.req,
+						&sg_in,
+						&sg_out,
+						CTR_DRBG_BLOCK_LEN_BYTES,
+						NULL);
+
+		rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);
+
+		switch (rc) {
+		case 0:
+			break;
+		case -EINPROGRESS:
+		case -EBUSY:
+			rc = wait_for_completion_interruptible(
+				&ctx->aes_ctx.result.completion);
+			if (!rc && !ctx->aes_ctx.result.err) {
+				INIT_COMPLETION(ctx->aes_ctx.result.completion);
+				break;
+			}
+		/* fall through */
+		default:
+			pr_debug("crypto_ablkcipher_encrypt returned");
+			pr_debug(" with %d result %d on iteration\n",
+				rc,
+				ctx->aes_ctx.result.err);
+			break;
+		}
+
+		init_completion(&ctx->aes_ctx.result.completion);
+
+		memcpy(temp + AES128_BLOCK_SIZE * i,
+			ctx->aes_ctx.output.virt_addr,
+			AES128_BLOCK_SIZE);
+	}
+
+	if (data_len > 0)
+		pr_debug("in upadte, data_len = %zu\n", data_len);
+
+	for (i = 0; i < data_len; ++i)
+		ctx->seed.as_bytes[i] = temp[i] ^ data[i];
+
+	/* now copy the rest of temp to key and V */
+	if (32 > data_len) {
+		memcpy(ctx->seed.as_bytes + data_len,
+			temp + data_len,
+			32 - data_len);
+	}
+
+	memset(temp, 0, 32);
+	return CTR_DRBG_SUCCESS;
+}
+
+/*
+ * Reseeds the CTR_DRBG instance with entropy.  entropy_len_bits must
+ * be exactly 256.
+ */
+enum ctr_drbg_status_t ctr_drbg_reseed(struct ctr_drbg_ctx_s *ctx,
+					const void     *entropy,
+					size_t         entropy_len_bits)
+{
+	enum ctr_drbg_status_t update_rv;
+	uint8_t           seed_material[32];
+	int               rc;
+
+	if (ctx == NULL || entropy == NULL)
+		return CTR_DRBG_INVALID_ARG;
+
+	update_rv = block_cipher_df(ctx,
+				(uint8_t *)entropy,
+				(entropy_len_bits / 8),
+				seed_material,
+				32
+				);
+	if (CTR_DRBG_SUCCESS != update_rv) {
+		memset(seed_material, 0, 32);
+		return CTR_DRBG_GENERAL_ERROR;
+	}
+
+	rc = crypto_ablkcipher_setkey(ctx->aes_ctx.tfm,
+				ctx->seed.key_V.key,
+				AES128_KEY_SIZE
+				);
+	if (rc) {
+		memset(seed_material, 0, 32);
+		pr_debug("set-key in Instantiate failed, returns with %d", rc);
+		return CTR_DRBG_GENERAL_ERROR;
+	}
+
+	pr_debug("ctr_drbg_reseed, to call update\n");
+	update_rv = update(ctx, (const uint8_t *)seed_material, 32);
+	pr_debug("ctr_drbg_reseed, after called update\n");
+	if (update_rv != CTR_DRBG_SUCCESS) {
+		memset(seed_material, 0, 32);
+		return update_rv;
+	}
+	ctx->reseed_counter = 1;  /* think 0 but SP 800-90 says 1 */
+
+	memset(seed_material, 0, 32);
+
+	return CTR_DRBG_SUCCESS;
+
+}
+
+/*
+ * The NIST instantiate function.  entropy_len_bits must be exactly
+ * 256.  After reseed_interval generate requests, generated requests
+ * will fail  until the CTR_DRBG instance is reseeded. As per NIST SP
+ * 800-90, an error is returned if reseed_interval > 2^48.
+ */
+
+enum ctr_drbg_status_t
+ctr_drbg_instantiate(struct ctr_drbg_ctx_s *ctx,
+			const uint8_t *entropy,
+			size_t entropy_len_bits,
+			const uint8_t *nonce,
+			size_t nonce_len_bits,
+			unsigned long long reseed_interval)
+{
+
+	enum ctr_drbg_status_t update_rv;
+	uint8_t           seed_material[32];
+	uint8_t           df_input[32];
+	int               rc;
+
+	if (ctx == NULL || entropy == NULL || nonce == NULL)
+		return CTR_DRBG_INVALID_ARG;
+	if (((nonce_len_bits / 8) + (entropy_len_bits / 8)) > 32) {
+		pr_info("\nentropy_len_bits + nonce_len_bits is too long!");
+		pr_info("\nnonce len: %zu, entropy: %zu\n",
+			nonce_len_bits, entropy_len_bits);
+		return CTR_DRBG_INVALID_ARG + 1;
+	}
+
+	if (reseed_interval > (1ULL << 48))
+		return CTR_DRBG_INVALID_ARG + 2;
+
+	ctr_aes_init(ctx);
+
+	memset(ctx->seed.as_bytes, 0, sizeof(ctx->seed.as_bytes));
+	memcpy(df_input, (uint8_t *)entropy, entropy_len_bits / 8);
+	memcpy(df_input + (entropy_len_bits / 8), nonce, nonce_len_bits / 8);
+
+	update_rv = block_cipher_df(ctx, df_input, 24, seed_material, 32);
+	memset(df_input, 0, 32);
+
+	if (CTR_DRBG_SUCCESS != update_rv) {
+		pr_debug("block_cipher_df failed, returns %d", update_rv);
+		memset(seed_material, 0, 32);
+		return CTR_DRBG_GENERAL_ERROR;
+	}
+
+	rc = crypto_ablkcipher_setkey(ctx->aes_ctx.tfm,
+				ctx->seed.key_V.key,
+				AES128_KEY_SIZE);
+	if (rc) {
+		pr_debug("crypto_ablkcipher_setkey API failed: %d", rc);
+		memset(seed_material, 0, 32);
+		return CTR_DRBG_GENERAL_ERROR;
+	}
+	update_rv = update(ctx, (const uint8_t *)seed_material, 32);
+	if (update_rv != CTR_DRBG_SUCCESS) {
+		memset(seed_material, 0, 32);
+		return update_rv;
+	}
+
+	ctx->reseed_counter = 1;  /* think 0 but SP 800-90 says 1 */
+	ctx->reseed_interval = reseed_interval;
+
+	memset(seed_material, 0, 32);
+
+	pr_debug(" return from ctr_drbg_instantiate\n");
+
+	return CTR_DRBG_SUCCESS;
+}
+
+/*
+ * Generate random bits. len_bits is specified in bits, as required by
+ * NIST SP800-90.  It fails with CTR_DRBG_NEEDS_RESEED if the number
+ * of generates since instantiation or the last reseed >= the
+ * reseed_interval supplied at instantiation.  len_bits must be a
+ * multiple of 8.  len_bits must not exceed 2^19, as per NIST SP
+ * 800-90. Optionally stirs in additional_input which is
+ * additional_input_len_bits long, and is silently rounded up to a
+ * multiple of 8.  CTR_DRBG_INVALID_ARG is returned if any pointer arg
+ * is null and the corresponding length is non-zero or if
+ * additioanl_input_len_bits > 256.
+ */
+enum ctr_drbg_status_t
+ctr_drbg_generate_w_data(struct ctr_drbg_ctx_s *ctx,
+			void   *additional_input,
+			size_t additional_input_len_bits,
+			void   *buffer,
+			size_t len_bits)
+{
+	size_t total_blocks = (len_bits + 127) / 128;
+	enum ctr_drbg_status_t update_rv;
+	int rv = 0;
+	size_t i;
+	int rc;
+	struct scatterlist sg_in, sg_out;
+
+	if (ctx == NULL)
+		return CTR_DRBG_INVALID_ARG;
+	if (buffer == NULL && len_bits > 0)
+		return CTR_DRBG_INVALID_ARG;
+	if (len_bits % 8 != 0)
+		return CTR_DRBG_INVALID_ARG;
+	if (len_bits > (1<<19))
+		return CTR_DRBG_INVALID_ARG;
+
+	if ((additional_input == NULL && additional_input_len_bits > 0) ||
+		additional_input_len_bits > CTR_DRBG_SEED_LEN_BITS)
+		return CTR_DRBG_INVALID_ARG;
+	if (ctx->reseed_counter > ctx->reseed_interval)
+		return CTR_DRBG_NEEDS_RESEED;
+
+	rc = crypto_ablkcipher_setkey(ctx->aes_ctx.tfm,
+				ctx->seed.key_V.key,
+				AES128_KEY_SIZE);
+	if (rc) {
+		pr_debug("crypto_ablkcipher_setkey API failed: %d", rc);
+		return CTR_DRBG_GENERAL_ERROR;
+	}
+	if (rv < 0)
+		return CTR_DRBG_GENERAL_ERROR;
+
+	if (!ctx->continuous_test_started) {
+		increment_V(ctx);
+		init_completion(&ctx->aes_ctx.result.completion);
+		crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);
+		memcpy(ctx->aes_ctx.input.virt_addr, ctx->seed.key_V.V, 16);
+		sg_init_one(&sg_in, ctx->aes_ctx.input.virt_addr, 16);
+		sg_init_one(&sg_out, ctx->aes_ctx.output.virt_addr, 16);
+		ablkcipher_request_set_crypt(ctx->aes_ctx.req, &sg_in, &sg_out,
+					CTR_DRBG_BLOCK_LEN_BYTES, NULL);
+		rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);
+		switch (rc) {
+		case 0:
+			break;
+		case -EINPROGRESS:
+		case -EBUSY:
+			rc = wait_for_completion_interruptible(
+				&ctx->aes_ctx.result.completion);
+			if (!rc && !ctx->aes_ctx.result.err) {
+				INIT_COMPLETION(ctx->aes_ctx.result.completion);
+				break;
+			}
+			/* fall through */
+		default:
+			pr_debug(":crypto_ablkcipher_encrypt returned with %d result %d on iteration\n",
+				rc,
+				ctx->aes_ctx.result.err);
+			break;
+		}
+		init_completion(&ctx->aes_ctx.result.completion);
+
+		memcpy(ctx->prev_drn, ctx->aes_ctx.output.virt_addr, 16);
+		ctx->continuous_test_started = 1;
+	}
+
+	/* Generate the output */
+	for (i = 0; i < total_blocks; ++i) {
+		/* Increment the counter */
+		increment_V(ctx);
+		if (((len_bits % 128) != 0) && (i == (total_blocks - 1))) {
+			/* last block and it's a fragment */
+			init_completion(&ctx->aes_ctx.result.completion);
+
+			/*
+			 * Note: personalize these called routines for
+			 * specific testing.
+			 */
+
+			crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);
+
+			/* Encrypt some clear text! */
+
+			memcpy(ctx->aes_ctx.input.virt_addr,
+				ctx->seed.key_V.V,
+				16);
+			sg_init_one(&sg_in,
+				ctx->aes_ctx.input.virt_addr,
+				16);
+			sg_init_one(&sg_out,
+				ctx->aes_ctx.output.virt_addr,
+				16);
+			ablkcipher_request_set_crypt(ctx->aes_ctx.req,
+				&sg_in,
+				&sg_out,
+				CTR_DRBG_BLOCK_LEN_BYTES,
+				NULL);
+
+			rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);
+
+			switch (rc) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				rc = wait_for_completion_interruptible(
+					&ctx->aes_ctx.result.completion);
+				if (!rc && !ctx->aes_ctx.result.err) {
+					INIT_COMPLETION(
+						ctx->aes_ctx.result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				break;
+			}
+
+			init_completion(&ctx->aes_ctx.result.completion);
+
+			if (!memcmp(ctx->prev_drn,
+					ctx->aes_ctx.output.virt_addr,
+					16))
+				return CTR_DRBG_GENERAL_ERROR;
+			else
+				memcpy(ctx->prev_drn,
+					ctx->aes_ctx.output.virt_addr,
+					16);
+			rv = 0;
+			memcpy((uint8_t *)buffer + 16*i,
+				ctx->aes_ctx.output.virt_addr,
+				(len_bits % 128)/8);
+		} else {
+			/* normal case: encrypt direct to target buffer */
+
+			init_completion(&ctx->aes_ctx.result.completion);
+
+			/*
+			 * Note: personalize these called routines for
+			 * specific testing.
+			 */
+
+			crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);
+
+			/* Encrypt some clear text! */
+
+			memcpy(ctx->aes_ctx.input.virt_addr,
+				ctx->seed.key_V.V,
+				16);
+			sg_init_one(&sg_in,
+				ctx->aes_ctx.input.virt_addr,
+				16);
+			sg_init_one(&sg_out,
+				ctx->aes_ctx.output.virt_addr,
+				16);
+			ablkcipher_request_set_crypt(ctx->aes_ctx.req,
+						&sg_in,
+						&sg_out,
+						CTR_DRBG_BLOCK_LEN_BYTES,
+						NULL);
+
+			rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);
+
+			switch (rc) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				rc = wait_for_completion_interruptible(
+					&ctx->aes_ctx.result.completion);
+				if (!rc && !ctx->aes_ctx.result.err) {
+					INIT_COMPLETION(
+					ctx->aes_ctx.result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				break;
+			}
+
+			if (!memcmp(ctx->prev_drn,
+				ctx->aes_ctx.output.virt_addr,
+				16))
+				return CTR_DRBG_GENERAL_ERROR;
+			else
+				memcpy(ctx->prev_drn,
+					ctx->aes_ctx.output.virt_addr,
+					16);
+
+			memcpy((uint8_t *)buffer + 16*i,
+				ctx->aes_ctx.output.virt_addr,
+				16);
+			rv = 0;
+		}
+	}
+
+	update_rv = update(ctx,
+			additional_input,
+			(additional_input_len_bits + 7) / 8); /* round up */
+	if (update_rv != CTR_DRBG_SUCCESS)
+		return update_rv;
+
+	ctx->reseed_counter += 1;
+
+	return CTR_DRBG_SUCCESS;
+}
+
+/*
+ * Generate random bits, but with no provided data. See notes on
+ * ctr_drbg_generate_w_data()
+ */
+enum ctr_drbg_status_t
+ctr_drbg_generate(struct ctr_drbg_ctx_s *ctx,
+		void *buffer,
+		size_t len_bits)
+
+{
+	return ctr_drbg_generate_w_data(ctx, NULL, 0, buffer, len_bits);
+}
+
+void ctr_aes_deinit(struct ctr_drbg_ctx_s *ctx)
+{
+	if (ctx->aes_ctx.req) {
+		ablkcipher_request_free(ctx->aes_ctx.req);
+		ctx->aes_ctx.req = NULL;
+	}
+	if (ctx->aes_ctx.tfm) {
+		crypto_free_ablkcipher(ctx->aes_ctx.tfm);
+		ctx->aes_ctx.tfm = NULL;
+	}
+	if (ctx->aes_ctx.input.virt_addr) {
+		kzfree(ctx->aes_ctx.input.virt_addr);
+		ctx->aes_ctx.input.virt_addr = NULL;
+	}
+	if (ctx->aes_ctx.output.virt_addr) {
+		kzfree(ctx->aes_ctx.output.virt_addr);
+		ctx->aes_ctx.output.virt_addr = NULL;
+	}
+	if (ctx->df_aes_ctx.req) {
+		ablkcipher_request_free(ctx->df_aes_ctx.req);
+		ctx->df_aes_ctx.req = NULL;
+	}
+	if (ctx->df_aes_ctx.tfm) {
+		crypto_free_ablkcipher(ctx->df_aes_ctx.tfm);
+		ctx->df_aes_ctx.tfm = NULL;
+	}
+	if (ctx->df_aes_ctx.input.virt_addr) {
+		kzfree(ctx->df_aes_ctx.input.virt_addr);
+		ctx->df_aes_ctx.input.virt_addr = NULL;
+	}
+	if (ctx->df_aes_ctx.output.virt_addr) {
+		kzfree(ctx->df_aes_ctx.output.virt_addr);
+		ctx->df_aes_ctx.output.virt_addr = NULL;
+	}
+
+}
+
+/*
+ * Zeroizes the context structure. In some future implemenation it
+ * could also free resources.  So do call it.
+ */
+void
+ctr_drbg_uninstantiate(struct ctr_drbg_ctx_s *ctx)
+{
+	ctr_aes_deinit(ctx);
+	memset(ctx, 0, sizeof(*ctx));
+}
+
+/*
+ * the derivation functions to handle biased entropy input.
+ */
+enum ctr_drbg_status_t df_bcc_func(struct ctr_drbg_ctx_s *ctx,
+		uint8_t *key,
+		uint8_t *input,
+		uint32_t input_size,
+		uint8_t *output)
+{
+	enum ctr_drbg_status_t ret_val = CTR_DRBG_SUCCESS;
+	uint8_t *p;
+	int rc;
+	int i;
+	int n;
+	struct scatterlist sg_in, sg_out;
+
+	if (0 != (input_size % CTR_DRBG_BLOCK_LEN_BYTES))
+		return CTR_DRBG_INVALID_ARG;
+
+	n = input_size / CTR_DRBG_BLOCK_LEN_BYTES;
+
+	for (i = 0; i < CTR_DRBG_BLOCK_LEN_BYTES; i++)
+		ctx->df_aes_ctx.output.virt_addr[i] = 0;
+
+	rc = crypto_ablkcipher_setkey(ctx->df_aes_ctx.tfm,
+					key,
+					AES128_KEY_SIZE);
+	if (rc) {
+		pr_debug("crypto_ablkcipher_setkey API failed: %d\n", rc);
+		return CTR_DRBG_GENERAL_ERROR;
+	}
+
+	p = input;
+	while (n > 0) {
+		for (i = 0; i < CTR_DRBG_BLOCK_LEN_BYTES; i++, p++)
+			ctx->df_aes_ctx.input.virt_addr[i] =
+				ctx->df_aes_ctx.output.virt_addr[i] ^ (*p);
+
+		init_completion(&ctx->df_aes_ctx.result.completion);
+
+		/*
+		 * Note: personalize these called routines for
+		 * specific testing.
+		 */
+
+		crypto_ablkcipher_clear_flags(ctx->df_aes_ctx.tfm, ~0);
+
+		/* Encrypt some clear text! */
+
+		sg_init_one(&sg_in, ctx->df_aes_ctx.input.virt_addr, 16);
+		sg_init_one(&sg_out, ctx->df_aes_ctx.output.virt_addr, 16);
+
+		ablkcipher_request_set_crypt(ctx->df_aes_ctx.req,
+					&sg_in,
+					&sg_out,
+					CTR_DRBG_BLOCK_LEN_BYTES,
+					NULL);
+
+		rc = crypto_ablkcipher_encrypt(ctx->df_aes_ctx.req);
+
+		switch (rc) {
+		case 0:
+			break;
+		case -EINPROGRESS:
+		case -EBUSY:
+			rc = wait_for_completion_interruptible(
+				&ctx->df_aes_ctx.result.completion);
+			if (!rc && !ctx->df_aes_ctx.result.err) {
+				INIT_COMPLETION(
+				ctx->df_aes_ctx.result.completion);
+				break;
+			}
+			/* fall through */
+		default:
+			break;
+		}
+
+		init_completion(&ctx->df_aes_ctx.result.completion);
+		n--;
+	}
+
+	for (i = 0; i < CTR_DRBG_BLOCK_LEN_BYTES; i++)
+		output[i] = ctx->df_aes_ctx.output.virt_addr[i];
+
+	return ret_val;
+}
+
+/* output_size must <= 512 bits (<= 64) */
+enum ctr_drbg_status_t
+block_cipher_df(struct ctr_drbg_ctx_s *ctx,
+		const uint8_t *input,
+		uint32_t input_size,
+		uint8_t *output,
+		uint32_t output_size)
+{
+	enum ctr_drbg_status_t ret_val = CTR_DRBG_SUCCESS;
+	uint32_t          s_len = 0;
+	uint32_t          s_pad_len = 0;
+	uint8_t           temp[32];
+	uint32_t          out_len = 0;
+	uint8_t           siv_string[64];
+	uint8_t          *p_s_string = NULL;
+	int               rc;
+	struct scatterlist sg_in, sg_out;
+
+	if (output_size > 64)
+		return CTR_DRBG_INVALID_ARG;
+
+	s_len = input_size + 9;
+
+	s_pad_len = s_len % 16;
+
+	if (0 != s_pad_len)
+		s_len += (16 - s_pad_len);
+
+	/* add the length of IV */
+	s_len += 16;
+
+	if (s_len > 64)
+		pr_debug("error! s_len is too big!!!!!!!!!!!!\n");
+
+	memset(siv_string, 0, 64);
+
+	p_s_string = siv_string + 16;
+
+	p_s_string[3] = input_size;
+	p_s_string[7] = output_size;
+	memcpy(p_s_string + 8, input, input_size);
+	p_s_string[8 + input_size] = 0x80;
+	if (0 < s_pad_len)
+		memset(p_s_string + 9 + input_size, '\0', s_pad_len);
+
+	ret_val = df_bcc_func(ctx, df_initial_k, siv_string, s_len, temp);
+
+	if (CTR_DRBG_SUCCESS != ret_val) {
+		pr_debug("df_bcc_func failed, returned %d", ret_val);
+		goto out;
+	}
+
+	siv_string[3] = 0x1;
+	ret_val = df_bcc_func(ctx, df_initial_k, siv_string, s_len, temp + 16);
+
+	if (CTR_DRBG_SUCCESS != ret_val)
+		goto out;
+
+	out_len = 0;
+	rc = crypto_ablkcipher_setkey(ctx->df_aes_ctx.tfm,
+				temp,
+				AES128_KEY_SIZE);
+	if (rc) {
+		pr_debug("crypto_ablkcipher_setkey API failed: %d", rc);
+		goto out;
+	}
+	memcpy(ctx->df_aes_ctx.input.virt_addr, temp + 16, 16);
+
+	while (out_len < output_size) {
+
+		init_completion(&ctx->df_aes_ctx.result.completion);
+
+		/*
+		 * Note: personalize these called routines for
+		 * specific testing.
+		 */
+
+		crypto_ablkcipher_clear_flags(ctx->df_aes_ctx.tfm, ~0);
+
+		/* Encrypt some clear text! */
+
+		sg_init_one(&sg_in, ctx->df_aes_ctx.input.virt_addr, 16);
+		sg_init_one(&sg_out, ctx->df_aes_ctx.output.virt_addr, 16);
+		ablkcipher_request_set_crypt(ctx->df_aes_ctx.req,
+					&sg_in,
+					&sg_out,
+					CTR_DRBG_BLOCK_LEN_BYTES,
+					NULL);
+
+		rc = crypto_ablkcipher_encrypt(ctx->df_aes_ctx.req);
+
+		switch (rc) {
+		case 0:
+			break;
+		case -EINPROGRESS:
+		case -EBUSY:
+			rc = wait_for_completion_interruptible(
+				&ctx->df_aes_ctx.result.completion);
+			if (!rc && !ctx->df_aes_ctx.result.err) {
+				INIT_COMPLETION(
+					ctx->df_aes_ctx.result.completion);
+				break;
+			}
+			/* fall through */
+		default:
+			break;
+		}
+
+
+		init_completion(&ctx->df_aes_ctx.result.completion);
+
+		memcpy(output + out_len, ctx->df_aes_ctx.output.virt_addr, 16);
+		memcpy(ctx->df_aes_ctx.input.virt_addr, output + out_len, 16);
+		out_len += 16;
+	}
+
+out:
+	memset(siv_string, 0, 64);
+	memset(temp, 0, 32);
+	return ret_val;
+}
+
diff --git a/drivers/char/hw_random/ctr_drbg.h b/drivers/char/hw_random/ctr_drbg.h
new file mode 100644
index 0000000..55a9988
--- /dev/null
+++ b/drivers/char/hw_random/ctr_drbg.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_CTR_DRBG_H__
+#define __MSM_CTR_DRBG_H__
+
+/* This is the module that is actually follows the details of NIST SP
+ * 800-90 so it can claim to use a FIPS-approved algorithm.
+ */
+
+/* Added ctr_drbg_generate_w_data which supplies
+ * additional input to the generate operation.
+ */
+
+
+#define CTR_DRBG_MAX_REQ_LEN_BITS	(1 << 19)
+#define CTR_DRBG_SEED_LEN_BITS		256
+#define CTR_DRBG_BLOCK_LEN_BITS		128
+#define CTR_DRBG_BLOCK_LEN_BYTES	(CTR_DRBG_BLOCK_LEN_BITS/8)
+#define CTR_DRBG_MAX_RESEED_INTERVAL	(1ULL << 48)
+
+#define MSM_AES128_BLOCK_SIZE   (16)
+#define MSM_ENTROPY_BUFFER_SIZE (16)
+#define MSM_NONCE_BUFFER_SIZE   (8)
+
+enum ctr_drbg_status_t {
+	CTR_DRBG_SUCCESS = 0,
+	CTR_DRBG_NEEDS_RESEED,
+	CTR_DRBG_INVALID_ARG,
+	CTR_DRBG_GENERAL_ERROR = 0xFF,
+};
+
+union ctr_drbg_seed_t {
+	uint8_t as_bytes[32];
+	uint32_t as_words[8];
+	uint64_t as_64[4];
+	struct {
+		uint8_t key[16];
+		uint8_t V[16];
+	} key_V;
+};
+
+struct msm_ctr_tcrypt_result_s {
+	struct completion completion;
+	int err;
+};
+
+struct msm_ctr_buffer_s {
+	unsigned char *virt_addr;
+};
+
+struct aes_struct_s {
+	struct crypto_ablkcipher	*tfm;
+	struct ablkcipher_request	*req;
+	struct msm_ctr_buffer_s		input;
+	struct msm_ctr_buffer_s		output;
+	struct msm_ctr_tcrypt_result_s	result;
+};
+
+struct ctr_drbg_ctx_s {
+	unsigned long long reseed_counter;  /* starts at 1 as per SP
+					     * 800-90
+					     */
+	unsigned long long	reseed_interval;
+	union ctr_drbg_seed_t	seed;
+	struct aes_struct_s	aes_ctx;
+	struct aes_struct_s	df_aes_ctx;
+	uint8_t			prev_drn[MSM_AES128_BLOCK_SIZE];
+	uint8_t			continuous_test_started;
+};
+
+enum ctr_drbg_status_t ctr_drbg_instantiate(struct ctr_drbg_ctx_s *ctx,
+					const uint8_t *entropy,
+					size_t entropy_len_bits,
+					const uint8_t *nonce,
+					size_t nonce_len_bits,
+					unsigned long long reseed_interval);
+
+enum ctr_drbg_status_t ctr_drbg_reseed(struct ctr_drbg_ctx_s *ctx,
+				const void *entropy,
+				size_t entropy_len);
+
+enum ctr_drbg_status_t ctr_drbg_generate_w_data(struct ctr_drbg_ctx_s *ctx,
+			void *additional_input,
+			size_t additional_input_len_bits,
+			void *buffer,
+			size_t len_bits);
+
+enum ctr_drbg_status_t ctr_drbg_generate(struct ctr_drbg_ctx_s *ctx,
+				void *buffer,
+				size_t len);
+
+void ctr_drbg_uninstantiate(struct ctr_drbg_ctx_s *ctx);
+
+enum ctr_drbg_status_t block_cipher_df(struct ctr_drbg_ctx_s *ctx,
+				const uint8_t *input,
+				uint32_t input_size,
+				uint8_t *output,
+				uint32_t output_size
+				);
+void ctr_aes_deinit(struct ctr_drbg_ctx_s *ctx);
+
+#endif /* __MSM_CTR_DRBG_H__ */
diff --git a/drivers/char/hw_random/fips_drbg.c b/drivers/char/hw_random/fips_drbg.c
new file mode 100644
index 0000000..7b4225e
--- /dev/null
+++ b/drivers/char/hw_random/fips_drbg.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <mach/msm_bus.h>
+#include <linux/qrng.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/string.h>
+
+#include "msm_rng.h"
+#include "fips_drbg.h"
+
+/* The fips-140 random number generator is a wrapper around the CTR_DRBG
+ * random number generator, which is built according to the
+ * specifications in NIST SP 800-90 using AES-128.
+ *
+ * This wrapper has the following functionality
+ * a. Entropy collection is via a callback.
+ * b. A failure of CTR_DRBG because reseeding is needed invisibly
+ *    causes the underlying CTR_DRBG instance to be reseeded with
+ *    new random data and then the generate request is retried.
+ * c. Limitations in CTR_DRBG (like not allowed more than 65536 bytes
+ *    to be genrated in one request) are worked around.  At this level
+ *    it just works.
+ * d. On success the return value is zero.  If the callback was invoked
+ *    and returned a non-zero value, that value is returned.  On all other
+ *    errors -1 is returned.
+ */
+
+#ifndef NULL
+  #define NULL  0
+#endif
+
+/*  32 bytes = 256 bits = seed length */
+#define MAGIC 0xab10d161
+
+#define RESEED_INTERVAL (1 << 31)
+
+int get_entropy_callback(void *ctx, void *buf)
+{
+	struct msm_rng_device *msm_rng_dev = (struct msm_rng_device *)ctx;
+	int ret_val = -1;
+
+	if (NULL == ctx)
+		return FIPS140_PRNG_ERR;
+
+	if (NULL == buf)
+		return FIPS140_PRNG_ERR;
+
+	ret_val = msm_rng_direct_read(msm_rng_dev, buf);
+	if ((size_t)ret_val != Q_HW_DRBG_BLOCK_BYTES)
+		return ret_val;
+
+	return 0;
+}
+
+/* Initialize *ctx. Automatically reseed after reseed_interval calls
+ * to fips_drbg_gen.  The underlying CTR_DRBG will automatically be
+ * reseeded every reseed_interval requests.  Values over
+ * CTR_DRBG_MAX_RESEED_INTERVAL (2^48) or that are zero are silently
+ * converted to CTR_DRBG_MAX_RESEED_INTERVAL.  (It is easy to justify
+ * lowering values that are too large to CTR_DRBG_MAX_RESEED_INTERVAL
+ * (the NIST SP800-90 limit): just silently enforcing the rules.
+ * Silently converted 0 to to CTR_DRBG_MAX_RESEED_INTERVAL is harder.
+ * The alternative is to return an error.  But since
+ * CTR_DRBG_MAX_RESEED is safe, we relieve the caller of one more
+ * error to worry about.)
+ */
+static int
+do_fips_drbg_init(struct fips_drbg_ctx_s *ctx,
+	      get_entropy_callback_t callback,
+	      void *callback_ctx,
+	      unsigned long long reseed_interval)
+{
+	uint8_t entropy_pool[Q_HW_DRBG_BLOCK_BYTES];
+	enum ctr_drbg_status_t init_rv;
+	int rv = -1;
+
+	if (ctx == NULL)
+		return FIPS140_PRNG_ERR;
+	if (callback == NULL)
+		return FIPS140_PRNG_ERR;
+	if (reseed_interval == 0 ||
+		reseed_interval > CTR_DRBG_MAX_RESEED_INTERVAL)
+		reseed_interval = CTR_DRBG_MAX_RESEED_INTERVAL;
+
+	/* fill in callback related fields in ctx */
+	ctx->get_entropy_callback = callback;
+	ctx->get_entropy_callback_ctx = callback_ctx;
+
+	if (!ctx->fips_drbg_started) {
+		rv = (*ctx->get_entropy_callback)(ctx->get_entropy_callback_ctx,
+			ctx->prev_hw_drbg_block
+			);
+		if (rv != 0)
+			return FIPS140_PRNG_ERR;
+		ctx->fips_drbg_started = 1;
+	}
+
+	rv = (*ctx->get_entropy_callback)(ctx->get_entropy_callback_ctx,
+		entropy_pool
+		);
+	if (rv != 0) {
+		memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES);
+		return FIPS140_PRNG_ERR;
+	}
+
+	if (!memcmp(entropy_pool,
+			ctx->prev_hw_drbg_block,
+			Q_HW_DRBG_BLOCK_BYTES)) {
+		memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES);
+		return FIPS140_PRNG_ERR;
+	} else
+		memcpy(ctx->prev_hw_drbg_block,
+			entropy_pool,
+			Q_HW_DRBG_BLOCK_BYTES);
+
+
+	init_rv = ctr_drbg_instantiate(&ctx->ctr_drbg_ctx,
+		entropy_pool,
+		8 * MSM_ENTROPY_BUFFER_SIZE,
+		entropy_pool + MSM_ENTROPY_BUFFER_SIZE,
+		8 * 8,
+		reseed_interval);
+
+	memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES);
+
+	if (init_rv == 0)
+		ctx->magic = MAGIC;
+
+	return 0;
+}
+
+int fips_drbg_init(struct msm_rng_device *msm_rng_ctx)
+{
+	uint32_t ret_val = 0;
+
+	ret_val = do_fips_drbg_init(msm_rng_ctx->drbg_ctx,
+			get_entropy_callback,
+			msm_rng_ctx,
+			RESEED_INTERVAL
+			);
+	if (ret_val != 0)
+		ret_val = FIPS140_PRNG_ERR;
+
+	return ret_val;
+}
+
+/* Push new entropy into the CTR_DRBG instance in ctx, combining
+ * it with the entropy already there.  On success, 0 is returned.  If
+ * the callback returns a non-zero value, that value is returned.
+ * Other errors return -1.
+ */
+static int
+fips_drbg_reseed(struct fips_drbg_ctx_s *ctx)
+{
+	uint8_t entropy_pool[Q_HW_DRBG_BLOCK_BYTES];
+	int rv;
+	enum ctr_drbg_status_t init_rv;
+
+	if (ctx == NULL)
+		return FIPS140_PRNG_ERR;
+
+	if (!ctx->fips_drbg_started) {
+		rv = (*ctx->get_entropy_callback)(ctx->get_entropy_callback_ctx,
+			ctx->prev_hw_drbg_block
+			);
+		if (rv != 0)
+			return FIPS140_PRNG_ERR;
+		ctx->fips_drbg_started = 1;
+	}
+
+	rv = (*ctx->get_entropy_callback)(ctx->get_entropy_callback_ctx,
+		entropy_pool
+		);
+	if (rv != 0) {
+		memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES);
+		return FIPS140_PRNG_ERR;
+	}
+
+	if (!memcmp(entropy_pool,
+		    ctx->prev_hw_drbg_block,
+		    Q_HW_DRBG_BLOCK_BYTES)) {
+		memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES);
+		return FIPS140_PRNG_ERR;
+	} else
+		memcpy(ctx->prev_hw_drbg_block,
+		       entropy_pool,
+		       Q_HW_DRBG_BLOCK_BYTES);
+
+	init_rv = ctr_drbg_reseed(&ctx->ctr_drbg_ctx,
+				  entropy_pool,
+				  8 * MSM_ENTROPY_BUFFER_SIZE);
+
+	/* Zeroize the buffer for security. */
+	memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES);
+
+	return (init_rv == CTR_DRBG_SUCCESS ?
+				FIPS140_PRNG_OK :
+				FIPS140_PRNG_ERR);
+}
+
+/* generate random bytes.  len is in bytes On success returns 0.  If
+ * the callback returns a non-zero value, that is returned.  Other
+ * errors return -1. */
+int
+fips_drbg_gen(struct fips_drbg_ctx_s *ctx, void *tgt, size_t len)
+{
+
+	/* The contorted flow in this function is so that the CTR_DRBG
+	stuff can follow NIST SP 800-90, which has the generate function
+	fail and return a special code if a reseed is needed. We also work
+	around the CTR_DRBG limitation of the maximum request sized being
+	2^19 bits. */
+
+	enum ctr_drbg_status_t gen_rv;
+	int rv;
+
+	if (ctx == NULL || ctx->magic != MAGIC)
+		return FIPS140_PRNG_ERR;
+	if (tgt == NULL && len > 0)
+		return FIPS140_PRNG_ERR;
+	while (len > 0) {
+		size_t req_len;
+
+		if (len < (CTR_DRBG_MAX_REQ_LEN_BITS / 8))
+			req_len = len;
+		else
+			req_len = CTR_DRBG_MAX_REQ_LEN_BITS / 8;
+
+		gen_rv = ctr_drbg_generate(&ctx->ctr_drbg_ctx,
+					   tgt,
+					   8*req_len);
+		switch (gen_rv) {
+		case CTR_DRBG_SUCCESS:
+			tgt = (uint8_t *)tgt + req_len;
+			len -= req_len;
+			break;
+		case CTR_DRBG_NEEDS_RESEED:
+			rv = fips_drbg_reseed(ctx);
+			if (rv != 0)
+				return rv;
+			break;
+		default:
+			return FIPS140_PRNG_ERR;
+		}
+	}
+
+	return 0;
+}
+
+/* free resources and zeroize state */
+void
+fips_drbg_final(struct fips_drbg_ctx_s *ctx)
+{
+	ctr_drbg_uninstantiate(&ctx->ctr_drbg_ctx);
+	ctx->get_entropy_callback     = 0;
+	ctx->get_entropy_callback_ctx = 0;
+	ctx->fips_drbg_started        = 0;
+	memset(ctx->prev_hw_drbg_block, 0, Q_HW_DRBG_BLOCK_BYTES);
+	ctx->magic = 0;
+}
+
diff --git a/drivers/char/hw_random/fips_drbg.h b/drivers/char/hw_random/fips_drbg.h
new file mode 100644
index 0000000..06da362
--- /dev/null
+++ b/drivers/char/hw_random/fips_drbg.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_FIPS_DRBG_H__
+#define __MSM_FIPS_DRBG_H__
+
+#include "ctr_drbg.h"
+#include "msm_rng.h"
+
+#define FIPS140_PRNG_OK  (0)
+#define FIPS140_PRNG_ERR (-1)
+
+typedef int (*get_entropy_callback_t)(void *ctx, void *buf);
+
+struct fips_drbg_ctx_s {
+	uint32_t magic;		/* for checking that ctx is likely valid */
+	get_entropy_callback_t get_entropy_callback;
+	void *get_entropy_callback_ctx;
+	struct ctr_drbg_ctx_s ctr_drbg_ctx;
+	uint8_t fips_drbg_started;
+	uint8_t prev_hw_drbg_block[Q_HW_DRBG_BLOCK_BYTES];
+};
+
+/*
+ * initialize *ctx, requesting automatic reseed after reseed_interval
+ * calls to qpsi_rng_gen.  callback is a function to get entropy.
+ * callback_ctx is a pointer to any context structure that function
+ * may need.  (Pass NULL if no context structure is needed.) callback
+ * must return zero or a positive number on success, and a
+ * negative number on an error.
+ */
+int fips_drbg_init(struct msm_rng_device *msm_rng_ctx);
+
+/* generated random data.  Returns 0 on success, -1 on failures */
+int fips_drbg_gen(struct fips_drbg_ctx_s *ctx, void *tgt, size_t len);
+
+
+/* free resources and zeroize state */
+/* Failure to call fips_drbg_final is not a security issue, since
+   CTR_DRBG provides backtracking resistance by updating Key and V
+   immediately after the data has been generated but before the
+   generate function returns.  But it is a resource issue (except at
+   program termination), as it abandons a FILE structure and a file
+   descriptor. */
+void fips_drbg_final(struct fips_drbg_ctx_s *ctx);
+
+#endif /* __MSM_FIPS_DRBG_H__ */
diff --git a/drivers/char/hw_random/msm_fips_selftest.c b/drivers/char/hw_random/msm_fips_selftest.c
new file mode 100644
index 0000000..3c23605
--- /dev/null
+++ b/drivers/char/hw_random/msm_fips_selftest.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "fips_drbg.h"
+#include "ctr_drbg.h"
+#include "msm_rng.h"
+#include "msm_fips_selftest.h"
+
+#define CTRAES128_ENTROPY_BYTES       (16)
+#define CTRAES128_NONCE_BYTES         (8)
+#define CTRAES128_MAX_OUTPUT_BYTES    (64)
+
+struct ctr_drbg_testcase_s {
+	char *name;
+	char *entropy_string;
+	char *nonce_string;
+	char *reseed_entropy_string;
+	char *expected_string;
+};
+
+static struct ctr_drbg_testcase_s t0 = {
+	.name = "use_pr_0",
+	.entropy_string = "\x8f\xb9\x57\x3a\x54\x62\x53\xcd"
+			  "\xbf\x62\x15\xa1\x80\x5a\x41\x38",
+	.nonce_string   = "\x7c\x2c\xe6\x54\x02\xbc\xa6\x83",
+	.reseed_entropy_string = "\xbc\x5a\xd8\x9a\xe1\x8c\x49\x1f"
+				 "\x90\xa2\xae\x9e\x7e\x2c\xf9\x9d",
+	.expected_string = "\x07\x62\x82\xe8\x0e\x65\xd7\x70"
+			   "\x1a\x35\xb3\x44\x63\x68\xb6\x16"
+			   "\xf8\xd9\x62\x23\xb9\xb5\x11\x64"
+			   "\x23\xa3\xa2\x32\xc7\x2c\xea\xbf"
+			   "\x4a\xcc\xc4\x0a\xc6\x19\xd6\xaa"
+			   "\x68\xae\xdb\x8b\x26\x70\xb8\x07"
+			   "\xcc\xe9\x9f\xc2\x1b\x8f\xa5\x16"
+			   "\xef\x75\xb6\x8f\xc0\x6c\x87\xc7",
+};
+
+static struct ctr_drbg_testcase_s t1 = {
+	.name = "use_pr_1",
+	.entropy_string = "\xa3\x56\xf3\x9a\xce\x48\x59\xb1"
+			  "\xe1\x99\x49\x40\x22\x8e\xa4\xeb",
+	.nonce_string   = "\xff\x33\xe9\x51\x39\xf7\x67\xf1",
+	.reseed_entropy_string = "\x66\x8f\x0f\xe2\xd8\xa9\xa9\x29"
+				 "\x20\xfc\xb9\xf3\x55\xd6\xc3\x4c",
+	.expected_string = "\xa1\x06\x61\x65\x7b\x98\x0f\xac"
+			   "\xce\x77\x91\xde\x7f\x6f\xe6\x1e"
+			   "\x88\x15\xe5\xe2\x4c\xce\xb8\xa6"
+			   "\x63\xf2\xe8\x2f\x5b\xfb\x16\x92"
+			   "\x06\x2a\xf3\xa8\x59\x05\xe0\x5a"
+			   "\x92\x9a\x07\x65\xc7\x41\x29\x3a"
+			   "\x4b\x1d\x15\x3e\x02\x14\x7b\xdd"
+			   "\x74\x5e\xbd\x70\x07\x4d\x6c\x08",
+};
+
+static struct ctr_drbg_testcase_s *testlist[] = {
+	&t0, &t1
+};
+
+static int allzeroP(void *p, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; ++i)
+		if (((uint8_t *)p)[i] != 0)
+			return 0;
+
+	return 1;
+}
+
+/*
+ * basic test.  return value is error count.
+ */
+int fips_ctraes128_df_known_answer_test(struct ctr_debg_test_inputs_s *tcase)
+{
+	struct ctr_drbg_ctx_s ctx;
+	enum ctr_drbg_status_t rv;
+
+	if (tcase->observed_string_len > CTRAES128_MAX_OUTPUT_BYTES) {
+		pr_debug("known answer test output is bigger than 64!\n");
+		return 1;
+	}
+
+	memset(&ctx, 0, sizeof(ctx));
+
+	ctx.continuous_test_started = 1;
+
+	rv = ctr_drbg_instantiate(&ctx,
+				  tcase->entropy_string,
+				  8 * CTRAES128_ENTROPY_BYTES,
+				  tcase->nonce_string,
+				  8 * CTRAES128_NONCE_BYTES,
+				  1<<19);
+	if (rv != CTR_DRBG_SUCCESS) {
+		pr_err("test instantiate failed with code %d\n", rv);
+		return 1;
+	}
+
+	rv = ctr_drbg_reseed(&ctx,
+			     tcase->reseed_entropy_string,
+			     8 * CTRAES128_ENTROPY_BYTES);
+	if (rv != CTR_DRBG_SUCCESS) {
+		pr_err("test reseed failed with code %d\n", rv);
+		return 1;
+	}
+
+	rv = ctr_drbg_generate(&ctx,
+			       tcase->observed_string,
+			       tcase->observed_string_len * 8);
+	if (rv != CTR_DRBG_SUCCESS) {
+		pr_err("test generate (2) failed with code %d\n", rv);
+		return 1;
+	}
+
+	rv = ctr_drbg_generate(&ctx,
+			       tcase->observed_string,
+			       tcase->observed_string_len * 8);
+	if (rv != CTR_DRBG_SUCCESS) {
+		pr_err("test generate (2) failed with code %d\n", rv);
+		return 1;
+	}
+
+	ctr_drbg_uninstantiate(&ctx);
+
+	if (!allzeroP(&ctx.seed, sizeof(ctx.seed))) {
+		pr_err("test Final failed to zeroize the context\n");
+		return 1;
+	}
+
+	pr_info("\n DRBG counter test done");
+	return 0;
+
+}
+
+static int fips_drbg_healthcheck_sanitytest(void)
+{
+	struct ctr_drbg_ctx_s *p_ctx = NULL;
+	enum ctr_drbg_status_t rv = CTR_DRBG_SUCCESS;
+	char entropy_string[MSM_ENTROPY_BUFFER_SIZE];
+	char nonce[MSM_NONCE_BUFFER_SIZE];
+	char buffer[32];
+
+	pr_info("start DRBG health check sanity test.\n");
+	p_ctx = kzalloc(sizeof(struct ctr_drbg_ctx_s), GFP_KERNEL);
+	if (NULL == p_ctx) {
+		rv = CTR_DRBG_GENERAL_ERROR;
+		pr_err("p_ctx kzalloc fail\n");
+		goto outbuf;
+	}
+
+	/*
+	 * test DRGB Instantiaion function error handling.
+	 * Sends a NULL pointer as DTR-DRBG context.
+	 */
+	rv = ctr_drbg_instantiate(NULL,
+				  entropy_string,
+				  8 * CTRAES128_ENTROPY_BYTES,
+				  nonce,
+				  8 * CTRAES128_NONCE_BYTES,
+				  1<<19);
+	if (CTR_DRBG_SUCCESS == rv) {
+		rv = CTR_DRBG_INVALID_ARG;
+		pr_err("failed to handle NULL pointer of CTR context\n");
+		goto outbuf;
+	}
+
+	/*
+	 * test DRGB Instantiaion function error handling.
+	 * Sends a NULL pointer as entropy input.
+	 */
+	rv = ctr_drbg_instantiate(p_ctx,
+				  NULL,
+				  8 * CTRAES128_ENTROPY_BYTES,
+				  nonce,
+				  8 * CTRAES128_NONCE_BYTES,
+				  1<<19);
+	if (CTR_DRBG_SUCCESS == rv) {
+		rv = CTR_DRBG_INVALID_ARG;
+		pr_err("failed to handle NULL pointer of entropy string\n");
+		goto outbuf;
+	}
+
+	rv = ctr_drbg_instantiate(p_ctx,
+				  entropy_string,
+				  8 * CTRAES128_ENTROPY_BYTES,
+				  NULL,
+				  8 * CTRAES128_NONCE_BYTES,
+				  1<<19);
+	if (CTR_DRBG_SUCCESS == rv) {
+		rv = CTR_DRBG_INVALID_ARG;
+		pr_err("failed to handle NULL pointer of nonce string\n");
+		goto outbuf;
+	}
+
+	/*
+	 * test DRGB Instantiaion function error handling.
+	 * Sends very long seed length.
+	 */
+	rv = ctr_drbg_instantiate(p_ctx,
+				  entropy_string,
+				  8 * CTRAES128_ENTROPY_BYTES,
+				  nonce,
+				  32 * CTRAES128_NONCE_BYTES,
+				  1<<19);
+	if (CTR_DRBG_SUCCESS == rv) {
+		rv = CTR_DRBG_INVALID_ARG;
+		pr_err("failed to handle incorrect seed size\n");
+		goto outbuf;
+	}
+
+
+	rv = ctr_drbg_instantiate(p_ctx,
+				  entropy_string,
+				  8 * CTRAES128_ENTROPY_BYTES,
+				  nonce,
+				  8 * CTRAES128_NONCE_BYTES,
+				  1<<19);
+	if (CTR_DRBG_SUCCESS != rv) {
+		pr_err("Instantiation failed to handle CTR-DRBG instance\n");
+		goto outbuf;
+	}
+
+	/*
+	 * test DRGB generator function error handling.
+	 * set output string as NULL.
+	 */
+	rv = ctr_drbg_generate(p_ctx, NULL, 256);
+	if (CTR_DRBG_SUCCESS == rv) {
+		pr_err("failed to handle incorrect buffer pointer\n");
+		rv = CTR_DRBG_INVALID_ARG;
+		goto outdrbg;
+	}
+
+	rv = ctr_drbg_generate(p_ctx, &buffer,  1 << 20);
+	if (CTR_DRBG_SUCCESS == rv) {
+		pr_err("failed to handle too long output length\n");
+		rv = CTR_DRBG_INVALID_ARG;
+		goto outdrbg;
+	}
+
+	rv = ctr_drbg_generate(p_ctx, &buffer,  177);
+	if (CTR_DRBG_SUCCESS == rv) {
+		pr_err("failed to handle incorrect output length\n");
+		rv = CTR_DRBG_INVALID_ARG;
+		goto outdrbg;
+	}
+
+	pr_info("DRBG health check sanity test passed.\n");
+	rv = CTR_DRBG_SUCCESS;
+
+outdrbg:
+	ctr_drbg_uninstantiate(p_ctx);
+
+outbuf:
+	if (p_ctx)
+		kzfree(p_ctx);
+	p_ctx = NULL;
+
+	memset(buffer, 0, 32);
+	memset(nonce, 0, MSM_NONCE_BUFFER_SIZE);
+	memset(entropy_string, 0, MSM_ENTROPY_BUFFER_SIZE);
+
+	return rv;
+}
+
+int fips_self_test(void)
+{
+	struct ctr_debg_test_inputs_s cavs_input;
+	uint8_t entropy[CTRAES128_ENTROPY_BYTES];
+	uint8_t nonce[CTRAES128_NONCE_BYTES];
+	uint8_t reseed_entropy[CTRAES128_ENTROPY_BYTES];
+	uint8_t expected[CTRAES128_MAX_OUTPUT_BYTES];
+	uint8_t observed[CTRAES128_MAX_OUTPUT_BYTES];
+	unsigned int i;
+	int errors = 0;
+	int ret;
+
+	cavs_input.entropy_string = entropy;
+	cavs_input.nonce_string = nonce;
+	cavs_input.reseed_entropy_string = reseed_entropy;
+	cavs_input.observed_string = observed;
+	cavs_input.observed_string_len = CTRAES128_MAX_OUTPUT_BYTES;
+
+
+	ret = fips_drbg_healthcheck_sanitytest();
+	if (CTR_DRBG_SUCCESS != ret) {
+		pr_err("DRBG health check fail\n");
+		errors++;
+		return errors;
+	}
+
+	for (i = 0;
+	     i < sizeof(testlist)/sizeof(struct ctr_drbg_testcase_s *);
+	     ++i) {
+		memcpy(entropy,
+			testlist[i]->entropy_string,
+			CTRAES128_ENTROPY_BYTES);
+		memcpy(nonce,
+			testlist[i]->nonce_string,
+			CTRAES128_NONCE_BYTES);
+		memcpy(reseed_entropy,
+			testlist[i]->reseed_entropy_string,
+			CTRAES128_ENTROPY_BYTES);
+		memcpy(expected,
+			testlist[i]->expected_string,
+			CTRAES128_MAX_OUTPUT_BYTES);
+
+		pr_debug("starting test %s\n", testlist[i]->name);
+		ret = fips_ctraes128_df_known_answer_test(&cavs_input);
+		pr_debug("completed test %s\n\n", testlist[i]->name);
+		if (0 != ret) {
+			pr_debug("got error from drbg known answer test!\n");
+			return 1;
+		}
+
+		if (memcmp(expected,
+			cavs_input.observed_string,
+			CTRAES128_MAX_OUTPUT_BYTES) != 0) {
+			errors++;
+			pr_info("%s: generate failed\n", testlist[i]->name);
+			return 1;
+		} else
+			pr_info("%s: generate PASSED!\n", testlist[i]->name);
+	}
+
+	if (errors == 0)
+		pr_debug("All tests passed\n");
+	else
+		pr_debug("%d tests failed\n", errors);
+
+	return errors;
+
+}
+
diff --git a/drivers/char/hw_random/msm_fips_selftest.h b/drivers/char/hw_random/msm_fips_selftest.h
new file mode 100644
index 0000000..090ae01
--- /dev/null
+++ b/drivers/char/hw_random/msm_fips_selftest.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_FIPS_SELFTEST_H__
+#define __MSM_FIPS_SELFTEST_H__
+
+struct ctr_debg_test_inputs_s {
+	char *entropy_string;		/* must by 16 bytes */
+	char *nonce_string;		/* must be 8 bytes */
+	char *reseed_entropy_string;	/* must be 16 bytes */
+	char *observed_string;		/* lenth is defined
+						in observed_string_len */
+	int  observed_string_len;
+};
+
+int fips_ctraes128_df_known_answer_test(struct ctr_debg_test_inputs_s *tcase);
+
+int fips_self_test(void);
+
+#endif  /* __MSM_FIPS_SELFTEST_H__ */
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index 4118a7a..e7b9a27 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,13 @@
 #include <linux/fs.h>
 #include <linux/cdev.h>
 
+#include <linux/platform_data/qcom_crypto_device.h>
+
+#include "msm_rng.h"
+#include "ctr_drbg.h"
+#include "fips_drbg.h"
+#include "msm_fips_selftest.h"
+
 #define DRIVER_NAME "msm_rng"
 
 /* Device specific register offsets */
@@ -46,16 +53,34 @@
 #define MAX_HW_FIFO_DEPTH 16                     /* FIFO is 16 words deep */
 #define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4) /* FIFO is 32 bits wide  */
 
+/* Global FIPS status  */
+#ifdef CONFIG_FIPS_ENABLE
+enum fips_status g_fips140_status = FIPS140_STATUS_FAIL;
+EXPORT_SYMBOL(g_fips140_status);
 
-struct msm_rng_device {
-	struct platform_device *pdev;
-	void __iomem *base;
-	struct clk *prng_clk;
-	uint32_t qrng_perf_client;
+#else
+enum fips_status g_fips140_status = FIPS140_STATUS_NA;
+EXPORT_SYMBOL(g_fips140_status);
+
+#endif
+
+/*FIPS140-2 call back for DRBG self test */
+void *drbg_call_back;
+EXPORT_SYMBOL(drbg_call_back);
+
+
+
+enum {
+	FIPS_NOT_STARTED = 0,
+	DRBG_FIPS_STARTED
 };
 
 struct msm_rng_device msm_rng_device_info;
 
+#ifdef CONFIG_FIPS_ENABLE
+static int fips_mode_enabled = FIPS_NOT_STARTED;
+#endif
+
 static long msm_rng_ioctl(struct file *filp, unsigned int cmd,
 				unsigned long arg)
 {
@@ -77,28 +102,24 @@
 	return ret;
 }
 
-static int msm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+/*
+ *
+ *  This function calls hardware random bit generator directory and retuns it
+ *  back to caller
+ *
+ */
+int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, void *data)
 {
-	struct msm_rng_device *msm_rng_dev;
 	struct platform_device *pdev;
 	void __iomem *base;
-	size_t maxsize;
 	size_t currsize = 0;
 	unsigned long val;
 	unsigned long *retdata = data;
 	int ret;
 
-	msm_rng_dev = (struct msm_rng_device *)rng->priv;
 	pdev = msm_rng_dev->pdev;
 	base = msm_rng_dev->base;
 
-	/* calculate max size bytes to transfer back to caller */
-	maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max);
-
-	/* no room for word data */
-	if (maxsize < 4)
-		return 0;
-
 	/* enable PRNG clock */
 	ret = clk_prepare_enable(msm_rng_dev->prng_clk);
 	if (ret) {
@@ -120,6 +141,74 @@
 		*(retdata++) = val;
 		currsize += 4;
 
+	} while (currsize < Q_HW_DRBG_BLOCK_BYTES);
+
+	/* vote to turn off clock */
+	clk_disable_unprepare(msm_rng_dev->prng_clk);
+
+	val = 0L;
+	return currsize;
+
+}
+
+static int msm_rng_drbg_read(struct hwrng *rng,
+			void *data, size_t max, bool wait)
+{
+	struct msm_rng_device *msm_rng_dev;
+	struct platform_device *pdev;
+	void __iomem *base;
+	size_t maxsize;
+	size_t currsize = 0;
+	unsigned long val;
+	unsigned long *retdata = data;
+	int ret, ret1;
+
+	msm_rng_dev = (struct msm_rng_device *)rng->priv;
+	pdev = msm_rng_dev->pdev;
+	base = msm_rng_dev->base;
+
+
+	down(&msm_rng_dev->drbg_sem);
+
+	/* calculate max size bytes to transfer back to caller */
+	maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max);
+
+	/* no room for word data */
+	if (maxsize < 4)
+		return 0;
+
+	/* read random data from CTR-AES based DRBG */
+	if (FIPS140_DRBG_ENABLED == msm_rng_dev->fips140_drbg_enabled) {
+		ret1 = fips_drbg_gen(msm_rng_dev->drbg_ctx, data, maxsize);
+		if (FIPS140_PRNG_ERR == ret1)
+			panic("random number generator generator error.\n");
+	} else
+		ret1 = 1;
+
+	/* read random data from h/w */
+	/* enable PRNG clock */
+	ret = clk_prepare_enable(msm_rng_dev->prng_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable clock in callback\n");
+		up(&msm_rng_dev->drbg_sem);
+		return 0;
+	}
+	/* read random data from h/w */
+	do {
+		/* check status bit if data is available */
+		if (!(readl_relaxed(base + PRNG_STATUS_OFFSET) & 0x00000001))
+			break;	/* no data to read so just bail */
+
+		/* read FIFO */
+		val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
+		if (!val)
+			break;	/* no data to read so just bail */
+
+		/* write data back to callers pointer */
+		if (0 != ret1)
+			*(retdata++) = val;
+		currsize += 4;
+
 		/* make sure we stay on 32bit boundary */
 		if ((maxsize - currsize) < 4)
 			break;
@@ -127,9 +216,112 @@
 	/* vote to turn off clock */
 	clk_disable_unprepare(msm_rng_dev->prng_clk);
 
+	up(&msm_rng_dev->drbg_sem);
+
 	return currsize;
 }
 
+#ifdef CONFIG_FIPS_ENABLE
+static void _fips_drbg_init_error(struct msm_rng_device  *msm_rng_dev)
+{
+	unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
+	clk_put(msm_rng_dev->prng_clk);
+	iounmap(msm_rng_dev->base);
+	kzfree(msm_rng_dev->drbg_ctx);
+	kzfree(msm_rng_dev);
+	panic("software random number generator initialization error.\n");
+}
+#else
+static inline void _fips_drbg_init_error(struct msm_rng_device *msm_rng_dev)
+{
+	return;
+}
+
+#endif
+
+#ifdef CONFIG_FIPS_ENABLE
+int _do_msm_fips_drbg_init(void *rng_dev)
+{
+	struct msm_rng_device *msm_rng_dev = (struct msm_rng_device *) rng_dev;
+
+	int ret;
+
+	if (NULL == msm_rng_dev)
+		return 1;
+
+	ret = fips_drbg_init(msm_rng_dev);
+	if (0 == ret) {
+		pr_debug("start fips self test\n");
+		ret = fips_self_test();
+		if (ret) {
+			msm_rng_dev->fips140_drbg_enabled =
+				FIPS140_DRBG_DISABLED;
+			_fips_drbg_init_error(msm_rng_dev);
+		} else {
+			msm_rng_dev->fips140_drbg_enabled =
+				FIPS140_DRBG_ENABLED;
+		}
+	} else {
+		msm_rng_dev->fips140_drbg_enabled = FIPS140_DRBG_DISABLED;
+		_fips_drbg_init_error(msm_rng_dev);
+	}
+
+	return ret;
+}
+#else
+int _do_msm_fips_drbg_init(void *rng_dev)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_FIPS_ENABLE
+static int msm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+	struct msm_rng_device *msm_rng_dev = (struct msm_rng_device *)rng->priv;
+	unsigned char a[Q_HW_DRBG_BLOCK_BYTES];
+	int read_size;
+	unsigned char *p = data;
+
+	switch (fips_mode_enabled) {
+	case DRBG_FIPS_STARTED:
+		return msm_rng_drbg_read(rng, data, max, wait);
+		break;
+	case FIPS_NOT_STARTED:
+		if (g_fips140_status != FIPS140_STATUS_PASS) {
+			do {
+				read_size = msm_rng_direct_read(msm_rng_dev, a);
+				if (read_size <= 0)
+					break;
+				if ((max - read_size > 0)) {
+					memcpy(p, a, read_size);
+					p += read_size;
+					max -= read_size;
+				} else {
+					memcpy(p, a, max);
+				break;
+				}
+			} while (1);
+			return p - (unsigned char *)data;
+		} else {
+				fips_mode_enabled  = DRBG_FIPS_STARTED;
+				return msm_rng_drbg_read(rng, data, max, wait);
+			}
+		break;
+	default:
+		return 0;
+		break;
+	}
+
+	return 0;
+}
+#else
+static int msm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+	return msm_rng_drbg_read(rng, data, max, wait);
+}
+#endif
+
 static struct hwrng msm_rng = {
 	.name = DRIVER_NAME,
 	.read = msm_rng_read,
@@ -187,6 +379,20 @@
 static struct class *msm_rng_class;
 static struct cdev msm_rng_cdev;
 
+#ifdef CONFIG_FIPS_ENABLE
+
+static void _first_msm_drbg_init(struct msm_rng_device *msm_rng_dev)
+{
+	fips_reg_drbg_callback((void *)msm_rng_dev);
+	return;
+}
+#else
+static void _first_msm_drbg_init(struct msm_rng_device *msm_rng_dev)
+{
+	_do_msm_fips_drbg_init(msm_rng_dev);
+}
+#endif
+
 static int __devinit msm_rng_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -205,7 +411,7 @@
 		goto err_exit;
 	}
 
-	msm_rng_dev = kzalloc(sizeof(msm_rng_dev), GFP_KERNEL);
+	msm_rng_dev = kzalloc(sizeof(struct msm_rng_device), GFP_KERNEL);
 	if (!msm_rng_dev) {
 		dev_err(&pdev->dev, "cannot allocate memory\n");
 		error = -ENOMEM;
@@ -220,6 +426,14 @@
 	}
 	msm_rng_dev->base = base;
 
+	msm_rng_dev->drbg_ctx = kzalloc(sizeof(struct fips_drbg_ctx_s),
+					GFP_KERNEL);
+	if (!msm_rng_dev->drbg_ctx) {
+		dev_err(&pdev->dev, "cannot allocate memory\n");
+		error = -ENOMEM;
+		goto err_clk_get;
+	}
+
 	/* create a handle for clock control */
 	if ((pdev->dev.of_node) && (of_property_read_bool(pdev->dev.of_node,
 					"qcom,msm-rng-iface-clk")))
@@ -279,7 +493,11 @@
 	}
 	cdev_init(&msm_rng_cdev, &msm_rng_fops);
 
-	return ret;
+	sema_init(&msm_rng_dev->drbg_sem, 1);
+
+	_first_msm_drbg_init(msm_rng_dev);
+
+	return error;
 
 unregister_chrdev:
 	unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
@@ -288,7 +506,8 @@
 err_clk_get:
 	iounmap(msm_rng_dev->base);
 err_iomap:
-	kfree(msm_rng_dev);
+	kzfree(msm_rng_dev->drbg_ctx);
+	kzfree(msm_rng_dev);
 err_exit:
 	return error;
 }
@@ -296,6 +515,9 @@
 static int __devexit msm_rng_remove(struct platform_device *pdev)
 {
 	struct msm_rng_device *msm_rng_dev = platform_get_drvdata(pdev);
+
+	fips_drbg_final(msm_rng_dev->drbg_ctx);
+
 	unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
 	hwrng_unregister(&msm_rng);
 	clk_put(msm_rng_dev->prng_clk);
@@ -303,7 +525,11 @@
 	platform_set_drvdata(pdev, NULL);
 	if (msm_rng_dev->qrng_perf_client)
 		msm_bus_scale_unregister_client(msm_rng_dev->qrng_perf_client);
-	kfree(msm_rng_dev);
+	if (msm_rng_dev->drbg_ctx) {
+		kzfree(msm_rng_dev->drbg_ctx);
+		msm_rng_dev->drbg_ctx = NULL;
+	}
+	kzfree(msm_rng_dev);
 	return 0;
 }
 
@@ -336,6 +562,10 @@
 }
 
 module_exit(msm_rng_exit);
+#ifdef CONFIG_FIPS_ENABLE
+EXPORT_SYMBOL(fips_ctraes128_df_known_answer_test);
+#endif
+EXPORT_SYMBOL(_do_msm_fips_drbg_init);
 
 MODULE_AUTHOR("The Linux Foundation");
 MODULE_DESCRIPTION("Qualcomm MSM Random Number Driver");
diff --git a/drivers/char/hw_random/msm_rng.h b/drivers/char/hw_random/msm_rng.h
new file mode 100644
index 0000000..b79ba46
--- /dev/null
+++ b/drivers/char/hw_random/msm_rng.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MSM_RNG_HEADER__
+#define __MSM_RNG_HEADER__
+
+#include <linux/semaphore.h>
+#include <linux/qcedev.h>
+
+struct _fips_drbg_ctx;
+
+#define FIPS140_DRBG_ENABLED  (1)
+#define FIPS140_DRBG_DISABLED (0)
+
+#define Q_HW_DRBG_BLOCK_BYTES (32)
+
+extern void fips_reg_drbg_callback(void *src);
+
+struct msm_rng_device {
+	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *prng_clk;
+	uint32_t qrng_perf_client;
+	struct  semaphore drbg_sem;
+	struct fips_drbg_ctx_s *drbg_ctx;
+	int    fips140_drbg_enabled;
+};
+
+/*
+ *
+ *  This function calls hardware random bit generator
+ *  directory and retuns it back to caller.
+ *
+ */
+int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, void *data);
+
+#endif
diff --git a/drivers/crypto/msm/Makefile b/drivers/crypto/msm/Makefile
index df9acf2..ee8bc93 100644
--- a/drivers/crypto/msm/Makefile
+++ b/drivers/crypto/msm/Makefile
@@ -1,3 +1,6 @@
+ifeq ($(CONFIG_FIPS_ENABLE), y)
+	obj-$(CONFIG_CRYPTO_DEV_QCEDEV) += qcedev_fips.o
+endif
 obj-$(CONFIG_CRYPTO_DEV_QCEDEV) += qcedev.o
 ifeq ($(CONFIG_CRYPTO_DEV_QCE50), y)
 	obj-$(CONFIG_CRYPTO_DEV_QCE) += qce50.o
@@ -8,5 +11,8 @@
 		obj-$(CONFIG_CRYPTO_DEV_QCE) += qce.o
 	endif
 endif
+ifeq ($(CONFIG_FIPS_ENABLE), y)
+	obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto_fips.o
+endif
 obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto.o
 obj-$(CONFIG_CRYPTO_DEV_OTA_CRYPTO) += ota_crypto.o
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 4845f11..309816d 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1,6 +1,6 @@
 /* Qualcomm CE device driver.
  *
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,12 +33,16 @@
 #include <mach/scm.h>
 #include <mach/msm_bus.h>
 #include <linux/qcedev.h>
+#include "qcedevi.h"
 #include "qce.h"
 
 
 #define CACHE_LINE_SIZE 32
 #define CE_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE
 
+/* are FIPS integrity tests done ?? */
+bool is_fips_qcedev_integritytest_done;
+
 static uint8_t  _std_init_vector_sha1_uint8[] =   {
 	0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89,
 	0x98, 0xBA, 0xDC, 0xFE, 0x10, 0x32, 0x54, 0x76,
@@ -52,98 +56,8 @@
 	0x1F, 0x83, 0xD9, 0xAB, 0x5B, 0xE0, 0xCD, 0x19
 };
 
-enum qcedev_crypto_oper_type {
-  QCEDEV_CRYPTO_OPER_CIPHER	= 0,
-  QCEDEV_CRYPTO_OPER_SHA	= 1,
-  QCEDEV_CRYPTO_OPER_LAST
-};
-
-struct qcedev_handle;
-
-struct qcedev_cipher_req {
-	struct ablkcipher_request creq;
-	void *cookie;
-};
-
-struct qcedev_sha_req {
-	struct ahash_request sreq;
-	void *cookie;
-};
-
-struct	qcedev_sha_ctxt {
-	uint32_t	auth_data[4];
-	uint8_t		digest[QCEDEV_MAX_SHA_DIGEST];
-	uint32_t	diglen;
-	uint8_t		trailing_buf[64];
-	uint32_t	trailing_buf_len;
-	uint8_t		first_blk;
-	uint8_t		last_blk;
-	uint8_t		authkey[QCEDEV_MAX_SHA_BLOCK_SIZE];
-	bool		init_done;
-};
-
-struct qcedev_async_req {
-	struct list_head			list;
-	struct completion			complete;
-	enum qcedev_crypto_oper_type		op_type;
-	union {
-		struct qcedev_cipher_op_req	cipher_op_req;
-		struct qcedev_sha_op_req	sha_op_req;
-	};
-	union{
-		struct qcedev_cipher_req	cipher_req;
-		struct qcedev_sha_req		sha_req;
-	};
-	struct qcedev_handle			*handle;
-	int					err;
-};
-
 static DEFINE_MUTEX(send_cmd_lock);
 static DEFINE_MUTEX(qcedev_sent_bw_req);
-/**********************************************************************
- * Register ourselves as a misc device to be able to access the dev driver
- * from userspace. */
-
-
-#define QCEDEV_DEV	"qcedev"
-
-struct qcedev_control{
-
-	/* CE features supported by platform */
-	struct msm_ce_hw_support platform_support;
-
-	uint32_t ce_lock_count;
-	uint32_t high_bw_req_count;
-
-	/* CE features/algorithms supported by HW engine*/
-	struct ce_hw_support ce_support;
-
-	uint32_t  bus_scale_handle;
-
-	/* misc device */
-	struct miscdevice miscdevice;
-
-	/* qce handle */
-	void *qce;
-
-	/* platform device */
-	struct platform_device *pdev;
-
-	unsigned magic;
-
-	struct list_head ready_commands;
-	struct qcedev_async_req *active_command;
-	spinlock_t lock;
-	struct tasklet_struct done_tasklet;
-};
-
-struct qcedev_handle {
-	/* qcedev control handle */
-	struct qcedev_control *cntl;
-	/* qce internal sha context*/
-	struct	qcedev_sha_ctxt sha_ctxt;
-};
-
 /*-------------------------------------------------------------------------
 * Resource Locking Service
 * ------------------------------------------------------------------------*/
@@ -345,6 +259,12 @@
 	struct qcedev_handle *handle;
 	struct qcedev_control *podev;
 
+	/* IF FIPS tests not passed, return error */
+	if (((g_fips140_status == FIPS140_STATUS_FAIL) ||
+		(g_fips140_status == FIPS140_STATUS_PASS_CRYPTO)) &&
+		is_fips_qcedev_integritytest_done)
+		return -ENXIO;
+
 	podev = qcedev_minor_to_control(MINOR(inode->i_rdev));
 	if (podev == NULL) {
 		pr_err("%s: no such device %d\n", __func__,
@@ -427,7 +347,7 @@
 	return;
 }
 
-static void qcedev_sha_req_cb(void *cookie, unsigned char *digest,
+void qcedev_sha_req_cb(void *cookie, unsigned char *digest,
 	unsigned char *authdata, int ret)
 {
 	struct qcedev_sha_req *areq;
@@ -454,7 +374,7 @@
 };
 
 
-static void qcedev_cipher_req_cb(void *cookie, unsigned char *icv,
+void qcedev_cipher_req_cb(void *cookie, unsigned char *icv,
 	unsigned char *iv, int ret)
 {
 	struct qcedev_cipher_req *areq;
@@ -825,7 +745,7 @@
 	if (user_src && __copy_from_user(k_src,
 				(void __user *)user_src,
 				qcedev_areq->sha_op_req.data[0].len)) {
-		kfree(k_buf_src);
+		kzfree(k_buf_src);
 		return -EFAULT;
 	}
 	k_src += qcedev_areq->sha_op_req.data[0].len;
@@ -834,7 +754,7 @@
 		if (user_src && __copy_from_user(k_src,
 					(void __user *)user_src,
 					qcedev_areq->sha_op_req.data[i].len)) {
-			kfree(k_buf_src);
+			kzfree(k_buf_src);
 			return -EFAULT;
 		}
 		k_src += qcedev_areq->sha_op_req.data[i].len;
@@ -865,7 +785,7 @@
 	handle->sha_ctxt.last_blk = 0;
 	handle->sha_ctxt.first_blk = 0;
 
-	kfree(k_buf_src);
+	kzfree(k_buf_src);
 	return err;
 }
 
@@ -979,7 +899,7 @@
 		}
 		sreq->entries = saved_req->entries;
 		sreq->data_len = saved_req->data_len;
-		kfree(saved_req);
+		kzfree(saved_req);
 	} else
 		err = qcedev_sha_update_max_xfer(qcedev_areq, handle, sg_src);
 
@@ -1038,7 +958,7 @@
 	handle->sha_ctxt.init_done = false;
 	memset(&handle->sha_ctxt.trailing_buf[0], 0, 64);
 
-	kfree(k_buf_src);
+	kzfree(k_buf_src);
 	return err;
 }
 
@@ -1090,7 +1010,7 @@
 			(void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
 		if (user_src && __copy_from_user(k_src, (void __user *)user_src,
 				qcedev_areq->sha_op_req.data[i].len)) {
-			kfree(k_buf_src);
+			kzfree(k_buf_src);
 			return -EFAULT;
 		}
 		k_src += qcedev_areq->sha_op_req.data[i].len;
@@ -1104,7 +1024,7 @@
 	handle->sha_ctxt.diglen = qcedev_areq->sha_op_req.diglen;
 	err = submit_req(qcedev_areq, handle);
 
-	kfree(k_buf_src);
+	kzfree(k_buf_src);
 	return err;
 }
 
@@ -1224,7 +1144,7 @@
 	handle->sha_ctxt.last_blk = 0;
 	handle->sha_ctxt.first_blk = 0;
 
-	kfree(k_src);
+	kzfree(k_src);
 	return err;
 }
 
@@ -1507,8 +1427,8 @@
 				err = qcedev_vbuf_ablk_cipher_max_xfer(areq,
 						&di, handle, k_align_src);
 				if (err < 0) {
-					kfree(k_buf_src);
-					kfree(saved_req);
+					kzfree(k_buf_src);
+					kzfree(saved_req);
 					return err;
 				}
 
@@ -1549,8 +1469,8 @@
 				err = qcedev_vbuf_ablk_cipher_max_xfer(areq,
 						&di, handle, k_align_src);
 				if (err < 0) {
-					kfree(k_buf_src);
-					kfree(saved_req);
+					kzfree(k_buf_src);
+					kzfree(saved_req);
 					return err;
 				}
 
@@ -1593,8 +1513,8 @@
 	creq->data_len = saved_req->data_len;
 	creq->byteoffset = saved_req->byteoffset;
 
-	kfree(saved_req);
-	kfree(k_buf_src);
+	kzfree(saved_req);
+	kzfree(k_buf_src);
 	return err;
 
 }
@@ -1703,6 +1623,18 @@
 		goto error;
 	}
 
+	/* Ensure IV size */
+	if (req->ivlen > QCEDEV_MAX_IV_SIZE) {
+		pr_err("%s: ivlen is not correct: %u\n", __func__, req->ivlen);
+		goto error;
+	}
+
+	/* Ensure Key size */
+	if (req->encklen > QCEDEV_MAX_KEY_SIZE) {
+		pr_err("%s: Klen is not correct: %u\n", __func__, req->encklen);
+		goto error;
+	}
+
 	/* Ensure zer ivlen for ECB  mode  */
 	if (req->ivlen > 0) {
 		if ((req->mode == QCEDEV_AES_MODE_ECB) ||
@@ -1718,8 +1650,8 @@
 		}
 	}
 	/* Check for sum of all dst length is equal to data_len  */
-	for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++) {
-		if (req->vbuf.dst[i].len > ULONG_MAX - total) {
+	for (i = 0; i < req->entries; i++) {
+		if (req->vbuf.dst[i].len >= ULONG_MAX - total) {
 			pr_err("%s: Integer overflow on total req dst vbuf length\n",
 				__func__);
 			goto error;
@@ -2001,6 +1933,58 @@
 		}
 		break;
 
+		/* This IOCTL call can be called only once
+		by FIPS Integrity test */
+	case QCEDEV_IOCTL_UPDATE_FIPS_STATUS:
+		{
+		enum fips_status status;
+		if (is_fips_qcedev_integritytest_done)
+			return -EPERM;
+
+		if (!access_ok(VERIFY_WRITE, (void __user *)arg,
+			sizeof(enum fips_status)))
+			return -EFAULT;
+
+		if (__copy_from_user(&status, (void __user *)arg,
+			sizeof(enum fips_status)))
+			return -EFAULT;
+
+		g_fips140_status = _fips_update_status(status);
+		pr_info("qcedev: FIPS140-2 Global status flag: %d\n",
+			g_fips140_status);
+		is_fips_qcedev_integritytest_done = true;
+
+		if (g_fips140_status == FIPS140_STATUS_FAIL) {
+			pr_info("qcedev: FIPS140-2 Integrity test failed\n");
+			break;
+		}
+
+		if (!(_do_msm_fips_drbg_init(drbg_call_back)) &&
+			(g_fips140_status != FIPS140_STATUS_NA))
+			g_fips140_status = FIPS140_STATUS_PASS;
+		}
+
+		pr_info("qcedev: FIPS140-2 Global status flag: %d\n",
+			g_fips140_status);
+
+		break;
+
+		/* Read only IOCTL call to read the
+		current FIPS140-2 Status */
+	case QCEDEV_IOCTL_QUERY_FIPS_STATUS:
+		{
+		enum fips_status status;
+		if (!access_ok(VERIFY_WRITE, (void __user *)arg,
+			sizeof(enum fips_status)))
+			return -EFAULT;
+
+		status = g_fips140_status;
+		if (__copy_to_user((void __user *)arg, &status,
+			sizeof(enum fips_status)))
+			return -EFAULT;
+
+		}
+		break;
 	default:
 		return -ENOTTY;
 	}
@@ -2076,6 +2060,25 @@
 			goto err;
 		}
 	}
+
+/*
+ * FIPS140-2 Known Answer Tests:
+ * IN case of any failure, do not Init the module
+ */
+	is_fips_qcedev_integritytest_done = false;
+	if (g_fips140_status != FIPS140_STATUS_NA) {
+		if (_fips_qcedev_cipher_selftest(&qce_dev[0]) ||
+			_fips_qcedev_sha_selftest(&qce_dev[0])) {
+			pr_err("qcedev: FIPS140-2 Known Answer Tests : Failed\n");
+			panic("SYSTEM CAN NOT BOOT !!!");
+			rc = -1;
+		} else {
+			pr_info("qcedev: FIPS140-2 Known Answer Tests : Successful\n");
+			rc = 0;
+		}
+	} else
+		pr_info("qcedev: FIPS140-2 Known Answer Tests : Skipped\n");
+
 	if (rc >= 0)
 		return 0;
 	else
diff --git a/drivers/crypto/msm/qcedev_fips.c b/drivers/crypto/msm/qcedev_fips.c
new file mode 100644
index 0000000..fde1b88
--- /dev/null
+++ b/drivers/crypto/msm/qcedev_fips.c
@@ -0,0 +1,489 @@
+/* FIPS Known answer tests for QCEDEV / FIPS-non-FIPS separation .
+ *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/mman.h>
+#include <linux/types.h>
+#include <linux/export.h>
+#include <linux/qcedev.h>
+#include "qcedevi.h"
+#include "qcedev_fips.h"
+
+/*
+ * Initiate the session handle (like open /dev/qce)
+ */
+static int _fips_initiate_qcedev_handle(struct qcedev_control *podev,
+				struct qcedev_async_req *qcedev_areq)
+{
+	struct  qcedev_handle *handle;
+
+	handle = kzalloc(sizeof(struct qcedev_handle), GFP_KERNEL);
+	if (handle == NULL) {
+		pr_err("Failed to allocate memory %ld\n", PTR_ERR(handle));
+		return -ENOMEM;
+	}
+
+	handle->cntl = podev;
+	qcedev_areq->handle = handle;
+	return 0;
+}
+
+/*
+ *Initiate QCEDEV request for sha/hmac
+ */
+static
+int _fips_initiate_qcedev_async_req_sha(struct qcedev_async_req *qcedev_areq,
+		struct scatterlist *fips_sg,
+		int tv_index)
+{
+	qcedev_areq->sha_op_req.alg =
+		fips_test_vector_sha_hmac[tv_index].hash_alg;
+
+	/* If HMAC setup key else make key length zero */
+	if ((qcedev_areq->sha_op_req.alg == QCEDEV_ALG_SHA1_HMAC) ||
+		(qcedev_areq->sha_op_req.alg == QCEDEV_ALG_SHA256_HMAC) ||
+		(qcedev_areq->sha_op_req.alg == QCEDEV_ALG_AES_CMAC)) {
+		qcedev_areq->sha_op_req.authkey =
+			&fips_test_vector_sha_hmac[tv_index].key[0];
+		qcedev_areq->sha_op_req.authklen  =
+			fips_test_vector_sha_hmac[tv_index].klen;
+	} else
+		qcedev_areq->sha_op_req.authklen = 0;
+
+	/* Setup input and digest */
+	qcedev_areq->sha_op_req.data[0].vaddr =
+		&fips_test_vector_sha_hmac[tv_index].input[0];
+	qcedev_areq->sha_op_req.data[0].len =
+		fips_test_vector_sha_hmac[tv_index].ilen;
+	qcedev_areq->sha_op_req.data_len =
+		fips_test_vector_sha_hmac[tv_index].ilen;
+
+	/* Setup sha context and other parameters */
+	qcedev_areq->sha_op_req.entries = 1;
+	qcedev_areq->op_type = QCEDEV_CRYPTO_OPER_SHA;
+	memset(&qcedev_areq->handle->sha_ctxt, 0,
+		sizeof(struct qcedev_sha_ctxt));
+	qcedev_areq->handle->sha_ctxt.first_blk = 1;
+
+	/* Initialize digest and digest length */
+	memset(&qcedev_areq->sha_op_req.digest[0], 0, QCEDEV_MAX_SHA_DIGEST);
+	qcedev_areq->sha_op_req.diglen =
+		fips_test_vector_sha_hmac[tv_index].diglen;
+	switch (qcedev_areq->sha_op_req.alg) {
+	case QCEDEV_ALG_SHA1:
+	case QCEDEV_ALG_SHA1_HMAC:
+		memcpy(&qcedev_areq->handle->sha_ctxt.digest[0],
+			&_std_init_vector_sha1_uint8[0],
+			SHA1_DIGEST_SIZE);
+		break;
+	case QCEDEV_ALG_SHA256:
+	case QCEDEV_ALG_SHA256_HMAC:
+		memcpy(&qcedev_areq->handle->sha_ctxt.digest[0],
+			&_std_init_vector_sha256_uint8[0],
+			SHA256_DIGEST_SIZE);
+		break;
+	case QCEDEV_ALG_AES_CMAC:
+		qcedev_areq->handle->sha_ctxt.diglen =
+			fips_test_vector_sha_hmac[tv_index].diglen;
+		break;
+	default:
+		pr_err(" _fips_initiate_qcedev_async_req_sha : Invalid algo");
+		return -EINVAL;
+	}
+
+	qcedev_areq->handle->sha_ctxt.init_done = true;
+	qcedev_areq->handle->sha_ctxt.trailing_buf_len =
+		qcedev_areq->sha_op_req.data_len;
+	memcpy(&qcedev_areq->handle->sha_ctxt.trailing_buf[0],
+		fips_test_vector_sha_hmac[tv_index].input,
+		fips_test_vector_sha_hmac[tv_index].ilen);
+	qcedev_areq->handle->sha_ctxt.last_blk = 1;
+	qcedev_areq->sha_req.sreq.nbytes = qcedev_areq->sha_op_req.data_len;
+	qcedev_areq->sha_req.cookie = qcedev_areq->handle;
+	qcedev_areq->sha_req.sreq.src = fips_sg;
+	sg_set_buf(qcedev_areq->sha_req.sreq.src,
+		&qcedev_areq->handle->sha_ctxt.trailing_buf[0],
+		qcedev_areq->sha_op_req.data_len);
+	sg_mark_end(qcedev_areq->sha_req.sreq.src);
+	return 0;
+}
+
+/*
+ * Clean up of sha context after request completion
+ */
+static void _fips_clear_qcedev_handle(struct qcedev_sha_ctxt *sha_ctxt)
+{
+	sha_ctxt->first_blk = 0;
+	sha_ctxt->last_blk = 0;
+	sha_ctxt->auth_data[0] = 0;
+	sha_ctxt->auth_data[1] = 0;
+	sha_ctxt->trailing_buf_len = 0;
+	sha_ctxt->init_done = false;
+	memset(&sha_ctxt->trailing_buf[0], 0, 64);
+}
+
+/*
+ * Self test for SHA / HMAC
+ */
+int _fips_qcedev_sha_selftest(struct qcedev_control *podev)
+{
+	int ret = 0, tv_index, num_tv;
+	struct qce_sha_req sreq;
+	struct qcedev_async_req qcedev_areq;
+	struct scatterlist fips_sg;
+
+	/* Initiate handle */
+	if (_fips_initiate_qcedev_handle(podev, &qcedev_areq))
+		return -ENOMEM;
+
+	num_tv = (sizeof(fips_test_vector_sha_hmac))/
+		(sizeof(struct _fips_test_vector_sha_hmac));
+
+	/* Tests one by one */
+	for (tv_index = 0; tv_index < num_tv; tv_index++) {
+		init_completion(&qcedev_areq.complete);
+
+		/* Initiate the qcedev request */
+		if (_fips_initiate_qcedev_async_req_sha(&qcedev_areq,
+			&fips_sg, tv_index))
+			return -EINVAL;
+
+		podev->active_command = &qcedev_areq;
+
+		/* Initiate qce hash request */
+		sreq.qce_cb = qcedev_sha_req_cb;
+		if (qcedev_areq.sha_op_req.alg != QCEDEV_ALG_AES_CMAC) {
+			sreq.digest = &qcedev_areq.handle->sha_ctxt.digest[0];
+			sreq.first_blk = qcedev_areq.handle->sha_ctxt.first_blk;
+			sreq.last_blk = qcedev_areq.handle->sha_ctxt.last_blk;
+			sreq.auth_data[0] =
+				qcedev_areq.handle->sha_ctxt.auth_data[0];
+			sreq.auth_data[1] =
+				qcedev_areq.handle->sha_ctxt.auth_data[1];
+			sreq.auth_data[2] =
+				qcedev_areq.handle->sha_ctxt.auth_data[2];
+			sreq.auth_data[3] =
+				qcedev_areq.handle->sha_ctxt.auth_data[3];
+		}
+
+		sreq.size = qcedev_areq.sha_req.sreq.nbytes;
+		sreq.src = qcedev_areq.sha_req.sreq.src;
+		sreq.areq = (void *)&qcedev_areq.sha_req;
+		sreq.flags = 0;
+		switch (qcedev_areq.sha_op_req.alg) {
+		case QCEDEV_ALG_SHA1:
+			sreq.alg = QCE_HASH_SHA1;
+			break;
+		case QCEDEV_ALG_SHA256:
+			sreq.alg = QCE_HASH_SHA256;
+			break;
+		case QCEDEV_ALG_SHA1_HMAC:
+			sreq.alg = QCE_HASH_SHA1_HMAC;
+			sreq.authkey = &qcedev_areq.sha_op_req.authkey[0];
+			sreq.authklen = qcedev_areq.sha_op_req.authklen;
+			break;
+		case QCEDEV_ALG_SHA256_HMAC:
+			sreq.alg = QCE_HASH_SHA256_HMAC;
+			sreq.authkey =
+				&qcedev_areq.sha_op_req.authkey[0];
+			sreq.authklen =
+				qcedev_areq.sha_op_req.authklen;
+			break;
+		case QCEDEV_ALG_AES_CMAC:
+			sreq.alg = QCE_HASH_AES_CMAC;
+			sreq.authkey =
+				&qcedev_areq.sha_op_req.authkey[0];
+			sreq.authklen =
+				qcedev_areq.sha_op_req.authklen;
+			break;
+		default:
+			ret = -EINVAL;
+			goto handle_free;
+		}
+
+		/*qce call */
+		ret = qce_process_sha_req(podev->qce, &sreq);
+		if (ret == 0)
+			wait_for_completion(&qcedev_areq.complete);
+		else
+			goto handle_free;
+
+		/* Known answer test */
+		if (memcmp(&qcedev_areq.handle->sha_ctxt.digest[0],
+			fips_test_vector_sha_hmac[tv_index].digest,
+			fips_test_vector_sha_hmac[tv_index].diglen)) {
+				ret = -1;
+				goto handle_free;
+		}
+		_fips_clear_qcedev_handle(&qcedev_areq.handle->sha_ctxt);
+	}
+
+handle_free:
+	kzfree(qcedev_areq.handle);
+	return ret;
+}
+
+/*
+ * Initiate QCEDEV request for cipher (Encryption/ Decryption requests)
+ */
+static
+void _fips_initiate_qcedev_async_req_cipher(
+			struct qcedev_async_req *qcedev_areq,
+			enum qcedev_oper_enum qcedev_oper,
+			struct scatterlist *fips_sg,
+			uint8_t *k_align_src,
+			int tv_index)
+{
+	uint8_t *k_align_dst = k_align_src;
+
+	/* Setup Key */
+	memset(qcedev_areq->cipher_op_req.enckey, 0,
+		fips_test_vector_cipher[tv_index].klen);
+	memcpy(qcedev_areq->cipher_op_req.enckey,
+		fips_test_vector_cipher[tv_index].key,
+		fips_test_vector_cipher[tv_index].klen);
+	qcedev_areq->cipher_op_req.encklen =
+		fips_test_vector_cipher[tv_index].klen;
+
+	/* Setup IV */
+	memset(qcedev_areq->cipher_op_req.iv, 0,
+		fips_test_vector_cipher[tv_index].ivlen);
+	memcpy(qcedev_areq->cipher_op_req.iv,
+		fips_test_vector_cipher[tv_index].iv,
+		fips_test_vector_cipher[tv_index].ivlen);
+	qcedev_areq->cipher_op_req.ivlen =
+		fips_test_vector_cipher[tv_index].ivlen;
+
+	/* Setup other parameters */
+	qcedev_areq->cipher_op_req.byteoffset  = 0;
+	qcedev_areq->cipher_op_req.alg =
+		fips_test_vector_cipher[tv_index].enc_alg;
+	qcedev_areq->cipher_op_req.mode =
+		fips_test_vector_cipher[tv_index].mode;
+	qcedev_areq->cipher_op_req.use_pmem = 0;
+	qcedev_areq->cipher_op_req.in_place_op = 1;
+	qcedev_areq->cipher_op_req.entries = 1;
+	qcedev_areq->cipher_op_req.op = qcedev_oper;
+	qcedev_areq->op_type = QCEDEV_CRYPTO_OPER_CIPHER;
+
+	/* Setup Input and output buffers */
+	if (qcedev_oper == QCEDEV_OPER_ENC) {
+		qcedev_areq->cipher_op_req.data_len =
+			fips_test_vector_cipher[tv_index].pln_txt_len;
+		qcedev_areq->cipher_op_req.vbuf.src[0].len =
+			fips_test_vector_cipher[tv_index].pln_txt_len;
+	} else {
+		qcedev_areq->cipher_op_req.data_len =
+			fips_test_vector_cipher[tv_index].enc_txt_len;
+		qcedev_areq->cipher_op_req.vbuf.src[0].len =
+			fips_test_vector_cipher[tv_index].enc_txt_len;
+	}
+
+	qcedev_areq->cipher_op_req.vbuf.src[0].vaddr =
+		&k_align_src[0];
+	qcedev_areq->cipher_op_req.vbuf.dst[0].vaddr =
+		&k_align_dst[0];
+	qcedev_areq->cipher_op_req.vbuf.dst[0].len =
+		fips_test_vector_cipher[tv_index].enc_txt_len;
+
+	qcedev_areq->cipher_req.creq.src = fips_sg;
+	qcedev_areq->cipher_req.creq.dst = fips_sg;
+	sg_set_buf(qcedev_areq->cipher_req.creq.src,
+		k_align_src,
+		qcedev_areq->cipher_op_req.data_len);
+	sg_mark_end(qcedev_areq->cipher_req.creq.src);
+
+	qcedev_areq->cipher_req.creq.nbytes =
+		qcedev_areq->cipher_op_req.data_len;
+	qcedev_areq->cipher_req.creq.info =
+		qcedev_areq->cipher_op_req.iv;
+	qcedev_areq->cipher_req.cookie = qcedev_areq->handle;
+}
+
+/*
+ * Initiate QCE request for cipher (Encryption/ Decryption requests)
+ */
+static int _fips_initiate_qce_req_cipher(struct qcedev_async_req *qcedev_areq,
+			struct qce_req *creq,
+			enum qce_cipher_dir_enum cipher_dir)
+{
+	creq->dir = cipher_dir;
+	creq->iv = &qcedev_areq->cipher_op_req.iv[0];
+	creq->ivsize = qcedev_areq->cipher_op_req.ivlen;
+	creq->enckey =  &qcedev_areq->cipher_op_req.enckey[0];
+	creq->encklen = qcedev_areq->cipher_op_req.encklen;
+	creq->cryptlen = qcedev_areq->cipher_op_req.data_len;
+	creq->op = QCE_REQ_ABLK_CIPHER;
+	creq->qce_cb = qcedev_cipher_req_cb;
+	creq->areq = (void *)&qcedev_areq->cipher_req;
+	creq->flags = 0;
+	switch (qcedev_areq->cipher_op_req.alg) {
+	case QCEDEV_ALG_3DES:
+		creq->alg = CIPHER_ALG_3DES;
+		break;
+	case QCEDEV_ALG_AES:
+		creq->alg = CIPHER_ALG_AES;
+		break;
+	default:
+		pr_err(" _fips_initiate_qce_req_cipher : Invalid algo");
+		return -EINVAL;
+	}
+
+	switch (qcedev_areq->cipher_op_req.mode) {
+	case QCEDEV_AES_MODE_CBC:
+	case QCEDEV_DES_MODE_CBC:
+		creq->mode = QCE_MODE_CBC;
+		break;
+	case QCEDEV_AES_MODE_ECB:
+	case QCEDEV_DES_MODE_ECB:
+		creq->mode = QCE_MODE_ECB;
+		break;
+	case QCEDEV_AES_MODE_CTR:
+		creq->mode = QCE_MODE_CTR;
+		break;
+	case QCEDEV_AES_MODE_XTS:
+		creq->mode = QCE_MODE_XTS;
+		break;
+	case QCEDEV_AES_MODE_CCM:
+		creq->mode = QCE_MODE_CCM;
+		break;
+	default:
+		pr_err(" _fips_initiate_qce_req_cipher : Invalid algo");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Self test for Cipher algorithms
+ */
+int _fips_qcedev_cipher_selftest(struct qcedev_control *podev)
+{
+	int ret = 0, tv_index = 0, num_tv;
+	struct qcedev_async_req qcedev_areq;
+	struct qce_req creq;
+	struct scatterlist fips_sg;
+	uint8_t *k_align_src = NULL;
+
+	/* initiate handle */
+	if (_fips_initiate_qcedev_handle(podev, &qcedev_areq))
+		return -ENOMEM;
+
+	num_tv = (sizeof(fips_test_vector_cipher)) /
+		(sizeof(struct _fips_test_vector_cipher));
+
+	/* tests one by one */
+	for (tv_index = 0; tv_index < num_tv; tv_index++) {
+
+		/* Allocate single buffer for in-place operation */
+		k_align_src = kzalloc(QCE_MAX_OPER_DATA, GFP_KERNEL);
+		if (k_align_src == NULL) {
+			pr_err("qcedev: Failed to allocate memory for k_align_src %ld\n",
+				PTR_ERR(k_align_src));
+			kzfree(qcedev_areq.handle);
+			return -ENOMEM;
+		}
+
+		/**************** Encryption Tests *****************/
+		init_completion(&qcedev_areq.complete);
+		memcpy(&k_align_src[0],
+			fips_test_vector_cipher[tv_index].pln_txt,
+			fips_test_vector_cipher[tv_index].pln_txt_len);
+
+		/* Initiate qcedev request */
+		_fips_initiate_qcedev_async_req_cipher(&qcedev_areq,
+			QCEDEV_OPER_ENC, &fips_sg,
+			k_align_src, tv_index);
+		podev->active_command = &qcedev_areq;
+
+		/* Initiate qce cipher request */
+		if (_fips_initiate_qce_req_cipher(&qcedev_areq,
+			&creq, QCE_ENCRYPT)) {
+			ret = -EINVAL;
+			kzfree(k_align_src);
+			goto free_handle;
+		}
+
+		/* qce call */
+		ret = qce_ablk_cipher_req(podev->qce, &creq);
+		if (ret == 0)
+			wait_for_completion(&qcedev_areq.complete);
+		else {
+			kzfree(k_align_src);
+			goto free_handle;
+		}
+
+		/* Known answer test for encryption */
+		if (memcmp(k_align_src,
+			fips_test_vector_cipher[tv_index].enc_txt,
+			fips_test_vector_cipher[tv_index].enc_txt_len)) {
+			ret = -1;
+			kzfree(k_align_src);
+			goto free_handle;
+		}
+
+		/**************** Decryption Tests *****************/
+		init_completion(&qcedev_areq.complete);
+		memset(&k_align_src[0], 0,
+			fips_test_vector_cipher[tv_index].pln_txt_len);
+		memcpy(&k_align_src[0],
+			fips_test_vector_cipher[tv_index].enc_txt,
+			fips_test_vector_cipher[tv_index].enc_txt_len);
+
+		/* Initiate qcedev request */
+		_fips_initiate_qcedev_async_req_cipher(&qcedev_areq,
+			QCEDEV_OPER_DEC, &fips_sg,
+			k_align_src, tv_index);
+		podev->active_command = &qcedev_areq;
+
+		/*Initiate qce cipher request */
+		if (_fips_initiate_qce_req_cipher(&qcedev_areq,
+			&creq, QCE_DECRYPT)) {
+			ret = -EINVAL;
+			kzfree(k_align_src);
+			goto free_handle;
+		}
+
+		/* qce call */
+		ret = qce_ablk_cipher_req(podev->qce, &creq);
+		if (ret == 0)
+			wait_for_completion(&qcedev_areq.complete);
+		else {
+			kzfree(k_align_src);
+			goto free_handle;
+		}
+
+		/* Known answer test for Decryption */
+		if (memcmp(k_align_src,
+			fips_test_vector_cipher[tv_index].pln_txt,
+			fips_test_vector_cipher[tv_index].pln_txt_len)) {
+			ret = -1;
+			kzfree(k_align_src);
+			goto free_handle;
+		}
+		podev->active_command = NULL;
+		kzfree(k_align_src);
+	}
+
+free_handle:
+	kzfree(qcedev_areq.handle);
+	return ret;
+}
+
+void fips_reg_drbg_callback(void *src)
+{
+	drbg_call_back = src;
+}
+EXPORT_SYMBOL(fips_reg_drbg_callback);
diff --git a/drivers/crypto/msm/qcedev_fips.h b/drivers/crypto/msm/qcedev_fips.h
new file mode 100644
index 0000000..6f8ae7c
--- /dev/null
+++ b/drivers/crypto/msm/qcedev_fips.h
@@ -0,0 +1,438 @@
+/* Test vectors : FIPS Known answer tests for QCEDEV .
+ *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CRYPTO_MSM_QCEDEV_FIPS_H
+#define __CRYPTO_MSM_QCEDEV_FIPS_H
+
+#include "qce.h"
+
+static uint8_t  _std_init_vector_sha1_uint8[] =   {
+	0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89,
+	0x98, 0xBA, 0xDC, 0xFE, 0x10, 0x32, 0x54, 0x76,
+	0xC3, 0xD2, 0xE1, 0xF0
+};
+
+/* standard initialization vector for SHA-256, source: FIPS 180-2 */
+static uint8_t _std_init_vector_sha256_uint8[] = {
+	0x6A, 0x09, 0xE6, 0x67, 0xBB, 0x67, 0xAE, 0x85,
+	0x3C, 0x6E, 0xF3, 0x72, 0xA5, 0x4F, 0xF5, 0x3A,
+	0x51, 0x0E, 0x52, 0x7F, 0x9B, 0x05, 0x68, 0x8C,
+	0x1F, 0x83, 0xD9, 0xAB, 0x5B, 0xE0, 0xCD, 0x19
+};
+
+/*
+ * For Hashing / HMAC algorithms
+ */
+struct _fips_test_vector_sha_hmac {
+	char *key;
+	unsigned char klen;
+	char *input;
+	unsigned char ilen;
+	char *digest;
+	unsigned char diglen;
+	enum qcedev_sha_alg_enum hash_alg;
+};
+
+/*
+ * For cipher algorithms
+ */
+struct _fips_test_vector_cipher {
+	char *key;
+	unsigned char klen;
+	char *iv;
+	unsigned char ivlen;
+	char *pln_txt;
+	unsigned int pln_txt_len;
+	char *enc_txt;
+	unsigned int enc_txt_len;
+	enum qcedev_cipher_alg_enum enc_alg;
+	enum qcedev_cipher_mode_enum mode;
+};
+
+
+/*
+ * Test vectors sha and hmac algorothms
+ */
+static struct _fips_test_vector_sha_hmac fips_test_vector_sha_hmac[] = {
+/* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA1.pdf */
+	{/* SHA1 */
+		.hash_alg	=	QCEDEV_ALG_SHA1,
+		.input		=	"abc",
+		.ilen		=	3,
+		.digest	=	"\xa9\x99\x3e\x36\x47\x06\x81\x6a"
+					"\xba\x3e\x25\x71\x78\x50\xc2\x6c"
+					"\x9c\xd0\xd8\x9d",
+		.diglen	=	SHA1_DIGEST_SIZE,
+	},
+/* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf */
+	{/* SHA256 */
+		.hash_alg	=	QCEDEV_ALG_SHA256,
+		.input		=	"abc",
+		.ilen		=	3,
+		.digest	=	"\xba\x78\x16\xbf\x8f\x01\xcf\xea"
+					"\x41\x41\x40\xde\x5d\xae\x22\x23"
+					"\xb0\x03\x61\xa3\x96\x17\x7a\x9c"
+					"\xb4\x10\xff\x61\xf2\x00\x15\xad",
+		.diglen	=	SHA256_DIGEST_SIZE,
+	},
+/* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/HMAC_SHA1.pdf */
+	{/* HMAC-SHA1 */
+		.hash_alg	=	QCEDEV_ALG_SHA1_HMAC,
+		.key		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+					"\x10\x11\x12\x13",
+		.klen		=	20,
+		.input		=	"Sample message for keylen<blocklen",
+		.ilen		=	34,
+		.digest	=	"\x4C\x99\xFF\x0C\xB1\xB3\x1B\xD3"
+					"\x3F\x84\x31\xDB\xAF\x4D\x17\xFC"
+					"\xD3\x56\xA8\x07",
+		.diglen	=	SHA1_DIGEST_SIZE,
+	},
+/* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/HMAC_SHA256.pdf */
+	{/* HMAC-SHA256 */
+		.hash_alg	=	QCEDEV_ALG_SHA256_HMAC,
+		.key		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+					"\x10\x11\x12\x13\x14\x15\x16\x17"
+					"\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+					"\x20\x21\x22\x23\x24\x25\x26\x27"
+					"\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F"
+					"\x30\x31\x32\x33\x34\x35\x36\x37"
+					"\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F",
+		.klen		=	64,
+		.input		=	"Sample message for keylen=blocklen",
+		.ilen		=	34,
+		.digest	=	"\x8B\xB9\xA1\xDB\x98\x06\xF2\x0D"
+					"\xF7\xF7\x7B\x82\x13\x8C\x79\x14"
+					"\xD1\x74\xD5\x9E\x13\xDC\x4D\x01"
+					"\x69\xC9\x05\x7B\x13\x3E\x1D\x62",
+		.diglen	=	SHA256_DIGEST_SIZE,
+	},
+/* From NIST Special Publication 800-38B Appendix D.1 */
+	{/* AES 128-CMAC */
+		.hash_alg	=	QCEDEV_ALG_AES_CMAC,
+		.key		=	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+					"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen		=	16,
+		.input		=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+		.ilen		=	16,
+		.digest	=	"\x07\x0a\x16\xb4\x6b\x4d\x41\x44"
+					"\xf7\x9b\xdd\x9d\xd0\x4a\x28\x7c",
+		.diglen	=	16,
+	},
+	/* From NIST Special Publication 800-38B Appendix D.1 */
+	{/* AES 256-CMAC */
+		.hash_alg	=	QCEDEV_ALG_AES_CMAC,
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.input		=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+		.ilen		=	16,
+		.digest	=	"\x28\xa7\x02\x3f\x45\x2e\x8f\x82"
+						"\xbd\x4b\xf2\x8d\x8c\x37\xc3\x5c",
+		.diglen	=	16,
+	},
+};
+
+ /*
+ *Test vectors for cipher algorithms
+ */
+static struct _fips_test_vector_cipher fips_test_vector_cipher[] = {
+	/* From NIST Special Publication 800-38A, Appendix F.1 */
+	{/* AES-128 ECB */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_ECB,
+		.key		=	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+					"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen		=	16,
+		.ivlen		=	0,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x3a\xd7\x7b\xb4\x0d\x7a\x36\x60"
+					"\xa8\x9e\xca\xf3\x24\x66\xef\x97"
+					"\xf5\xd3\xd5\x85\x03\xb9\x69\x9d"
+					"\xe7\x85\x89\x5a\x96\xfd\xba\xaf"
+					"\x43\xb1\xcd\x7f\x59\x8e\xce\x23"
+					"\x88\x1b\x00\xe3\xed\x03\x06\x88"
+					"\x7b\x0c\x78\x5e\x27\xe8\xad\x3f"
+					"\x82\x23\x20\x71\x04\x72\x5d\xd4",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.1 */
+	{/* AES-256 ECB */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_ECB,
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.ivlen		=	0,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c"
+					"\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8"
+					"\x59\x1c\xcb\x10\xd4\x10\xed\x26"
+					"\xdc\x5b\xa7\x4a\x31\x36\x28\x70"
+					"\xb6\xed\x21\xb9\x9c\xa6\xf4\xf9"
+					"\xf1\x53\xe7\xb1\xbe\xaf\xed\x1d"
+					"\x23\x30\x4b\x7a\x39\xf9\xf3\xff"
+					"\x06\x7d\x8d\x8f\x9e\x24\xec\xc7",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.2 */
+	{/* AES-128 CBC */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_CBC,
+		.key		=	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+					"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen		=	16,
+		.iv		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x76\x49\xab\xac\x81\x19\xb2\x46"
+					"\xce\xe9\x8e\x9b\x12\xe9\x19\x7d"
+					"\x50\x86\xcb\x9b\x50\x72\x19\xee"
+					"\x95\xdb\x11\x3a\x91\x76\x78\xb2"
+					"\x73\xbe\xd6\xb8\xe3\xc1\x74\x3b"
+					"\x71\x16\xe6\x9e\x22\x22\x95\x16"
+					"\x3f\xf1\xca\xa1\x68\x1f\xac\x09"
+					"\x12\x0e\xca\x30\x75\x86\xe1\xa7",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.2 */
+	{/* AES-256 CBC */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_CBC,
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.iv		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba"
+					"\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
+					"\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d"
+					"\x67\x9f\x77\x7b\xc6\x70\x2c\x7d"
+					"\x39\xf2\x33\x69\xa9\xd9\xba\xcf"
+					"\xa5\x30\xe2\x63\x04\x23\x14\x61"
+					"\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc"
+					"\xda\x6c\x19\x07\x8c\x6a\x9d\x1b",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.5 */
+	{/* AES-128 CTR */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_CTR,
+		.key		=	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+					"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen		=	16,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x87\x4d\x61\x91\xb6\x20\xe3\x26"
+					"\x1b\xef\x68\x64\x99\x0d\xb6\xce"
+					"\x98\x06\xf6\x6b\x79\x70\xfd\xff"
+					"\x86\x17\x18\x7b\xb9\xff\xfd\xff"
+					"\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e"
+					"\x5b\x4f\x09\x02\x0d\xb0\x3e\xab"
+					"\x1e\x03\x1d\xda\x2f\xbe\x03\xd1"
+					"\x79\x21\x70\xa0\xf3\x00\x9c\xee",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.5 */
+	{/* AES-256 CTR */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_CTR,
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x60\x1e\xc3\x13\x77\x57\x89\xa5"
+					"\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28"
+					"\xf4\x43\xe3\xca\x4d\x62\xb5\x9a"
+					"\xca\x84\xe9\x90\xca\xca\xf5\xc5"
+					"\x2b\x09\x30\xda\xa2\x3d\xe9\x4c"
+					"\xe8\x70\x17\xba\x2d\x84\x98\x8d"
+					"\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6"
+					"\x13\xc2\xdd\x08\x45\x79\x41\xa6",
+		.enc_txt_len	=	64,
+	},
+	/* Derived From From NIST Special Publication 800-38A */
+	{/* AES-128 XTS requires 2 keys and thus length of key is twice. */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_XTS,
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xba\x2a\x7d\x50\x7b\x60\x63\x3e"
+					"\xf3\x1b\x06\x14\xb4\x45\xb5\xb5"
+					"\x42\x0d\x12\x57\x28\x15\x2e\x5d"
+					"\x5a\x54\xbe\x46\x5c\x9d\x1f\x2e"
+					"\x18\x8e\x79\x07\xc7\xdf\xe7\xf8"
+					"\x78\xa6\x53\x2a\x80\xb4\xd9\xce"
+					"\x1d\xbe\x75\x7e\xb6\x11\xef\x1e"
+					"\x51\x5d\xd6\x70\x03\x51\xcc\x94",
+		.enc_txt_len	=	64,
+	},
+	/* Derived From From NIST Special Publication 800-38A */
+	{/* AES-256 XTS requires 2 keys and thus length of key is twice */
+		.enc_alg	=	QCEDEV_ALG_AES,
+		.mode		=	QCEDEV_AES_MODE_XTS,
+		.key		=	"\x3a\xd7\x7b\xb4\x0d\x7a\x36\x60"
+					"\xa8\x9e\xca\xf3\x24\x66\xef\x97"
+					"\xf5\xd3\xd5\x85\x03\xb9\x69\x9d"
+					"\xe7\x85\x89\x5a\x96\xfd\xba\xaf"
+					"\x43\xb1\xcd\x7f\x59\x8e\xce\x23"
+					"\x88\x1b\x00\xe3\xed\x03\x06\x88"
+					"\x7b\x0c\x78\x5e\x27\xe8\xad\x3f"
+					"\x82\x23\x20\x71\x04\x72\x5d\xd4",
+		.klen		=	64,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xd7\x2b\x90\x02\x6f\xf0\xd2\x39"
+					"\x7b\x1a\x57\x92\xd0\x1e\xc1\xb6"
+					"\x04\x8c\x08\x8e\xa4\x1f\xa0\x0f"
+					"\x5e\xd8\xaf\xda\x6e\xd2\x4e\x5b"
+					"\x23\xde\x09\xa4\x19\x79\xda\xd4"
+					"\xe9\x4b\xbc\x05\x2e\xca\x20\x7d"
+					"\xd5\x0f\x89\x88\xa3\xda\x46\x1f"
+					"\x1e\xde\x53\x78\x90\xb2\x9a\x2c",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-67, Appendix B.1 */
+	{/* 3DES ECB */
+		.enc_alg	=	QCEDEV_ALG_3DES,
+		.mode		=	QCEDEV_DES_MODE_ECB,
+		.key		=	"\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+					"\x23\x45\x67\x89\xAB\xCD\xEF\x01"
+					"\x45\x67\x89\xAB\xCD\xEF\x01\x23",
+		.klen		=	24,
+		.ivlen		=	0,
+		.pln_txt	=	"\x54\x68\x65\x20\x71\x75\x66\x63"
+					"\x6B\x20\x62\x72\x6F\x77\x6E\x20"
+					"\x66\x6F\x78\x20\x6A\x75\x6D\x70",
+		.pln_txt_len	=	24,
+		.enc_txt	=	"\xA8\x26\xFD\x8C\xE5\x3B\x85\x5F"
+					"\xCC\xE2\x1C\x81\x12\x25\x6F\xE6"
+					"\x68\xD5\xC0\x5D\xD9\xB6\xB9\x00",
+		.enc_txt_len	=	24,
+	},
+	/* Derived From From NIST Special Publication 800-38A  and 800-67 */
+	{/* 3DES CBC */
+		.enc_alg	=	QCEDEV_ALG_3DES,
+		.mode		=	QCEDEV_DES_MODE_CBC,
+		.key		=	"\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+					"\x23\x45\x67\x89\xAB\xCD\xEF\x01"
+					"\x45\x67\x89\xAB\xCD\xEF\x01\x23",
+		.klen		=	24,
+		.iv		=	"\x00\x01\x02\x03\x04\x05\x06\x07",
+		.ivlen		=	8,
+		.pln_txt	=	"\x54\x68\x65\x20\x71\x75\x66\x63"
+					"\x6B\x20\x62\x72\x6F\x77\x6E\x20"
+					"\x66\x6F\x78\x20\x6A\x75\x6D\x70",
+		.pln_txt_len	=	24,
+		.enc_txt	=	"\xf3\x68\xd0\x6f\x3b\xbd\x61\x4e"
+					"\x60\xf2\xd0\x24\x5c\xad\x3f\x81"
+					"\x8d\x5c\x69\xf2\xcb\x3f\xd5\xc7",
+		.enc_txt_len	=	24,
+	},
+};
+#endif	/* __CRYPTO_MSM_QCEDEV_FIPS_H */
+
diff --git a/drivers/crypto/msm/qcedevi.h b/drivers/crypto/msm/qcedevi.h
new file mode 100644
index 0000000..361050a
--- /dev/null
+++ b/drivers/crypto/msm/qcedevi.h
@@ -0,0 +1,173 @@
+/* QTI crypto Driver
+ *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CRYPTO_MSM_QCEDEVI_H
+#define __CRYPTO_MSM_QCEDEVI_H
+
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <crypto/hash.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/fips_status.h>
+#include "qce.h"
+
+#define CACHE_LINE_SIZE 32
+#define CE_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE
+
+/* FIPS global status variable */
+extern enum fips_status g_fips140_status;
+
+/*FIPS140-2 call back for DRBG self test */
+extern void *drbg_call_back;
+
+enum qcedev_crypto_oper_type {
+	QCEDEV_CRYPTO_OPER_CIPHER = 0,
+	QCEDEV_CRYPTO_OPER_SHA = 1,
+	QCEDEV_CRYPTO_OPER_LAST
+};
+
+struct qcedev_handle;
+
+struct qcedev_cipher_req {
+	struct ablkcipher_request creq;
+	void *cookie;
+};
+
+struct qcedev_sha_req {
+	struct ahash_request sreq;
+	void *cookie;
+};
+
+struct	qcedev_sha_ctxt {
+	uint32_t	auth_data[4];
+	uint8_t	digest[QCEDEV_MAX_SHA_DIGEST];
+	uint32_t	diglen;
+	uint8_t	trailing_buf[64];
+	uint32_t	trailing_buf_len;
+	uint8_t	first_blk;
+	uint8_t	last_blk;
+	uint8_t	authkey[QCEDEV_MAX_SHA_BLOCK_SIZE];
+	bool		init_done;
+};
+
+struct qcedev_async_req {
+	struct list_head			list;
+	struct completion			complete;
+	enum qcedev_crypto_oper_type		op_type;
+	union {
+		struct qcedev_cipher_op_req	cipher_op_req;
+		struct qcedev_sha_op_req	sha_op_req;
+	};
+
+	union {
+		struct qcedev_cipher_req	cipher_req;
+		struct qcedev_sha_req		sha_req;
+	};
+	struct qcedev_handle			*handle;
+	int					err;
+};
+
+/**********************************************************************
+ * Register ourselves as a misc device to be able to access the dev driver
+ * from userspace. */
+
+#define QCEDEV_DEV	"qcedev"
+
+struct qcedev_control {
+
+	/* CE features supported by platform */
+	struct msm_ce_hw_support platform_support;
+
+	uint32_t ce_lock_count;
+	uint32_t high_bw_req_count;
+
+	/* CE features/algorithms supported by HW engine*/
+	struct ce_hw_support ce_support;
+
+	uint32_t  bus_scale_handle;
+
+	/* misc device */
+	struct miscdevice miscdevice;
+
+	/* qce handle */
+	void *qce;
+
+	/* platform device */
+	struct platform_device *pdev;
+
+	unsigned magic;
+
+	struct list_head ready_commands;
+	struct qcedev_async_req *active_command;
+	spinlock_t lock;
+	struct tasklet_struct done_tasklet;
+};
+
+struct qcedev_handle {
+	/* qcedev control handle */
+	struct qcedev_control *cntl;
+	/* qce internal sha context*/
+	struct qcedev_sha_ctxt sha_ctxt;
+};
+
+void qcedev_cipher_req_cb(void *cookie, unsigned char *icv,
+	unsigned char *iv, int ret);
+
+void qcedev_sha_req_cb(void *cookie, unsigned char *digest,
+	unsigned char *authdata, int ret);
+
+extern int _do_msm_fips_drbg_init(void *rng_dev);
+
+#ifdef CONFIG_FIPS_ENABLE
+
+/*
+ * Self test for Cipher algorithms
+ */
+int _fips_qcedev_cipher_selftest(struct qcedev_control *podev);
+
+/*
+ * Self test for SHA / HMAC
+ */
+
+int _fips_qcedev_sha_selftest(struct qcedev_control *podev);
+
+/*
+ * Update FIPs Global status Status
+ */
+static inline enum fips_status _fips_update_status(enum fips_status status)
+{
+	return (status == FIPS140_STATUS_PASS) ?
+		FIPS140_STATUS_QCRYPTO_ALLOWED :
+		FIPS140_STATUS_FAIL;
+}
+
+#else
+
+static inline int _fips_qcedev_cipher_selftest(struct qcedev_control *podev)
+{
+	return 0;
+}
+static inline int _fips_qcedev_sha_selftest(struct qcedev_control *podev)
+{
+	return 0;
+}
+
+static inline enum fips_status _fips_update_status(enum fips_status status)
+{
+	return FIPS140_STATUS_NA;
+}
+
+#endif  /* CONFIG_FIPS_ENABLE */
+
+#endif  /* __CRYPTO_MSM_QCEDEVI_H */
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index c247189..b8975aa 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -45,9 +45,10 @@
 #include <linux/platform_data/qcom_crypto_device.h>
 #include <mach/msm_bus.h>
 #include <mach/qcrypto.h>
+#include <linux/fips_status.h>
+#include "qcryptoi.h"
 #include "qce.h"
 
-
 #define DEBUG_MAX_FNAME  16
 #define DEBUG_MAX_RW_BUF 2048
 
@@ -58,6 +59,9 @@
 
 #define QCRYPTO_HIGH_BANDWIDTH_TIMEOUT 1000
 
+/* are FIPS self tests done ?? */
+static bool is_fips_qcrypto_tests_done;
+
 enum qcrypto_bus_state {
 	BUS_NO_BANDWIDTH = 0,
 	BUS_HAS_BANDWIDTH,
@@ -683,6 +687,12 @@
 	struct qcrypto_alg *q_alg;
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
+	/* IF FIPS tests not passed, return error */
+	if (((g_fips140_status == FIPS140_STATUS_FAIL) ||
+		(g_fips140_status == FIPS140_STATUS_PASS_CRYPTO)) &&
+		is_fips_qcrypto_tests_done)
+		return -ENXIO;
+
 	q_alg = container_of(alg, struct qcrypto_alg, cipher_alg);
 	ctx->flags = 0;
 
@@ -710,6 +720,12 @@
 	struct qcrypto_alg *q_alg = container_of(alg, struct qcrypto_alg,
 								sha_alg);
 
+	/* IF FIPS tests not passed, return error */
+	if (((g_fips140_status == FIPS140_STATUS_FAIL) ||
+		(g_fips140_status == FIPS140_STATUS_PASS_CRYPTO)) &&
+		is_fips_qcrypto_tests_done)
+		return -ENXIO;
+
 	crypto_ahash_set_reqsize(ahash, sizeof(struct qcrypto_sha_req_ctx));
 	/* update context with ptr to cp */
 	sha_ctx->cp = q_alg->cp;
@@ -959,7 +975,7 @@
 		if (q_alg->alg_type == QCRYPTO_ALG_SHA)
 			crypto_unregister_ahash(&q_alg->sha_alg);
 		list_del(&q_alg->entry);
-		kfree(q_alg);
+		kzfree(q_alg);
 	}
 }
 
@@ -978,7 +994,7 @@
 	mutex_unlock(&cp->engine_lock);
 	if (pengine->qce)
 		qce_close(pengine->qce);
-	kfree(pengine);
+	kzfree(pengine);
 	return 0;
 }
 
@@ -1282,7 +1298,7 @@
 		if (bytes != areq->nbytes)
 			pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
 								areq->nbytes);
-		kfree(rctx->data);
+		kzfree(rctx->data);
 	}
 
 	if (cp->platform_support.ce_shared)
@@ -1329,7 +1345,7 @@
 			if (bytes != nbytes)
 				pr_warn("bytes copied=0x%x bytes to copy= 0x%x",
 						bytes, nbytes);
-			kfree(rctx->data);
+			kzfree(rctx->data);
 		}
 		kzfree(rctx->assoc);
 		areq->assoc = rctx->assoc_sg;
@@ -1363,7 +1379,7 @@
 			if (bytes != nbytes)
 				pr_warn("bytes copied=0x%x bytes to copy= 0x%x",
 						bytes, nbytes);
-			kfree(rctx->data);
+			kzfree(rctx->data);
 		}
 
 		if (ret == 0) {
@@ -3163,7 +3179,7 @@
 						rctx->trailing_buf_len);
 			memcpy((rctx->data2 + rctx->trailing_buf_len),
 					rctx->data, req->src->length);
-			kfree(rctx->data);
+			kzfree(rctx->data);
 			rctx->data = rctx->data2;
 			sg_set_buf(&rctx->sg[0], rctx->data,
 					(rctx->trailing_buf_len +
@@ -3351,7 +3367,7 @@
 		INIT_COMPLETION(sha_ctx->ahash_req_complete);
 	}
 
-	kfree(in_buf);
+	kzfree(in_buf);
 	ahash_request_free(ahash_req);
 
 	return ret;
@@ -3628,6 +3644,23 @@
 	return 0;
 }
 
+/*
+ * Fill up fips_selftest_data structure
+ */
+
+static void _qcrypto_fips_selftest_d(struct fips_selftest_data *selftest_d,
+					struct ce_hw_support *ce_support,
+					char *prefix)
+{
+	strlcpy(selftest_d->algo_prefix, prefix, CRYPTO_MAX_ALG_NAME);
+	selftest_d->prefix_ahash_algo = ce_support->use_sw_ahash_algo;
+	selftest_d->prefix_hmac_algo = ce_support->use_sw_hmac_algo;
+	selftest_d->prefix_aes_xts_algo = ce_support->use_sw_aes_xts_algo;
+	selftest_d->prefix_aes_cbc_ecb_ctr_algo =
+		ce_support->use_sw_aes_cbc_ecb_ctr_algo;
+	selftest_d->prefix_aead_algo = ce_support->use_sw_aead_algo;
+	selftest_d->ce_device = ce_support->ce_device;
+}
 
 int qcrypto_cipher_set_device(struct ablkcipher_request *req, unsigned int dev)
 {
@@ -4235,6 +4268,10 @@
 	struct crypto_engine *pengine;
 	unsigned long flags;
 
+	/* For FIPS140-2 Power on self tests */
+	struct fips_selftest_data selftest_d;
+	char prefix[10] = "";
+
 	pengine = kzalloc(sizeof(*pengine), GFP_KERNEL);
 	if (!pengine) {
 		pr_err("qcrypto Memory allocation of q_alg FAIL, error %ld\n",
@@ -4245,7 +4282,7 @@
 	/* open qce */
 	handle = qce_open(pdev, &rc);
 	if (handle == NULL) {
-		kfree(pengine);
+		kzfree(pengine);
 		platform_set_drvdata(pdev, NULL);
 		return rc;
 	}
@@ -4328,7 +4365,7 @@
 
 	if (cp->total_units != 1) {
 		mutex_unlock(&cp->engine_lock);
-		return 0;
+		goto fips_selftest;
 	}
 
 	/* register crypto cipher algorithms the device supports */
@@ -4357,7 +4394,7 @@
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
 					q_alg->cipher_alg.cra_driver_name);
-			kfree(q_alg);
+			kzfree(q_alg);
 		} else {
 			list_add_tail(&q_alg->entry, &cp->alg_list);
 			dev_info(&pdev->dev, "%s\n",
@@ -4391,7 +4428,7 @@
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
 					q_alg->cipher_alg.cra_driver_name);
-			kfree(q_alg);
+			kzfree(q_alg);
 		} else {
 			list_add_tail(&q_alg->entry, &cp->alg_list);
 			dev_info(&pdev->dev, "%s\n",
@@ -4428,7 +4465,7 @@
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
 				q_alg->sha_alg.halg.base.cra_driver_name);
-			kfree(q_alg);
+			kzfree(q_alg);
 		} else {
 			list_add_tail(&q_alg->entry, &cp->alg_list);
 			dev_info(&pdev->dev, "%s\n",
@@ -4505,7 +4542,7 @@
 				dev_err(&pdev->dev,
 				"%s alg registration failed\n",
 				q_alg->sha_alg.halg.base.cra_driver_name);
-				kfree(q_alg);
+				kzfree(q_alg);
 			} else {
 				list_add_tail(&q_alg->entry, &cp->alg_list);
 				dev_info(&pdev->dev, "%s\n",
@@ -4541,7 +4578,7 @@
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
 					q_alg->cipher_alg.cra_driver_name);
-			kfree(q_alg);
+			kzfree(q_alg);
 		} else {
 			list_add_tail(&q_alg->entry, &cp->alg_list);
 			dev_info(&pdev->dev, "%s\n",
@@ -4580,13 +4617,42 @@
 	}
 
 	mutex_unlock(&cp->engine_lock);
+
+fips_selftest:
+	/*
+	* FIPS140-2 Known Answer Tests :
+	* IN case of any failure, do not Init the module
+	*/
+	is_fips_qcrypto_tests_done = false;
+
+	if (g_fips140_status != FIPS140_STATUS_NA) {
+
+		_qcrypto_prefix_alg_cra_name(prefix, 0);
+		_qcrypto_fips_selftest_d(&selftest_d, &cp->ce_support, prefix);
+		if (_fips_qcrypto_sha_selftest(&selftest_d) ||
+			_fips_qcrypto_cipher_selftest(&selftest_d) ||
+			_fips_qcrypto_aead_selftest(&selftest_d)) {
+			pr_err("qcrypto: FIPS140-2 Known Answer Tests : Failed\n");
+			panic("SYSTEM CAN NOT BOOT!!!");
+			rc = -1;
+			goto err;
+		} else
+			pr_info("qcrypto: FIPS140-2 Known Answer Tests: Successful\n");
+		if (g_fips140_status != FIPS140_STATUS_PASS)
+			g_fips140_status = FIPS140_STATUS_PASS_CRYPTO;
+
+	} else
+		pr_info("qcrypto: FIPS140-2 Known Answer Tests: Skipped\n");
+
+	is_fips_qcrypto_tests_done = true;
+
 	return 0;
 err:
 	_qcrypto_remove_engine(pengine);
 	mutex_unlock(&cp->engine_lock);
 	if (pengine->qce)
 		qce_close(pengine->qce);
-	kfree(pengine);
+	kzfree(pengine);
 	return rc;
 };
 
diff --git a/drivers/crypto/msm/qcrypto_fips.c b/drivers/crypto/msm/qcrypto_fips.c
new file mode 100644
index 0000000..a53690f
--- /dev/null
+++ b/drivers/crypto/msm/qcrypto_fips.c
@@ -0,0 +1,511 @@
+/* Qcrypto: FIPS 140-2 Selftests
+ *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <crypto/hash.h>
+#include <crypto/ctr.h>
+#include <crypto/des.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/hash.h>
+#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/internal/hash.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <mach/qcrypto.h>
+#include "qcryptoi.h"
+#include "qcrypto_fips.h"
+
+/*
+ * Callback function
+ */
+static void _fips_cb(struct crypto_async_request *crypto_async_req, int err)
+{
+	struct _fips_completion *fips_completion = crypto_async_req->data;
+	if (err == -EINPROGRESS)
+		return;
+
+	fips_completion->err = err;
+	complete(&fips_completion->completion);
+}
+
+/*
+ * Function to prefix if needed
+ */
+static int _fips_get_alg_cra_name(char cra_name[],
+				char *prefix, unsigned int size)
+{
+	char new_cra_name[CRYPTO_MAX_ALG_NAME];
+	strlcpy(new_cra_name, prefix, CRYPTO_MAX_ALG_NAME);
+	if (CRYPTO_MAX_ALG_NAME < size + strlen(prefix))
+		return -EINVAL;
+
+	strlcat(new_cra_name, cra_name, CRYPTO_MAX_ALG_NAME);
+	strlcpy(cra_name, new_cra_name, CRYPTO_MAX_ALG_NAME);
+	return 0;
+}
+
+/*
+ * Sha/HMAC self tests
+ */
+int _fips_qcrypto_sha_selftest(struct fips_selftest_data *selftest_d)
+{
+	int rc = 0, err, tv_index = 0, num_tv;
+	char *k_out_buf = NULL;
+	struct scatterlist fips_sg;
+	struct crypto_ahash *tfm;
+	struct ahash_request *ahash_req;
+	struct _fips_completion fips_completion;
+	struct _fips_test_vector_sha_hmac tv_sha_hmac;
+
+	num_tv = (sizeof(fips_test_vector_sha_hmac)) /
+	(sizeof(struct _fips_test_vector_sha_hmac));
+
+	/* One-by-one testing */
+	for (tv_index = 0; tv_index < num_tv; tv_index++) {
+		memcpy(&tv_sha_hmac, &fips_test_vector_sha_hmac[tv_index],
+			(sizeof(struct _fips_test_vector_sha_hmac)));
+		k_out_buf = kzalloc(tv_sha_hmac.diglen, GFP_KERNEL);
+		if (k_out_buf == NULL) {
+			pr_err("qcrypto: Failed to allocate memory for k_out_buf %ld\n",
+				PTR_ERR(k_out_buf));
+			return -ENOMEM;
+		}
+
+		memset(k_out_buf, 0, tv_sha_hmac.diglen);
+		init_completion(&fips_completion.completion);
+
+		/* use_sw flags are set in dtsi file which makes
+		default Linux API calls to go to s/w crypto instead
+		of h/w crypto. This code makes sure that all selftests
+		calls always go to h/w, independent of DTSI flags. */
+		if (tv_sha_hmac.klen == 0) {
+			if (selftest_d->prefix_ahash_algo)
+				if (_fips_get_alg_cra_name(tv_sha_hmac
+					.hash_alg, selftest_d->algo_prefix,
+					strlen(tv_sha_hmac.hash_alg))) {
+					rc = -1;
+					pr_err("Algo Name is too long for tv %d\n",
+					tv_index);
+					goto clr_buf;
+				}
+		} else {
+			if (selftest_d->prefix_hmac_algo)
+				if (_fips_get_alg_cra_name(tv_sha_hmac
+					.hash_alg, selftest_d->algo_prefix,
+					strlen(tv_sha_hmac.hash_alg))) {
+					rc = -1;
+					pr_err("Algo Name is too long for tv %d\n",
+					tv_index);
+					goto clr_buf;
+				}
+		}
+
+		tfm = crypto_alloc_ahash(tv_sha_hmac.hash_alg, 0, 0);
+		if (IS_ERR(tfm)) {
+			pr_err("qcrypto: %s algorithm not found\n",
+			tv_sha_hmac.hash_alg);
+			rc = PTR_ERR(tfm);
+			goto clr_buf;
+		}
+
+		ahash_req = ahash_request_alloc(tfm, GFP_KERNEL);
+		if (!ahash_req) {
+			pr_err("qcrypto: ahash_request_alloc failed\n");
+			rc = -ENOMEM;
+			goto clr_tfm;
+		}
+		rc = qcrypto_ahash_set_device(ahash_req, selftest_d->ce_device);
+		if (rc != 0) {
+			pr_err("%s qcrypto_cipher_set_device failed with err %d\n",
+				__func__, rc);
+			goto clr_ahash_req;
+		}
+		ahash_request_set_callback(ahash_req,
+			CRYPTO_TFM_REQ_MAY_BACKLOG,
+			_fips_cb, &fips_completion);
+
+		sg_init_one(&fips_sg, &tv_sha_hmac.input[0], tv_sha_hmac.ilen);
+
+		crypto_ahash_clear_flags(tfm, ~0);
+		if (tv_sha_hmac.klen != 0) {
+			rc = crypto_ahash_setkey(tfm, tv_sha_hmac.key,
+				tv_sha_hmac.klen);
+			if (rc) {
+				pr_err("qcrypto: crypto_ahash_setkey failed\n");
+				goto clr_ahash_req;
+			}
+		}
+
+		ahash_request_set_crypt(ahash_req, &fips_sg, k_out_buf,
+			tv_sha_hmac.ilen);
+		rc = crypto_ahash_digest(ahash_req);
+		if (rc == -EINPROGRESS || rc == -EBUSY) {
+			rc = wait_for_completion_interruptible(
+				&fips_completion.completion);
+			err = fips_completion.err;
+			if (!rc && !err) {
+				INIT_COMPLETION(fips_completion.completion);
+			} else {
+				pr_err("qcrypto:SHA: wait_for_completion failed\n");
+				goto clr_ahash_req;
+			}
+
+		}
+
+		if (memcmp(k_out_buf, tv_sha_hmac.digest,
+			tv_sha_hmac.diglen))
+			rc = -1;
+
+clr_ahash_req:
+		ahash_request_free(ahash_req);
+clr_tfm:
+		crypto_free_ahash(tfm);
+clr_buf:
+		kzfree(k_out_buf);
+
+	/* For any failure, return error */
+		if (rc)
+			return rc;
+
+	}
+	return rc;
+}
+
+/*
+* Cipher algorithm self tests
+*/
+int _fips_qcrypto_cipher_selftest(struct fips_selftest_data *selftest_d)
+{
+	int rc = 0, err, tv_index, num_tv;
+	struct crypto_ablkcipher *tfm;
+	struct ablkcipher_request *ablkcipher_req;
+	struct _fips_completion fips_completion;
+	char *k_align_src = NULL;
+	struct scatterlist fips_sg;
+	struct _fips_test_vector_cipher tv_cipher;
+
+	num_tv = (sizeof(fips_test_vector_cipher)) /
+		(sizeof(struct _fips_test_vector_cipher));
+
+	/* One-by-one testing */
+	for (tv_index = 0; tv_index < num_tv; tv_index++) {
+
+		memcpy(&tv_cipher, &fips_test_vector_cipher[tv_index],
+			(sizeof(struct _fips_test_vector_cipher)));
+
+		/* Single buffer allocation for in place operation */
+		k_align_src = kzalloc(tv_cipher.pln_txt_len, GFP_KERNEL);
+		if (k_align_src == NULL) {
+			pr_err("qcrypto:, Failed to allocate memory for k_align_src %ld\n",
+			PTR_ERR(k_align_src));
+			return -ENOMEM;
+		}
+
+		memcpy(&k_align_src[0], tv_cipher.pln_txt,
+			tv_cipher.pln_txt_len);
+
+		/* use_sw flags are set in dtsi file which makes
+		default Linux API calls to go to s/w crypto instead
+		of h/w crypto. This code makes sure that all selftests
+		calls always go to h/w, independent of DTSI flags. */
+		if (!strcmp(tv_cipher.mod_alg, "xts(aes)")) {
+			if (selftest_d->prefix_aes_xts_algo)
+				if (_fips_get_alg_cra_name(
+					tv_cipher.mod_alg,
+					selftest_d->algo_prefix,
+					strlen(tv_cipher.mod_alg))) {
+					rc = -1;
+					pr_err("Algo Name is too long for tv %d\n",
+					tv_index);
+					goto clr_buf;
+				}
+		} else {
+			if (selftest_d->prefix_aes_cbc_ecb_ctr_algo)
+				if (_fips_get_alg_cra_name(
+					tv_cipher.mod_alg,
+					selftest_d->algo_prefix,
+					strlen(tv_cipher.mod_alg))) {
+					rc = -1;
+					pr_err("Algo Name is too long for tv %d\n",
+					tv_index);
+					goto clr_buf;
+				}
+		}
+
+		tfm = crypto_alloc_ablkcipher(tv_cipher.mod_alg, 0, 0);
+		if (IS_ERR(tfm)) {
+			pr_err("qcrypto: %s algorithm not found\n",
+			tv_cipher.mod_alg);
+			rc = -ENOMEM;
+			goto clr_buf;
+		}
+
+		ablkcipher_req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+		if (!ablkcipher_req) {
+			pr_err("qcrypto: ablkcipher_request_alloc failed\n");
+			rc = -ENOMEM;
+			goto clr_tfm;
+		}
+		rc = qcrypto_cipher_set_device(ablkcipher_req,
+			selftest_d->ce_device);
+		if (rc != 0) {
+			pr_err("%s qcrypto_cipher_set_device failed with err %d\n",
+				__func__, rc);
+			goto clr_ablkcipher_req;
+		}
+		ablkcipher_request_set_callback(ablkcipher_req,
+			CRYPTO_TFM_REQ_MAY_BACKLOG,
+			_fips_cb, &fips_completion);
+
+		crypto_ablkcipher_clear_flags(tfm, ~0);
+		rc = crypto_ablkcipher_setkey(tfm, tv_cipher.key,
+			tv_cipher.klen);
+		if (rc) {
+			pr_err("qcrypto: crypto_ablkcipher_setkey failed\n");
+			goto clr_ablkcipher_req;
+		}
+		sg_set_buf(&fips_sg, k_align_src, tv_cipher.enc_txt_len);
+		sg_mark_end(&fips_sg);
+		ablkcipher_request_set_crypt(ablkcipher_req,
+			&fips_sg, &fips_sg, tv_cipher.pln_txt_len,
+			tv_cipher.iv);
+
+		/**** Encryption Test ****/
+		init_completion(&fips_completion.completion);
+		rc = crypto_ablkcipher_encrypt(ablkcipher_req);
+		if (rc == -EINPROGRESS || rc == -EBUSY) {
+			rc = wait_for_completion_interruptible(
+				&fips_completion.completion);
+			err = fips_completion.err;
+			if (!rc && !err) {
+				INIT_COMPLETION(fips_completion.completion);
+			} else {
+				pr_err("qcrypto:cipher:ENC, wait_for_completion failed\n");
+				goto clr_ablkcipher_req;
+			}
+
+		}
+
+		if (memcmp(k_align_src, tv_cipher.enc_txt,
+			tv_cipher.enc_txt_len)) {
+			rc = -1;
+			goto clr_ablkcipher_req;
+		}
+
+		/**** Decryption test ****/
+		init_completion(&fips_completion.completion);
+		rc = crypto_ablkcipher_decrypt(ablkcipher_req);
+		if (rc == -EINPROGRESS || rc == -EBUSY) {
+			rc = wait_for_completion_interruptible(
+				&fips_completion.completion);
+			err = fips_completion.err;
+			if (!rc && !err) {
+				INIT_COMPLETION(fips_completion.completion);
+			} else {
+				pr_err("qcrypto:cipher:DEC, wait_for_completion failed\n");
+				goto clr_ablkcipher_req;
+			}
+
+		}
+
+		if (memcmp(k_align_src, tv_cipher.pln_txt,
+			tv_cipher.pln_txt_len))
+			rc = -1;
+
+clr_ablkcipher_req:
+		ablkcipher_request_free(ablkcipher_req);
+clr_tfm:
+		crypto_free_ablkcipher(tfm);
+clr_buf:
+		kzfree(k_align_src);
+
+		if (rc)
+			return rc;
+
+	}
+	return rc;
+}
+
+/*
+ * AEAD algorithm self tests
+ */
+int _fips_qcrypto_aead_selftest(struct fips_selftest_data *selftest_d)
+{
+	int rc = 0, err, tv_index, num_tv, authsize, buf_length;
+	struct crypto_aead *tfm;
+	struct aead_request *aead_req;
+	struct _fips_completion fips_completion;
+	struct scatterlist fips_sg, fips_assoc_sg;
+	char *k_align_src = NULL;
+	struct _fips_test_vector_aead tv_aead;
+
+	num_tv = (sizeof(fips_test_vector_aead)) /
+		(sizeof(struct _fips_test_vector_aead));
+
+	/* One-by-one testing */
+	for (tv_index = 0; tv_index < num_tv; tv_index++) {
+
+		memcpy(&tv_aead, &fips_test_vector_aead[tv_index],
+			(sizeof(struct _fips_test_vector_aead)));
+
+		if (tv_aead.pln_txt_len > tv_aead.enc_txt_len)
+			buf_length = tv_aead.pln_txt_len;
+		else
+			buf_length = tv_aead.enc_txt_len;
+
+		/* Single buffer allocation for in place operation */
+		k_align_src = kzalloc(buf_length, GFP_KERNEL);
+		if (k_align_src == NULL) {
+			pr_err("qcrypto:, Failed to allocate memory for k_align_src %ld\n",
+				PTR_ERR(k_align_src));
+			return -ENOMEM;
+		}
+		memcpy(&k_align_src[0], tv_aead.pln_txt,
+			tv_aead.pln_txt_len);
+
+		/* use_sw flags are set in dtsi file which makes
+		default Linux API calls to go to s/w crypto instead
+		of h/w crypto. This code makes sure that all selftests
+		calls always go to h/w, independent of DTSI flags. */
+		if (selftest_d->prefix_aead_algo) {
+			if (_fips_get_alg_cra_name(tv_aead.mod_alg,
+				selftest_d->algo_prefix,
+				strlen(tv_aead.mod_alg))) {
+				rc = -1;
+				pr_err("Algo Name is too long for tv %d\n",
+					tv_index);
+				goto clr_buf;
+			}
+		}
+		tfm = crypto_alloc_aead(tv_aead.mod_alg, 0, 0);
+		if (IS_ERR(tfm)) {
+			pr_err("qcrypto: %s algorithm not found\n",
+				tv_aead.mod_alg);
+			rc = -ENOMEM;
+			goto clr_buf;
+		}
+		aead_req = aead_request_alloc(tfm, GFP_KERNEL);
+		if (!aead_req) {
+			pr_err("qcrypto:aead_request_alloc failed\n");
+			rc = -ENOMEM;
+			goto clr_tfm;
+		}
+		rc = qcrypto_aead_set_device(aead_req, selftest_d->ce_device);
+		if (rc != 0) {
+			pr_err("%s qcrypto_cipher_set_device failed with err %d\n",
+				__func__, rc);
+			goto clr_aead_req;
+		}
+		init_completion(&fips_completion.completion);
+		aead_request_set_callback(aead_req,
+			CRYPTO_TFM_REQ_MAY_BACKLOG,
+			_fips_cb, &fips_completion);
+		crypto_aead_clear_flags(tfm, ~0);
+		rc = crypto_aead_setkey(tfm, tv_aead.key, tv_aead.klen);
+		if (rc) {
+			pr_err("qcrypto:crypto_aead_setkey failed\n");
+			goto clr_aead_req;
+		}
+		authsize = abs(tv_aead.enc_txt_len - tv_aead.pln_txt_len);
+		rc = crypto_aead_setauthsize(tfm, authsize);
+		if (rc) {
+			pr_err("qcrypto:crypto_aead_setauthsize failed\n");
+			goto clr_aead_req;
+		}
+		sg_init_one(&fips_sg, k_align_src,
+		tv_aead.pln_txt_len + authsize);
+		aead_request_set_crypt(aead_req, &fips_sg, &fips_sg,
+			tv_aead.pln_txt_len , tv_aead.iv);
+		sg_init_one(&fips_assoc_sg, tv_aead.assoc, tv_aead.alen);
+		aead_request_set_assoc(aead_req, &fips_assoc_sg, tv_aead.alen);
+		/**** Encryption test ****/
+		rc = crypto_aead_encrypt(aead_req);
+		if (rc == -EINPROGRESS || rc == -EBUSY) {
+			rc = wait_for_completion_interruptible(
+				&fips_completion.completion);
+			err = fips_completion.err;
+			if (!rc && !err) {
+				INIT_COMPLETION(fips_completion.completion);
+			} else {
+				pr_err("qcrypto:aead:ENC, wait_for_completion failed\n");
+				goto clr_aead_req;
+			}
+
+		}
+		if (memcmp(k_align_src, tv_aead.enc_txt, tv_aead.enc_txt_len)) {
+			rc = -1;
+			goto clr_aead_req;
+		}
+
+		/** Decryption test **/
+		init_completion(&fips_completion.completion);
+		aead_request_set_callback(aead_req,
+			CRYPTO_TFM_REQ_MAY_BACKLOG,
+			_fips_cb, &fips_completion);
+		crypto_aead_clear_flags(tfm, ~0);
+		rc = crypto_aead_setkey(tfm, tv_aead.key, tv_aead.klen);
+		if (rc) {
+			pr_err("qcrypto:aead:DEC, crypto_aead_setkey failed\n");
+			goto clr_aead_req;
+		}
+
+		authsize = abs(tv_aead.enc_txt_len - tv_aead.pln_txt_len);
+		rc = crypto_aead_setauthsize(tfm, authsize);
+		if (rc) {
+			pr_err("qcrypto:aead:DEC, crypto_aead_setauthsize failed\n");
+			goto clr_aead_req;
+		}
+
+		sg_init_one(&fips_sg, k_align_src,
+			tv_aead.enc_txt_len + authsize);
+		aead_request_set_crypt(aead_req, &fips_sg, &fips_sg,
+			tv_aead.enc_txt_len, tv_aead.iv);
+		sg_init_one(&fips_assoc_sg, tv_aead.assoc, tv_aead.alen);
+		aead_request_set_assoc(aead_req, &fips_assoc_sg,
+			tv_aead.alen);
+		rc = crypto_aead_decrypt(aead_req);
+		if (rc == -EINPROGRESS || rc == -EBUSY) {
+			rc = wait_for_completion_interruptible(
+				&fips_completion.completion);
+			err = fips_completion.err;
+			if (!rc && !err) {
+				INIT_COMPLETION(fips_completion.completion);
+			} else {
+				pr_err("qcrypto:aead:DEC, wait_for_completion failed\n");
+				goto clr_aead_req;
+			}
+
+		}
+
+		if (memcmp(k_align_src, tv_aead.pln_txt, tv_aead.pln_txt_len)) {
+			rc = -1;
+			goto clr_aead_req;
+		}
+clr_aead_req:
+		aead_request_free(aead_req);
+clr_tfm:
+		crypto_free_aead(tfm);
+clr_buf:
+		kzfree(k_align_src);
+	/* In case of any failure, return error */
+		if (rc)
+			return rc;
+	}
+	return rc;
+}
+
diff --git a/drivers/crypto/msm/qcrypto_fips.h b/drivers/crypto/msm/qcrypto_fips.h
new file mode 100644
index 0000000..9624adc
--- /dev/null
+++ b/drivers/crypto/msm/qcrypto_fips.h
@@ -0,0 +1,446 @@
+/* FIPS Known answer tests for Qcrypto.
+ *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CRYPTO_MSM_QCRYPTO_FIPS_H
+#define __CRYPTO_MSM_QCRYPTO_FIPS_H
+
+struct _fips_completion {
+	struct completion completion;
+	int err;
+};
+
+/*
+ *   For cipher algorithms.
+ */
+struct _fips_test_vector_cipher {
+	char *key;
+	unsigned char klen;
+	char iv[16];
+	unsigned char ivlen;
+	char *pln_txt;
+	unsigned int pln_txt_len;
+	char *enc_txt;
+	unsigned int enc_txt_len;
+	char mod_alg[CRYPTO_MAX_ALG_NAME];
+};
+
+/*
+ * For Hashing / HMAC algorithms.
+ */
+struct _fips_test_vector_sha_hmac {
+	char *key;
+	unsigned char klen;
+	char *input;
+	unsigned char ilen;
+	char *digest;
+	unsigned char diglen;
+	char hash_alg[CRYPTO_MAX_ALG_NAME];
+};
+
+/*
+ *For AEAD algorithms
+ */
+struct _fips_test_vector_aead {
+	char *key;
+	unsigned char klen;
+	char iv[16];
+	unsigned char ivlen;
+	char assoc[32];
+	unsigned char alen;
+	char *pln_txt;
+	unsigned int pln_txt_len;
+	char *enc_txt;
+	unsigned int enc_txt_len;
+	char mod_alg[CRYPTO_MAX_ALG_NAME];
+};
+
+/*
+ *Test vectors for sha/hmac tests
+ */
+static struct _fips_test_vector_sha_hmac fips_test_vector_sha_hmac[] = {
+/*http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA1.pdf*/
+	{ /* SHA1 */
+		.hash_alg	=	"sha1",
+		.klen		=	0,
+		.input		=	"abc",
+		.ilen		=	3,
+		.digest	=	"\xa9\x99\x3e\x36\x47\x06\x81\x6a"
+					"\xba\x3e\x25\x71\x78\x50\xc2\x6c"
+					"\x9c\xd0\xd8\x9d",
+		.diglen	=	SHA1_DIGEST_SIZE,
+	},
+/* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf */
+	{/* SHA256 */
+		.hash_alg	=	"sha256",
+		.klen		=	0,
+		.input		=	"abc",
+		.ilen		=	3,
+		.digest	=	"\xba\x78\x16\xbf\x8f\x01\xcf\xea"
+					"\x41\x41\x40\xde\x5d\xae\x22\x23"
+					"\xb0\x03\x61\xa3\x96\x17\x7a\x9c"
+					"\xb4\x10\xff\x61\xf2\x00\x15\xad",
+		.diglen	=	SHA256_DIGEST_SIZE,
+	},
+/* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/HMAC_SHA1.pdf */
+	{/* HMAC-SHA1 */
+		.hash_alg	=	"hmac(sha1)",
+		.key		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+					"\x10\x11\x12\x13",
+		.klen		=	20,
+		.input		=	"Sample message for keylen<blocklen",
+		.ilen		=	34,
+		.digest	=	"\x4C\x99\xFF\x0C\xB1\xB3\x1B\xD3"
+					"\x3F\x84\x31\xDB\xAF\x4D\x17\xFC"
+					"\xD3\x56\xA8\x07",
+		.diglen	=	SHA1_DIGEST_SIZE,
+	},
+/* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/HMAC_SHA256.pdf */
+	{/* HMAC-SHA256 */
+		.hash_alg	=	"hmac(sha256)",
+		.key		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+					"\x10\x11\x12\x13\x14\x15\x16\x17"
+					"\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+					"\x20\x21\x22\x23\x24\x25\x26\x27"
+					"\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F"
+					"\x30\x31\x32\x33\x34\x35\x36\x37"
+					"\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F",
+		.klen		=	64,
+		.input		=	"Sample message for keylen=blocklen",
+		.ilen		=	34,
+		.digest	=	"\x8B\xB9\xA1\xDB\x98\x06\xF2\x0D"
+					"\xF7\xF7\x7B\x82\x13\x8C\x79\x14"
+					"\xD1\x74\xD5\x9E\x13\xDC\x4D\x01"
+					"\x69\xC9\x05\x7B\x13\x3E\x1D\x62",
+		.diglen	=	SHA256_DIGEST_SIZE,
+	},
+};
+
+/*
+ *Test vectors For cipher algorithms
+ */
+static struct _fips_test_vector_cipher fips_test_vector_cipher[] = {
+	/* From NIST Special Publication 800-38A, Appendix F.1 */
+	{/* AES-128 ECB */
+		.mod_alg	=	"ecb(aes)",
+		.key		=	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+					"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen		=	16,
+		.ivlen		=	0,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x3a\xd7\x7b\xb4\x0d\x7a\x36\x60"
+					"\xa8\x9e\xca\xf3\x24\x66\xef\x97"
+					"\xf5\xd3\xd5\x85\x03\xb9\x69\x9d"
+					"\xe7\x85\x89\x5a\x96\xfd\xba\xaf"
+					"\x43\xb1\xcd\x7f\x59\x8e\xce\x23"
+					"\x88\x1b\x00\xe3\xed\x03\x06\x88"
+					"\x7b\x0c\x78\x5e\x27\xe8\xad\x3f"
+					"\x82\x23\x20\x71\x04\x72\x5d\xd4",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.1 */
+	{/* AES-256 ECB */
+		.mod_alg	=	"ecb(aes)",
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.ivlen		=	0,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c"
+					"\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8"
+					"\x59\x1c\xcb\x10\xd4\x10\xed\x26"
+					"\xdc\x5b\xa7\x4a\x31\x36\x28\x70"
+					"\xb6\xed\x21\xb9\x9c\xa6\xf4\xf9"
+					"\xf1\x53\xe7\xb1\xbe\xaf\xed\x1d"
+					"\x23\x30\x4b\x7a\x39\xf9\xf3\xff"
+					"\x06\x7d\x8d\x8f\x9e\x24\xec\xc7",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.2 */
+	{/* AES-128 CBC */
+		.mod_alg	=	"cbc(aes)",
+		.key		=	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+					"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen		=	16,
+		.iv		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x76\x49\xab\xac\x81\x19\xb2\x46"
+					"\xce\xe9\x8e\x9b\x12\xe9\x19\x7d"
+					"\x50\x86\xcb\x9b\x50\x72\x19\xee"
+					"\x95\xdb\x11\x3a\x91\x76\x78\xb2"
+					"\x73\xbe\xd6\xb8\xe3\xc1\x74\x3b"
+					"\x71\x16\xe6\x9e\x22\x22\x95\x16"
+					"\x3f\xf1\xca\xa1\x68\x1f\xac\x09"
+					"\x12\x0e\xca\x30\x75\x86\xe1\xa7",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.2 */
+	{/* AES-256 CBC */
+		.mod_alg	=	"cbc(aes)",
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.iv		=	"\x00\x01\x02\x03\x04\x05\x06\x07"
+					"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba"
+					"\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
+					"\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d"
+					"\x67\x9f\x77\x7b\xc6\x70\x2c\x7d"
+					"\x39\xf2\x33\x69\xa9\xd9\xba\xcf"
+					"\xa5\x30\xe2\x63\x04\x23\x14\x61"
+					"\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc"
+					"\xda\x6c\x19\x07\x8c\x6a\x9d\x1b",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.5 */
+	{/* AES-128 CTR */
+		.mod_alg	=	"ctr(aes)",
+		.key		=	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+					"\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen		=	16,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x87\x4d\x61\x91\xb6\x20\xe3\x26"
+					"\x1b\xef\x68\x64\x99\x0d\xb6\xce"
+					"\x98\x06\xf6\x6b\x79\x70\xfd\xff"
+					"\x86\x17\x18\x7b\xb9\xff\xfd\xff"
+					"\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e"
+					"\x5b\x4f\x09\x02\x0d\xb0\x3e\xab"
+					"\x1e\x03\x1d\xda\x2f\xbe\x03\xd1"
+					"\x79\x21\x70\xa0\xf3\x00\x9c\xee",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-38A, Appendix F.5 */
+	{/* AES-256 CTR */
+		.mod_alg	=	"ctr(aes)",
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\x60\x1e\xc3\x13\x77\x57\x89\xa5"
+					"\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28"
+					"\xf4\x43\xe3\xca\x4d\x62\xb5\x9a"
+					"\xca\x84\xe9\x90\xca\xca\xf5\xc5"
+					"\x2b\x09\x30\xda\xa2\x3d\xe9\x4c"
+					"\xe8\x70\x17\xba\x2d\x84\x98\x8d"
+					"\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6"
+					"\x13\xc2\xdd\x08\x45\x79\x41\xa6",
+		.enc_txt_len	=	64,
+	},
+	/* Derived From From NIST Special Publication 800-38A */
+	{/* AES-128 XTS requires 2 keys and thus length of key is twice. */
+		.mod_alg	=	"xts(aes)",
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xba\x2a\x7d\x50\x7b\x60\x63\x3e"
+					"\xf3\x1b\x06\x14\xb4\x45\xb5\xb5"
+					"\x42\x0d\x12\x57\x28\x15\x2e\x5d"
+					"\x5a\x54\xbe\x46\x5c\x9d\x1f\x2e"
+					"\x18\x8e\x79\x07\xc7\xdf\xe7\xf8"
+					"\x78\xa6\x53\x2a\x80\xb4\xd9\xce"
+					"\x1d\xbe\x75\x7e\xb6\x11\xef\x1e"
+					"\x51\x5d\xd6\x70\x03\x51\xcc\x94",
+		.enc_txt_len	=	64,
+	},
+	/* Derived From From NIST Special Publication 800-38A */
+	{/* AES-256 XTS requires 2 keys and thus length of key is twice */
+		.mod_alg	=	"xts(aes)",
+		.key		=	"\x3a\xd7\x7b\xb4\x0d\x7a\x36\x60"
+					"\xa8\x9e\xca\xf3\x24\x66\xef\x97"
+					"\xf5\xd3\xd5\x85\x03\xb9\x69\x9d"
+					"\xe7\x85\x89\x5a\x96\xfd\xba\xaf"
+					"\x43\xb1\xcd\x7f\x59\x8e\xce\x23"
+					"\x88\x1b\x00\xe3\xed\x03\x06\x88"
+					"\x7b\x0c\x78\x5e\x27\xe8\xad\x3f"
+					"\x82\x23\x20\x71\x04\x72\x5d\xd4",
+		.klen		=	64,
+		.iv		=	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+					"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ivlen		=	16,
+		.pln_txt	=	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+					"\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+					"\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+					"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+					"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+					"\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+					"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+					"\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.pln_txt_len	=	64,
+		.enc_txt	=	"\xd7\x2b\x90\x02\x6f\xf0\xd2\x39"
+					"\x7b\x1a\x57\x92\xd0\x1e\xc1\xb6"
+					"\x04\x8c\x08\x8e\xa4\x1f\xa0\x0f"
+					"\x5e\xd8\xaf\xda\x6e\xd2\x4e\x5b"
+					"\x23\xde\x09\xa4\x19\x79\xda\xd4"
+					"\xe9\x4b\xbc\x05\x2e\xca\x20\x7d"
+					"\xd5\x0f\x89\x88\xa3\xda\x46\x1f"
+					"\x1e\xde\x53\x78\x90\xb2\x9a\x2c",
+		.enc_txt_len	=	64,
+	},
+	/* From NIST Special Publication 800-67, Appendix B.1 */
+	{/* 3DES ECB */
+		.mod_alg	=	"ecb(des3_ede)",
+		.key		=	"\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+					"\x23\x45\x67\x89\xAB\xCD\xEF\x01"
+					"\x45\x67\x89\xAB\xCD\xEF\x01\x23",
+		.klen		=	24,
+		.ivlen		=	0,
+		.pln_txt	=	"\x54\x68\x65\x20\x71\x75\x66\x63"
+					"\x6B\x20\x62\x72\x6F\x77\x6E\x20"
+					"\x66\x6F\x78\x20\x6A\x75\x6D\x70",
+		.pln_txt_len	=	24,
+		.enc_txt	=	"\xA8\x26\xFD\x8C\xE5\x3B\x85\x5F"
+					"\xCC\xE2\x1C\x81\x12\x25\x6F\xE6"
+					"\x68\xD5\xC0\x5D\xD9\xB6\xB9\x00",
+		.enc_txt_len	=	24,
+	},
+	/* Derived From From NIST Special Publication 800-38A  and 800-67 */
+	{/* 3DES CBC */
+		.mod_alg	=	"cbc(des3_ede)",
+		.key		=	"\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+					"\x23\x45\x67\x89\xAB\xCD\xEF\x01"
+					"\x45\x67\x89\xAB\xCD\xEF\x01\x23",
+		.klen		=	24,
+		.iv		=	"\x00\x01\x02\x03\x04\x05\x06\x07",
+		.ivlen		=	8,
+		.pln_txt	=	"\x54\x68\x65\x20\x71\x75\x66\x63"
+					"\x6B\x20\x62\x72\x6F\x77\x6E\x20"
+					"\x66\x6F\x78\x20\x6A\x75\x6D\x70",
+		.pln_txt_len	=	24,
+		.enc_txt	=	"\xf3\x68\xd0\x6f\x3b\xbd\x61\x4e"
+					"\x60\xf2\xd0\x24\x5c\xad\x3f\x81"
+					"\x8d\x5c\x69\xf2\xcb\x3f\xd5\xc7",
+		.enc_txt_len	=	24,
+	},
+};
+
+/*
+ *Test vectors For AEAD algorithms
+ */
+static struct _fips_test_vector_aead fips_test_vector_aead[] = {
+	/* From NIST Special Publication 800-38C: Appendix C.1  */
+	{ /*AES 128-CCM */
+		.mod_alg	=	"ccm(aes)",
+		.key		=	"\x40\x41\x42\x43\x44\x45\x46\x47"
+					"\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
+		.klen		=	16,
+		.iv		=	"\x07\x10\x11\x12\x13\x14\x15\x16"
+					"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ivlen		=	16,
+		.assoc		=	"\x00\x01\x02\x03\x04\x05\x06\x07",
+		.alen		=	8,
+		.pln_txt	=	"\x20\x21\x22\x23",
+		.pln_txt_len	=	4,
+		.enc_txt	=	"\x71\x62\x01\x5b\x4d\xac\x25\x5d",
+		.enc_txt_len	=	8,
+	},
+	/* Derived From NIST Special Publication 800-38C: Appendix C.1  */
+	{ /*AES 256-CCM */
+		.mod_alg	=	"ccm(aes)",
+		.key		=	"\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+					"\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+					"\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+					"\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen		=	32,
+		.iv		=	"\x07\x10\x11\x12\x13\x14\x15\x16"
+					"\x00\x00\x00\x00\x00\x00\x00\x00",
+		.ivlen		=	16,
+		.assoc		=	"\x00\x01\x02\x03\x04\x05\x06\x07",
+		.alen		=	8,
+		.pln_txt	=	"\x20\x21\x22\x23",
+		.pln_txt_len	=	4,
+		.enc_txt	=	"\xa8\xc7\xa9\x6a\x3a\x5b\x15\xe1",
+		.enc_txt_len	=	8,
+	},
+};
+
+#endif /* __CRYPTO_MSM_QCRYPTO_FIPS_H */
diff --git a/drivers/crypto/msm/qcryptoi.h b/drivers/crypto/msm/qcryptoi.h
new file mode 100644
index 0000000..64963ad
--- /dev/null
+++ b/drivers/crypto/msm/qcryptoi.h
@@ -0,0 +1,74 @@
+/* QTI Crypto driver
+ *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CRYPTO_MSM_QCRYPTOI_H
+#define __CRYPTO_MSM_QCRYPTOI_H
+
+/* FIPS global status variable */
+extern enum fips_status g_fips140_status;
+
+/* The structure to hold data
+ * that selftests require
+ */
+struct fips_selftest_data {
+
+	char algo_prefix[10];
+	unsigned int ce_device;
+	bool prefix_ahash_algo;
+	bool prefix_hmac_algo;
+	bool prefix_aes_xts_algo;
+	bool prefix_aes_cbc_ecb_ctr_algo;
+	bool prefix_aead_algo;
+};
+
+#ifdef CONFIG_FIPS_ENABLE
+/*
+ * Sha/HMAC self tests
+ */
+int _fips_qcrypto_sha_selftest(struct fips_selftest_data *selftest_d);
+
+/*
+* Cipher algorithm self tests
+*/
+int _fips_qcrypto_cipher_selftest(struct fips_selftest_data *selftest_d);
+
+/*
+ * AEAD algorithm self tests
+ */
+int _fips_qcrypto_aead_selftest(struct fips_selftest_data *selftest_d);
+
+#else
+
+static inline
+int _fips_qcrypto_sha_selftest(struct fips_selftest_data *selftest_d)
+{
+	return 0;
+}
+
+static inline
+int _fips_qcrypto_cipher_selftest(struct fips_selftest_data *selftest_d)
+{
+	return 0;
+}
+
+static
+inline int _fips_qcrypto_aead_selftest(struct fips_selftest_data *selftest_d)
+{
+	return 0;
+}
+
+#endif  /* CONFIG_FIPS_ENABLE*/
+
+#endif  /* __CRYPTO_MSM_QCRYPTOI_H */
+
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
old mode 100755
new mode 100644
index c5adf38..117c5de85
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -133,6 +133,7 @@
 header-y += fib_rules.h
 header-y += fiemap.h
 header-y += filter.h
+header-y += fips_status.h
 header-y += firewire-cdev.h
 header-y += firewire-constants.h
 header-y += flat.h
diff --git a/include/linux/fips_status.h b/include/linux/fips_status.h
new file mode 100644
index 0000000..7daf27b
--- /dev/null
+++ b/include/linux/fips_status.h
@@ -0,0 +1,33 @@
+#ifndef _UAPI_FIPS_STATUS__H
+#define _UAPI_FIPS_STATUS__H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/**
+* fips_status: global FIPS140-2 status
+* @FIPS140_STATUS_NA:
+*					Not a FIPS140-2 compliant Build.
+*					The flag status won't
+*					change throughout
+*					the lifetime
+* @FIPS140_STATUS_PASS_CRYPTO:
+*					KAT self tests are passed.
+* @FIPS140_STATUS_QCRYPTO_ALLOWED:
+*					Integrity test is passed.
+* @FIPS140_STATUS_PASS:
+*					All tests are passed and build
+*					is in FIPS140-2 mode
+* @FIPS140_STATUS_FAIL:
+*					One of the test is failed.
+*					This will block all requests
+*					to crypto modules
+*/
+enum fips_status {
+		FIPS140_STATUS_NA				= 0,
+		FIPS140_STATUS_PASS_CRYPTO		= 1,
+		FIPS140_STATUS_QCRYPTO_ALLOWED	= 2,
+		FIPS140_STATUS_PASS				= 3,
+		FIPS140_STATUS_FAIL				= 0xFF
+};
+#endif /* _UAPI_FIPS_STATUS__H */
diff --git a/include/linux/qcedev.h b/include/linux/qcedev.h
index 87040df..655f2ce 100644
--- a/include/linux/qcedev.h
+++ b/include/linux/qcedev.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/ioctl.h>
+#include "fips_status.h"
 
 #define QCEDEV_MAX_SHA_BLOCK_SIZE	64
 #define QCEDEV_MAX_BEARER	31
@@ -217,6 +218,16 @@
 	enum qcedev_sha_alg_enum	alg;
 };
 
+/**
+* struct qfips_verify_t - Holds data for FIPS Integrity test
+* @kernel_size  (IN):		Size of kernel Image
+* @kernel       (IN):		pointer to buffer containing the kernel Image
+*/
+struct qfips_verify_t {
+	unsigned kernel_size;
+	void *kernel;
+};
+
 
 #define QCEDEV_IOC_MAGIC	0x87
 
@@ -238,4 +249,8 @@
 	_IO(QCEDEV_IOC_MAGIC, 8)
 #define QCEDEV_IOCTL_GET_CMAC_REQ	\
 	_IOWR(QCEDEV_IOC_MAGIC, 9, struct qcedev_cipher_op_req)
+#define QCEDEV_IOCTL_UPDATE_FIPS_STATUS		\
+	_IOWR(QCEDEV_IOC_MAGIC, 10, enum fips_status)
+#define QCEDEV_IOCTL_QUERY_FIPS_STATUS	\
+	_IOR(QCEDEV_IOC_MAGIC, 11, enum fips_status)
 #endif /* _QCEDEV__H */