--- /dev/null
+FILESEXTRAPATHS_prepend := "${THISDIR}/cryptodev-fsl"
+
+SRC_URI_fslmachine = "git://github.com/nmav/cryptodev-linux.git \
+ file://0001-add-support-for-composite-TLS-SHA1-AES-algorithm-off.patch \
+ file://0002-use-function-local-storage-for-cipher-and-hmac-keys.patch \
+ file://0003-Add-support-for-aead-keys-for-composite-algorithms.patch \
+ file://0004-fix-scatterlist-size-for-in-place-operations.patch \
+ file://0005-add-dst_len-parameter-to-be-provided-by-the-user.patch \
+ file://0006-fix-build-error-on-some-targets.patch \
+ file://0007-add-support-for-COMPAT_CIOCAUTHCRYPT-ioctl.patch \
+ file://0008-fix-cipher-algorithm-memleaks.patch \
+ file://0009-PKC-support-added-in-cryptodev-module.patch \
+ file://0010-Compat-versions-of-PKC-IOCTLs.patch \
+ file://0011-Asynchronous-interface-changes-in-cryptodev.patch \
+ file://0012-ECC_KEYGEN-and-DLC_KEYGEN-supported-in-cryptodev-mod.patch \
+ file://0013-RCU-stall-fixed-in-PKC-asynchronous-interface.patch \
+ file://0014-use-static-allocation-for-keys-copied-from-userspace.patch \
+ file://0015-Add-RSA-Key-generation-offloading.patch \
+ file://0016-Fixed-compilation-error-of-openssl-with-fsl-cryptode.patch \
+"
+SRCREV_fslmachine = "e8609a408d40c83ae8fc11bbe9a7b3847612669b"
+
+S_fslmachine = "${WORKDIR}/git"
+
--- /dev/null
+From 434790a1bbafa371c0c6647238234573db98d017 Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Thu, 29 Aug 2013 16:52:30 +0300
+Subject: [[Patch][fsl 01/16] add support for composite TLS(SHA1,AES)
+ algorithm offload
+
+Upstream-status: Pending
+
+This adds support for composite algorithm offload in a single crypto
+(cipher + hmac) operation.
+
+It requires either software or hardware TLS support in the Linux kernel
+and can be used with Freescale B*, P* and T* platforms that have support
+for hardware TLS acceleration.
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
+---
+ crypto/cryptodev.h | 1 +
+ ioctl.c | 5 +++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
+index 7fb9c7d..c0e8cd4 100644
+--- a/crypto/cryptodev.h
++++ b/crypto/cryptodev.h
+@@ -50,6 +50,7 @@ enum cryptodev_crypto_op_t {
+ CRYPTO_SHA2_384,
+ CRYPTO_SHA2_512,
+ CRYPTO_SHA2_224_HMAC,
++ CRYPTO_TLS10_AES_CBC_HMAC_SHA1,
+ CRYPTO_ALGORITHM_ALL, /* Keep updated - see below */
+ };
+
+diff --git a/ioctl.c b/ioctl.c
+index d4e83f4..a0f1db1 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -146,6 +146,11 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ stream = 1;
+ aead = 1;
+ break;
++ case CRYPTO_TLS10_AES_CBC_HMAC_SHA1:
++ alg_name = "tls10(hmac(sha1),cbc(aes))";
++ stream = 0;
++ aead = 1;
++ break;
+ case CRYPTO_NULL:
+ alg_name = "ecb(cipher_null)";
+ stream = 1;
+--
+1.7.9.7
+
--- /dev/null
+From cc65307405a21c3b709ca6f2a6f64ff0c67c0eed Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Wed, 18 Sep 2013 13:42:31 +0300
+Subject: [[Patch][fsl 02/16] use function-local storage for cipher and hmac
+ keys
+
+Upstream-status: Pending
+
+This refactorization is necessary for next patches that add support for
+aead composite ciphers where the aead key is the sum of cipher and hmac
+keys.
+
+Without this patch, the hmac and cipher keys can't be combined in the
+same ioctl.
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
+---
+ ioctl.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/ioctl.c b/ioctl.c
+index a0f1db1..c614373 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -109,6 +109,8 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ const char *alg_name = NULL;
+ const char *hash_name = NULL;
+ int hmac_mode = 1, stream = 0, aead = 0;
++ uint8_t enckey[CRYPTO_CIPHER_MAX_KEY_LEN];
++ uint8_t mackey[CRYPTO_HMAC_MAX_KEY_LEN];
+
+ /* Does the request make sense? */
+ if (unlikely(!sop->cipher && !sop->mac)) {
+@@ -227,8 +229,6 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+
+ /* Set-up crypto transform. */
+ if (alg_name) {
+- uint8_t keyp[CRYPTO_CIPHER_MAX_KEY_LEN];
+-
+ if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) {
+ ddebug(1, "Setting key failed for %s-%zu.",
+ alg_name, (size_t)sop->keylen*8);
+@@ -236,12 +236,12 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ goto error_cipher;
+ }
+
+- if (unlikely(copy_from_user(keyp, sop->key, sop->keylen))) {
++ if (unlikely(copy_from_user(enckey, sop->key, sop->keylen))) {
+ ret = -EFAULT;
+ goto error_cipher;
+ }
+
+- ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keyp,
++ ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, enckey,
+ sop->keylen, stream, aead);
+ if (ret < 0) {
+ ddebug(1, "Failed to load cipher for %s", alg_name);
+@@ -251,8 +251,6 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ }
+
+ if (hash_name && aead == 0) {
+- uint8_t keyp[CRYPTO_HMAC_MAX_KEY_LEN];
+-
+ if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) {
+ ddebug(1, "Setting key failed for %s-%zu.",
+ hash_name, (size_t)sop->mackeylen*8);
+@@ -260,14 +258,14 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ goto error_hash;
+ }
+
+- if (sop->mackey && unlikely(copy_from_user(keyp, sop->mackey,
++ if (sop->mackey && unlikely(copy_from_user(mackey, sop->mackey,
+ sop->mackeylen))) {
+ ret = -EFAULT;
+ goto error_hash;
+ }
+
+ ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode,
+- keyp, sop->mackeylen);
++ mackey, sop->mackeylen);
+ if (ret != 0) {
+ ddebug(1, "Failed to load hash for %s", hash_name);
+ ret = -EINVAL;
+--
+1.7.9.7
+
--- /dev/null
+From 8cabaedb69acc5b44c7a9cf058045908130a6af7 Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Wed, 23 Oct 2013 16:57:22 +0300
+Subject: [[Patch][fsl 03/16] Add support for aead keys for composite
+ algorithms
+
+Upstream-status: Pending
+
+Composite aead algorithms (e.g. AES-CBC + HMAC-SHA1) need two keys to
+operate. The two keys are wrapped in a single buffer in the form
+used also by crypto/authenc.c
+Blockcipher and non-composite aead algorithms (e.g. AES-GCM) use a
+single key which is simply copied from user-space.
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
+---
+ cryptlib.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ cryptlib.h | 3 +++
+ ioctl.c | 24 ++++++++++++++----------
+ 3 files changed, 76 insertions(+), 10 deletions(-)
+
+diff --git a/cryptlib.c b/cryptlib.c
+index a7fbff4..2986d09 100644
+--- a/cryptlib.c
++++ b/cryptlib.c
+@@ -34,6 +34,8 @@
+ #include <crypto/hash.h>
+ #include <crypto/cryptodev.h>
+ #include <crypto/aead.h>
++#include <linux/rtnetlink.h>
++#include <crypto/authenc.h>
+ #include "cryptodev_int.h"
+
+
+@@ -53,6 +55,63 @@ static void cryptodev_complete(struct crypto_async_request *req, int err)
+ complete(&res->completion);
+ }
+
++int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop,
++ int aead)
++{
++ unsigned int klen = sop->keylen;
++
++ if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN))
++ return -EINVAL;
++
++ if (aead && sop->mackeylen) {
++ if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN))
++ return -EINVAL;
++ klen += sop->mackeylen;
++ klen += RTA_SPACE(sizeof(struct crypto_authenc_key_param));
++ }
++
++ *keylen = klen;
++ return 0;
++}
++
++int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead)
++{
++ /* Get algorithm key from user-space. For composite aead algorithms,
++ * the key representation is in the format used by linux kernel in
++ * crypto/authenc.c
++ */
++ struct crypto_authenc_key_param *param;
++ struct rtattr *rta;
++ int ret = 0;
++
++ if (aead && sop->mackeylen) {
++ /* the key header type and header length */
++ rta = (void *)key;
++ rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
++ rta->rta_len = RTA_LENGTH(sizeof(*param));
++
++ /* the key parameter is the length of the encryption key */
++ param = RTA_DATA(rta);
++ param->enckeylen = cpu_to_be32(sop->keylen);
++
++ /* copy the hash key */
++ key += RTA_SPACE(sizeof(*param));
++ if (unlikely(copy_from_user(key, sop->mackey, sop->mackeylen))) {
++ ret = -EFAULT;
++ goto error;
++ }
++ /* get the pointer ready for the encryption key */
++ key += sop->mackeylen;
++ }
++ /* blockcipher algorithms have the key ready to use */
++ if (unlikely(copy_from_user(key, sop->key, sop->keylen)))
++ ret = -EFAULT;
++
++error:
++ return ret;
++}
++
++
+ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
+ uint8_t *keyp, size_t keylen, int stream, int aead)
+ {
+diff --git a/cryptlib.h b/cryptlib.h
+index 0744284..a0a8a63 100644
+--- a/cryptlib.h
++++ b/cryptlib.h
+@@ -25,6 +25,9 @@ struct cipher_data {
+ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
+ uint8_t *key, size_t keylen, int stream, int aead);
+ void cryptodev_cipher_deinit(struct cipher_data *cdata);
++int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead);
++int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop,
++ int aead);
+ ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata,
+ const struct scatterlist *sg1,
+ struct scatterlist *sg2, size_t len);
+diff --git a/ioctl.c b/ioctl.c
+index c614373..3baf195 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -109,7 +109,8 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ const char *alg_name = NULL;
+ const char *hash_name = NULL;
+ int hmac_mode = 1, stream = 0, aead = 0;
+- uint8_t enckey[CRYPTO_CIPHER_MAX_KEY_LEN];
++ uint8_t *key = NULL;
++ unsigned int keylen;
+ uint8_t mackey[CRYPTO_HMAC_MAX_KEY_LEN];
+
+ /* Does the request make sense? */
+@@ -229,20 +230,22 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+
+ /* Set-up crypto transform. */
+ if (alg_name) {
+- if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) {
+- ddebug(1, "Setting key failed for %s-%zu.",
+- alg_name, (size_t)sop->keylen*8);
+- ret = -EINVAL;
++ ret = cryptodev_get_cipher_keylen(&keylen, sop, aead);
++ if (unlikely(ret < 0))
+ goto error_cipher;
+- }
+
+- if (unlikely(copy_from_user(enckey, sop->key, sop->keylen))) {
+- ret = -EFAULT;
++ key = kmalloc(keylen, GFP_KERNEL);
++ if (unlikely(!key)) {
++ ret = -ENOMEM;
+ goto error_cipher;
+ }
+
+- ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, enckey,
+- sop->keylen, stream, aead);
++ ret = cryptodev_get_cipher_key(key, sop, aead);
++ if (unlikely(ret < 0))
++ goto error_cipher;
++
++ ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, key, keylen,
++ stream, aead);
+ if (ret < 0) {
+ ddebug(1, "Failed to load cipher for %s", alg_name);
+ ret = -EINVAL;
+@@ -318,6 +321,7 @@ error_hash:
+ kfree(ses_new->sg);
+ kfree(ses_new->pages);
+ error_cipher:
++ kfree(key);
+ kfree(ses_new);
+
+ return ret;
+--
+1.7.9.7
+
--- /dev/null
+From 5a6cd042d3cee9e3bbf3b0125a89e64d75dffdc7 Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Thu, 31 Oct 2013 13:13:51 +0200
+Subject: [[Patch][fsl 04/16] fix scatterlist size for in-place operations
+
+Upstream-status: Pending
+
+For in-place operations, the scatterlist must be big enough to allow for
+either the source or destination data:
+ - for block ciphers, the destination will be bigger than the source if
+ the source is not multiple of blocksize
+ - for aead ciphers, the additional data and padding guarantees the
+ destination to be bigger than the source.
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
+---
+ zc.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/zc.c b/zc.c
+index 809a36d..8855083 100644
+--- a/zc.c
++++ b/zc.c
+@@ -162,8 +162,9 @@ int get_userbuf(struct csession *ses,
+ }
+
+ if (src == dst) { /* inplace operation */
+- rc = __get_userbuf(src, src_len, 1, ses->used_pages,
+- ses->pages, ses->sg, task, mm);
++ rc = __get_userbuf(src, max(src_len, dst_len), 1, ses->used_pages,
++ ses->pages, ses->sg, task, mm);
++
+ if (unlikely(rc)) {
+ derr(1, "failed to get user pages for data IO");
+ return rc;
+--
+1.7.9.7
+
--- /dev/null
+From e673e6ec09770b624d524bcd82f911e4fe2e2075 Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Thu, 31 Oct 2013 13:27:28 +0200
+Subject: [[Patch][fsl 05/16] add dst_len parameter to be provided by the user
+
+Upstream-status: Pending
+
+This allows the user to set the result length and relieves cryptodev
+from making assumptions about it.
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
+---
+ authenc.c | 13 +++----------
+ crypto/cryptodev.h | 1 +
+ 2 files changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/authenc.c b/authenc.c
+index a183820..5235973 100644
+--- a/authenc.c
++++ b/authenc.c
+@@ -199,7 +199,7 @@ static int fill_kcaop_from_caop(struct kernel_crypt_auth_op *kcaop, struct fcryp
+ kcaop->ivlen = caop->iv ? ses_ptr->cdata.ivsize : 0;
+
+ if (caop->flags & COP_FLAG_AEAD_TLS_TYPE)
+- kcaop->dst_len = caop->len + ses_ptr->cdata.blocksize /* pad */ + caop->tag_len;
++ kcaop->dst_len = caop->dst_len;
+ else
+ kcaop->dst_len = caop->len;
+
+@@ -645,8 +645,6 @@ __crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcao
+ ret = tls_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
+ dst_sg, caop->len);
+ } else {
+- int dst_len;
+-
+ if (unlikely(ses_ptr->cdata.init == 0 ||
+ (ses_ptr->cdata.stream == 0 &&
+ ses_ptr->cdata.aead == 0))) {
+@@ -655,13 +653,8 @@ __crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcao
+ goto free_auth_buf;
+ }
+
+- if (caop->op == COP_ENCRYPT)
+- dst_len = caop->len + cryptodev_cipher_get_tag_size(&ses_ptr->cdata);
+- else
+- dst_len = caop->len;
+-
+- ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst, dst_len,
+- kcaop->task, kcaop->mm, &src_sg, &dst_sg);
++ ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst,
++ caop->dst_len, kcaop->task, kcaop->mm, &src_sg, &dst_sg);
+ if (unlikely(ret)) {
+ derr(1, "get_userbuf(): Error getting user pages.");
+ goto free_auth_buf;
+diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
+index c0e8cd4..3ea3d35 100644
+--- a/crypto/cryptodev.h
++++ b/crypto/cryptodev.h
+@@ -137,6 +137,7 @@ struct crypt_auth_op {
+ __u16 op; /* COP_ENCRYPT or COP_DECRYPT */
+ __u16 flags; /* see COP_FLAG_AEAD_* */
+ __u32 len; /* length of source data */
++ __u32 dst_len; /* length of result data */
+ __u32 auth_len; /* length of auth data */
+ __u8 __user *auth_src; /* authenticated-only data */
+
+--
+1.7.9.7
+
--- /dev/null
+From 69e00f8c1633dfe6da20ccd0cf363a481c99fc97 Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Wed, 20 Nov 2013 11:29:50 +0200
+Subject: [[Patch][fsl 06/16] fix build error on some targets
+
+Upstream-status: Pending
+
+This updates incomplete patch f681e2e5fd1088bfe0aafd1ae2560c1dc9d04778
+and allows building main.o
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
+---
+ cryptlib.c | 4 ++--
+ cryptlib.h | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/cryptlib.c b/cryptlib.c
+index 2986d09..3576f39 100644
+--- a/cryptlib.c
++++ b/cryptlib.c
+@@ -113,7 +113,7 @@ error:
+
+
+ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
+- uint8_t *keyp, size_t keylen, int stream, int aead)
++ uint8_t *keyp, unsigned int keylen, int stream, int aead)
+ {
+ int ret;
+
+@@ -313,7 +313,7 @@ ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata,
+ /* Hash functions */
+
+ int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name,
+- int hmac_mode, void *mackey, size_t mackeylen)
++ int hmac_mode, void *mackey, unsigned int mackeylen)
+ {
+ int ret;
+
+diff --git a/cryptlib.h b/cryptlib.h
+index a0a8a63..4cb66ad 100644
+--- a/cryptlib.h
++++ b/cryptlib.h
+@@ -23,7 +23,7 @@ struct cipher_data {
+ };
+
+ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
+- uint8_t *key, size_t keylen, int stream, int aead);
++ uint8_t *key, unsigned int keylen, int stream, int aead);
+ void cryptodev_cipher_deinit(struct cipher_data *cdata);
+ int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead);
+ int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop,
+@@ -87,7 +87,7 @@ ssize_t cryptodev_hash_update(struct hash_data *hdata,
+ int cryptodev_hash_reset(struct hash_data *hdata);
+ void cryptodev_hash_deinit(struct hash_data *hdata);
+ int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name,
+- int hmac_mode, void *mackey, size_t mackeylen);
++ int hmac_mode, void *mackey, unsigned int mackeylen);
+
+
+ #endif
+--
+1.7.9.7
+
--- /dev/null
+From 75e26bf18997488518228cb851585bf8e4c3120f Mon Sep 17 00:00:00 2001
+From: Horia Geanta <horia.geanta@freescale.com>
+Date: Wed, 4 Dec 2013 15:43:41 +0200
+Subject: [[Patch][fsl 07/16] add support for COMPAT_CIOCAUTHCRYPT ioctl()
+
+Upstream-status: Pending
+
+Needed for 64b kernel with 32b user space.
+
+Signed-off-by: Horia Geanta <horia.geanta@freescale.com>
+Tested-by: Cristian Stoica <cristian.stoica@freescale.com>
+---
+ authenc.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ cryptodev_int.h | 41 ++++++++++++++++++++++++++++
+ ioctl.c | 16 +++++++++++
+ 3 files changed, 137 insertions(+)
+
+diff --git a/authenc.c b/authenc.c
+index 5235973..259a225 100644
+--- a/authenc.c
++++ b/authenc.c
+@@ -241,6 +241,86 @@ static int fill_caop_from_kcaop(struct kernel_crypt_auth_op *kcaop, struct fcryp
+ return 0;
+ }
+
++/* compatibility code for 32bit userlands */
++#ifdef CONFIG_COMPAT
++
++static inline void
++compat_to_crypt_auth_op(struct compat_crypt_auth_op *compat,
++ struct crypt_auth_op *caop)
++{
++ caop->ses = compat->ses;
++ caop->op = compat->op;
++ caop->flags = compat->flags;
++ caop->len = compat->len;
++ caop->dst_len = compat->dst_len;
++ caop->auth_len = compat->auth_len;
++ caop->tag_len = compat->tag_len;
++ caop->iv_len = compat->iv_len;
++
++ caop->auth_src = compat_ptr(compat->auth_src);
++ caop->src = compat_ptr(compat->src);
++ caop->dst = compat_ptr(compat->dst);
++ caop->tag = compat_ptr(compat->tag);
++ caop->iv = compat_ptr(compat->iv);
++}
++
++static inline void
++crypt_auth_op_to_compat(struct crypt_auth_op *caop,
++ struct compat_crypt_auth_op *compat)
++{
++ compat->ses = caop->ses;
++ compat->op = caop->op;
++ compat->flags = caop->flags;
++ compat->len = caop->len;
++ compat->dst_len = caop->dst_len;
++ compat->auth_len = caop->auth_len;
++ compat->tag_len = caop->tag_len;
++ compat->iv_len = caop->iv_len;
++
++ compat->auth_src = ptr_to_compat(caop->auth_src);
++ compat->src = ptr_to_compat(caop->src);
++ compat->dst = ptr_to_compat(caop->dst);
++ compat->tag = ptr_to_compat(caop->tag);
++ compat->iv = ptr_to_compat(caop->iv);
++}
++
++int compat_kcaop_from_user(struct kernel_crypt_auth_op *kcaop,
++ struct fcrypt *fcr, void __user *arg)
++{
++ struct compat_crypt_auth_op compat_caop;
++
++ if (unlikely(copy_from_user(&compat_caop, arg, sizeof(compat_caop)))) {
++ dprintk(1, KERN_ERR, "Error in copying from userspace\n");
++ return -EFAULT;
++ }
++
++ compat_to_crypt_auth_op(&compat_caop, &kcaop->caop);
++
++ return fill_kcaop_from_caop(kcaop, fcr);
++}
++
++int compat_kcaop_to_user(struct kernel_crypt_auth_op *kcaop,
++ struct fcrypt *fcr, void __user *arg)
++{
++ int ret;
++ struct compat_crypt_auth_op compat_caop;
++
++ ret = fill_caop_from_kcaop(kcaop, fcr);
++ if (unlikely(ret)) {
++ dprintk(1, KERN_ERR, "fill_caop_from_kcaop\n");
++ return ret;
++ }
++
++ crypt_auth_op_to_compat(&kcaop->caop, &compat_caop);
++
++ if (unlikely(copy_to_user(arg, &compat_caop, sizeof(compat_caop)))) {
++ dprintk(1, KERN_ERR, "Error in copying to userspace\n");
++ return -EFAULT;
++ }
++ return 0;
++}
++
++#endif /* CONFIG_COMPAT */
+
+ int kcaop_from_user(struct kernel_crypt_auth_op *kcaop,
+ struct fcrypt *fcr, void __user *arg)
+diff --git a/cryptodev_int.h b/cryptodev_int.h
+index d7660fa..8d206c9 100644
+--- a/cryptodev_int.h
++++ b/cryptodev_int.h
+@@ -73,11 +73,43 @@ struct compat_crypt_op {
+ compat_uptr_t iv;/* initialization vector for encryption operations */
+ };
+
++ /* input of CIOCAUTHCRYPT */
++struct compat_crypt_auth_op {
++ uint32_t ses; /* session identifier */
++ uint16_t op; /* COP_ENCRYPT or COP_DECRYPT */
++ uint16_t flags; /* see COP_FLAG_AEAD_* */
++ uint32_t len; /* length of source data */
++ uint32_t dst_len; /* length of result data */
++ uint32_t auth_len; /* length of auth data */
++ compat_uptr_t auth_src; /* authenticated-only data */
++
++ /* The current implementation is more efficient if data are
++ * encrypted in-place (src==dst). */
++ compat_uptr_t src; /* data to be encrypted and
++ authenticated */
++ compat_uptr_t dst; /* pointer to output data. Must have
++ * space for tag. For TLS this should be
++ * at least len + tag_size + block_size
++ * for padding */
++
++ compat_uptr_t tag; /* where the tag will be copied to. TLS
++ * mode doesn't use that as tag is
++ * copied to dst.
++ * SRTP mode copies tag there. */
++ uint32_t tag_len; /* the length of the tag. Use zero for
++ * digest size or max tag. */
++
++ /* initialization vector for encryption operations */
++ compat_uptr_t iv;
++ uint32_t iv_len;
++};
++
+ /* compat ioctls, defined for the above structs */
+ #define COMPAT_CIOCGSESSION _IOWR('c', 102, struct compat_session_op)
+ #define COMPAT_CIOCCRYPT _IOWR('c', 104, struct compat_crypt_op)
+ #define COMPAT_CIOCASYNCCRYPT _IOW('c', 107, struct compat_crypt_op)
+ #define COMPAT_CIOCASYNCFETCH _IOR('c', 108, struct compat_crypt_op)
++#define COMPAT_CIOCAUTHCRYPT _IOWR('c', 109, struct compat_crypt_auth_op)
+
+ #endif /* CONFIG_COMPAT */
+
+@@ -108,6 +140,15 @@ struct kernel_crypt_auth_op {
+
+ /* auth */
+
++#ifdef CONFIG_COMPAT
++int compat_kcaop_from_user(struct kernel_crypt_auth_op *kcaop,
++ struct fcrypt *fcr, void __user *arg);
++
++int compat_kcaop_to_user(struct kernel_crypt_auth_op *kcaop,
++ struct fcrypt *fcr, void __user *arg);
++#endif /* CONFIG_COMPAT */
++
++
+ int kcaop_from_user(struct kernel_crypt_auth_op *kcop,
+ struct fcrypt *fcr, void __user *arg);
+ int kcaop_to_user(struct kernel_crypt_auth_op *kcaop,
+diff --git a/ioctl.c b/ioctl.c
+index 3baf195..18874d3 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -991,6 +991,7 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+ struct session_op sop;
+ struct compat_session_op compat_sop;
+ struct kernel_crypt_op kcop;
++ struct kernel_crypt_auth_op kcaop;
+ int ret;
+
+ if (unlikely(!pcr))
+@@ -1033,6 +1034,21 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+ return ret;
+
+ return compat_kcop_to_user(&kcop, fcr, arg);
++
++ case COMPAT_CIOCAUTHCRYPT:
++ if (unlikely(ret = compat_kcaop_from_user(&kcaop, fcr, arg))) {
++ dprintk(1, KERN_WARNING, "Error copying from user\n");
++ return ret;
++ }
++
++ ret = crypto_auth_run(fcr, &kcaop);
++ if (unlikely(ret)) {
++ dprintk(1, KERN_WARNING, "Error in crypto_auth_run\n");
++ return ret;
++ }
++
++ return compat_kcaop_to_user(&kcaop, fcr, arg);
++
+ #ifdef ENABLE_ASYNC
+ case COMPAT_CIOCASYNCCRYPT:
+ if (unlikely(ret = compat_kcop_from_user(&kcop, fcr, arg)))
+--
+1.7.9.7
+
--- /dev/null
+From 9675e358fe73b33029a470aa5cf47527848f4054 Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Tue, 26 Nov 2013 16:36:37 +0200
+Subject: [[Patch][fsl 08/16] fix cipher algorithm memleaks
+
+Upstream-status: Pending
+
+Patch 67e743aef130d107c1b41e0aace7677f9ff53bd1 allocates memory for
+cipher algorithm key without freeing it when session terminates. This
+patch addresses the deallocation issue.
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
+---
+ cryptodev_int.h | 1 +
+ ioctl.c | 2 ++
+ 2 files changed, 3 insertions(+)
+
+diff --git a/cryptodev_int.h b/cryptodev_int.h
+index 8d206c9..8891837 100644
+--- a/cryptodev_int.h
++++ b/cryptodev_int.h
+@@ -166,6 +166,7 @@ struct csession {
+ struct hash_data hdata;
+ uint32_t sid;
+ uint32_t alignmask;
++ uint8_t *key;
+
+ unsigned int array_size;
+ unsigned int used_pages; /* the number of pages that are used */
+diff --git a/ioctl.c b/ioctl.c
+index 18874d3..63467e0 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -235,6 +235,7 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ goto error_cipher;
+
+ key = kmalloc(keylen, GFP_KERNEL);
++ ses_new->key = key;
+ if (unlikely(!key)) {
+ ret = -ENOMEM;
+ goto error_cipher;
+@@ -342,6 +343,7 @@ crypto_destroy_session(struct csession *ses_ptr)
+ ddebug(2, "freeing space for %d user pages", ses_ptr->array_size);
+ kfree(ses_ptr->pages);
+ kfree(ses_ptr->sg);
++ kfree(ses_ptr->key);
+ mutex_unlock(&ses_ptr->sem);
+ mutex_destroy(&ses_ptr->sem);
+ kfree(ses_ptr);
+--
+1.7.9.7
+
--- /dev/null
+From 55be37e9e308990b2eeeef7f974dfbfbb1120266 Mon Sep 17 00:00:00 2001
+From: Yashpal Dutta <yashpal.dutta@freescale.com>
+Date: Fri, 7 Mar 2014 06:16:09 +0545
+Subject: [[Patch][fsl 09/16] PKC support added in cryptodev module
+
+Upstream-status: Pending
+
+Signed-off-by: Yashpal Dutta <yashpal.dutta@freescale.com>
+---
+ cryptlib.c | 66 ++++++++-
+ cryptlib.h | 28 ++++
+ crypto/cryptodev.h | 15 ++-
+ cryptodev_int.h | 20 ++-
+ ioctl.c | 196 +++++++++++++++++++++++++--
+ main.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 685 insertions(+), 18 deletions(-)
+
+diff --git a/cryptlib.c b/cryptlib.c
+index 3576f39..fa0b63f 100644
+--- a/cryptlib.c
++++ b/cryptlib.c
+@@ -5,6 +5,8 @@
+ * Portions Copyright (c) 2010 Michael Weiser
+ * Portions Copyright (c) 2010 Phil Sutter
+ *
++ * Copyright 2012 Freescale Semiconductor, Inc.
++ *
+ * This file is part of linux cryptodev.
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -39,11 +41,6 @@
+ #include "cryptodev_int.h"
+
+
+-struct cryptodev_result {
+- struct completion completion;
+- int err;
+-};
+-
+ static void cryptodev_complete(struct crypto_async_request *req, int err)
+ {
+ struct cryptodev_result *res = req->data;
+@@ -244,7 +241,6 @@ static inline int waitfor(struct cryptodev_result *cr, ssize_t ret)
+ case 0:
+ break;
+ case -EINPROGRESS:
+- case -EBUSY:
+ wait_for_completion(&cr->completion);
+ /* At this point we known for sure the request has finished,
+ * because wait_for_completion above was not interruptible.
+@@ -424,3 +420,61 @@ int cryptodev_hash_final(struct hash_data *hdata, void *output)
+ return waitfor(hdata->async.result, ret);
+ }
+
++int cryptodev_pkc_offload(struct cryptodev_pkc *pkc)
++{
++ int ret = 0;
++ struct pkc_request *pkc_req = &pkc->req, *pkc_requested;
++
++ switch (pkc_req->type) {
++ case RSA_PUB:
++ case RSA_PRIV_FORM1:
++ case RSA_PRIV_FORM2:
++ case RSA_PRIV_FORM3:
++ pkc->s = crypto_alloc_pkc("pkc(rsa)",
++ CRYPTO_ALG_TYPE_PKC_RSA, 0);
++ break;
++ case DSA_SIGN:
++ case DSA_VERIFY:
++ case ECDSA_SIGN:
++ case ECDSA_VERIFY:
++ pkc->s = crypto_alloc_pkc("pkc(dsa)",
++ CRYPTO_ALG_TYPE_PKC_DSA, 0);
++ break;
++ case DH_COMPUTE_KEY:
++ case ECDH_COMPUTE_KEY:
++ pkc->s = crypto_alloc_pkc("pkc(dh)",
++ CRYPTO_ALG_TYPE_PKC_DH, 0);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (IS_ERR_OR_NULL(pkc->s))
++ return -EINVAL;
++
++ init_completion(&pkc->result.completion);
++ pkc_requested = pkc_request_alloc(pkc->s, GFP_KERNEL);
++
++ if (unlikely(IS_ERR_OR_NULL(pkc_requested))) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ pkc_requested->type = pkc_req->type;
++ pkc_requested->curve_type = pkc_req->curve_type;
++ memcpy(&pkc_requested->req_u, &pkc_req->req_u, sizeof(pkc_req->req_u));
++ pkc_request_set_callback(pkc_requested, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ cryptodev_complete_asym, pkc);
++ ret = crypto_pkc_op(pkc_requested);
++ if (ret != -EINPROGRESS && ret != 0)
++ goto error2;
++
++ if (pkc->type == SYNCHRONOUS)
++ ret = waitfor(&pkc->result, ret);
++
++ return ret;
++error2:
++ kfree(pkc_requested);
++error:
++ crypto_free_pkc(pkc->s);
++ return ret;
++}
+diff --git a/cryptlib.h b/cryptlib.h
+index 4cb66ad..e77edc5 100644
+--- a/cryptlib.h
++++ b/cryptlib.h
+@@ -1,3 +1,6 @@
++/*
++ * Copyright 2012 Freescale Semiconductor, Inc.
++ */
+ #ifndef CRYPTLIB_H
+ # define CRYPTLIB_H
+
+@@ -89,5 +92,30 @@ void cryptodev_hash_deinit(struct hash_data *hdata);
+ int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name,
+ int hmac_mode, void *mackey, unsigned int mackeylen);
+
++/* Operation Type */
++enum offload_type {
++ SYNCHRONOUS,
++ ASYNCHRONOUS
++};
++
++struct cryptodev_result {
++ struct completion completion;
++ int err;
++};
++
++struct cryptodev_pkc {
++ struct list_head list; /* To maintain the Jobs in completed
++ cryptodev lists */
++ struct kernel_crypt_kop kop;
++ struct crypto_pkc *s; /* Transform pointer from CryptoAPI */
++ struct cryptodev_result result; /* Result to be updated by
++ completion handler */
++ struct pkc_request req; /* PKC request structure allocated
++ from CryptoAPI */
++ enum offload_type type; /* Synchronous Vs Asynchronous request */
++ void *cookie; /*Additional opaque cookie to be used in future */
++ struct crypt_priv *priv;
++};
+
++int cryptodev_pkc_offload(struct cryptodev_pkc *);
+ #endif
+diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
+index 3ea3d35..575ce63 100644
+--- a/crypto/cryptodev.h
++++ b/crypto/cryptodev.h
+@@ -1,6 +1,10 @@
+-/* This is a source compatible implementation with the original API of
++/*
++ * Copyright 2012 Freescale Semiconductor, Inc.
++ *
++ * This is a source compatible implementation with the original API of
+ * cryptodev by Angelos D. Keromytis, found at openbsd cryptodev.h.
+- * Placed under public domain */
++ * Placed under public domain
++ */
+
+ #ifndef L_CRYPTODEV_H
+ #define L_CRYPTODEV_H
+@@ -246,6 +250,9 @@ struct crypt_kop {
+ __u16 crk_oparams;
+ __u32 crk_pad1;
+ struct crparam crk_param[CRK_MAXPARAM];
++ enum curve_t curve_type; /* 0 == Discrete Log,
++ 1 = EC_PRIME, 2 = EC_BINARY */
++ void *cookie;
+ };
+
+ enum cryptodev_crk_op_t {
+@@ -290,5 +297,7 @@ enum cryptodev_crk_op_t {
+ */
+ #define CIOCASYNCCRYPT _IOW('c', 110, struct crypt_op)
+ #define CIOCASYNCFETCH _IOR('c', 111, struct crypt_op)
+-
++/* additional ioctls for asynchronous operation for asymmetric ciphers*/
++#define CIOCASYMASYNCRYPT _IOW('c', 112, struct crypt_kop)
++#define CIOCASYMASYNFETCH _IOR('c', 113, struct crypt_kop)
+ #endif /* L_CRYPTODEV_H */
+diff --git a/cryptodev_int.h b/cryptodev_int.h
+index 8891837..b08c253 100644
+--- a/cryptodev_int.h
++++ b/cryptodev_int.h
+@@ -1,4 +1,6 @@
+-/* cipher stuff */
++/* cipher stuff
++ * Copyright 2012 Freescale Semiconductor, Inc.
++ */
+ #ifndef CRYPTODEV_INT_H
+ # define CRYPTODEV_INT_H
+
+@@ -113,6 +115,14 @@ struct compat_crypt_auth_op {
+
+ #endif /* CONFIG_COMPAT */
+
++/* kernel-internal extension to struct crypt_kop */
++struct kernel_crypt_kop {
++ struct crypt_kop kop;
++
++ struct task_struct *task;
++ struct mm_struct *mm;
++};
++
+ /* kernel-internal extension to struct crypt_op */
+ struct kernel_crypt_op {
+ struct crypt_op cop;
+@@ -158,6 +168,14 @@ int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop);
+
+ #include <cryptlib.h>
+
++/* Cryptodev Key operation handler */
++int crypto_bn_modexp(struct cryptodev_pkc *);
++int crypto_modexp_crt(struct cryptodev_pkc *);
++int crypto_kop_dsasign(struct cryptodev_pkc *);
++int crypto_kop_dsaverify(struct cryptodev_pkc *);
++int crypto_run_asym(struct cryptodev_pkc *);
++void cryptodev_complete_asym(struct crypto_async_request *, int);
++
+ /* other internal structs */
+ struct csession {
+ struct list_head entry;
+diff --git a/ioctl.c b/ioctl.c
+index 63467e0..44070e1 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -4,6 +4,7 @@
+ * Copyright (c) 2004 Michal Ludvig <mludvig@logix.net.nz>, SuSE Labs
+ * Copyright (c) 2009,2010,2011 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ * Copyright (c) 2010 Phil Sutter
++ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This file is part of linux cryptodev.
+ *
+@@ -87,8 +88,37 @@ struct crypt_priv {
+ int itemcount;
+ struct work_struct cryptask;
+ wait_queue_head_t user_waiter;
++ /* List of pending cryptodev_pkc asym requests */
++ struct list_head asym_completed_list;
++ /* For addition/removal of entry in pending list of asymmetric request*/
++ spinlock_t completion_lock;
+ };
+
++/* Asymmetric request Completion handler */
++void cryptodev_complete_asym(struct crypto_async_request *req, int err)
++{
++ struct cryptodev_pkc *pkc = req->data;
++ struct cryptodev_result *res = &pkc->result;
++
++ crypto_free_pkc(pkc->s);
++ res->err = err;
++ if (pkc->type == SYNCHRONOUS) {
++ if (err == -EINPROGRESS)
++ return;
++ complete(&res->completion);
++ } else {
++ struct crypt_priv *pcr = pkc->priv;
++ unsigned long flags;
++ spin_lock_irqsave(&pcr->completion_lock, flags);
++ list_add_tail(&pkc->list, &pcr->asym_completed_list);
++ spin_unlock_irqrestore(&pcr->completion_lock, flags);
++ /* wake for POLLIN */
++ wake_up_interruptible(&pcr->user_waiter);
++ }
++
++ kfree(req);
++}
++
+ #define FILL_SG(sg, ptr, len) \
+ do { \
+ (sg)->page = virt_to_page(ptr); \
+@@ -467,7 +497,8 @@ cryptodev_open(struct inode *inode, struct file *filp)
+ INIT_LIST_HEAD(&pcr->free.list);
+ INIT_LIST_HEAD(&pcr->todo.list);
+ INIT_LIST_HEAD(&pcr->done.list);
+-
++ INIT_LIST_HEAD(&pcr->asym_completed_list);
++ spin_lock_init(&pcr->completion_lock);
+ INIT_WORK(&pcr->cryptask, cryptask_routine);
+
+ init_waitqueue_head(&pcr->user_waiter);
+@@ -634,6 +665,79 @@ static int crypto_async_fetch(struct crypt_priv *pcr,
+ }
+ #endif
+
++/* get the first asym cipher completed job from the "done" queue
++ *
++ * returns:
++ * -EBUSY if no completed jobs are ready (yet)
++ * the return value otherwise */
++static int crypto_async_fetch_asym(struct cryptodev_pkc *pkc)
++{
++ int ret = 0;
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *ckop = &kop->kop;
++ struct pkc_request *pkc_req = &pkc->req;
++
++ switch (ckop->crk_op) {
++ case CRK_MOD_EXP:
++ {
++ struct rsa_pub_req_s *rsa_req = &pkc_req->req_u.rsa_pub_req;
++ copy_to_user(ckop->crk_param[3].crp_p, rsa_req->g,
++ rsa_req->g_len);
++ }
++ break;
++ case CRK_MOD_EXP_CRT:
++ {
++ struct rsa_priv_frm3_req_s *rsa_req =
++ &pkc_req->req_u.rsa_priv_f3;
++ copy_to_user(ckop->crk_param[6].crp_p,
++ rsa_req->f, rsa_req->f_len);
++ }
++ break;
++ case CRK_DSA_SIGN:
++ {
++ struct dsa_sign_req_s *dsa_req = &pkc_req->req_u.dsa_sign;
++
++ if (pkc_req->type == ECDSA_SIGN) {
++ copy_to_user(ckop->crk_param[6].crp_p,
++ dsa_req->c, dsa_req->d_len);
++ copy_to_user(ckop->crk_param[7].crp_p,
++ dsa_req->d, dsa_req->d_len);
++ } else {
++ copy_to_user(ckop->crk_param[5].crp_p,
++ dsa_req->c, dsa_req->d_len);
++ copy_to_user(ckop->crk_param[6].crp_p,
++ dsa_req->d, dsa_req->d_len);
++ }
++ }
++ break;
++ case CRK_DSA_VERIFY:
++ break;
++ case CRK_DH_COMPUTE_KEY:
++ {
++ struct dh_key_req_s *dh_req = &pkc_req->req_u.dh_req;
++ if (pkc_req->type == ECDH_COMPUTE_KEY)
++ copy_to_user(ckop->crk_param[4].crp_p,
++ dh_req->z, dh_req->z_len);
++ else
++ copy_to_user(ckop->crk_param[3].crp_p,
++ dh_req->z, dh_req->z_len);
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ kfree(pkc->cookie);
++ return ret;
++}
++
++/* this function has to be called from process context */
++static int fill_kop_from_cop(struct kernel_crypt_kop *kop)
++{
++ kop->task = current;
++ kop->mm = current->mm;
++ return 0;
++}
++
+ /* this function has to be called from process context */
+ static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
+ {
+@@ -657,11 +761,8 @@ static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
+
+ if (cop->iv) {
+ rc = copy_from_user(kcop->iv, cop->iv, kcop->ivlen);
+- if (unlikely(rc)) {
+- derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p",
+- kcop->ivlen, rc, cop->iv);
++ if (unlikely(rc))
+ return -EFAULT;
+- }
+ }
+
+ return 0;
+@@ -687,6 +788,25 @@ static int fill_cop_from_kcop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
+ return 0;
+ }
+
++static int kop_from_user(struct kernel_crypt_kop *kop,
++ void __user *arg)
++{
++ if (unlikely(copy_from_user(&kop->kop, arg, sizeof(kop->kop))))
++ return -EFAULT;
++
++ return fill_kop_from_cop(kop);
++}
++
++static int kop_to_user(struct kernel_crypt_kop *kop,
++ void __user *arg)
++{
++ if (unlikely(copy_to_user(arg, &kop->kop, sizeof(kop->kop)))) {
++ dprintk(1, KERN_ERR, "Cannot copy to userspace\n");
++ return -EFAULT;
++ }
++ return 0;
++}
++
+ static int kcop_from_user(struct kernel_crypt_op *kcop,
+ struct fcrypt *fcr, void __user *arg)
+ {
+@@ -816,7 +936,8 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+
+ switch (cmd) {
+ case CIOCASYMFEAT:
+- return put_user(0, p);
++ return put_user(CRF_MOD_EXP_CRT | CRF_MOD_EXP |
++ CRF_DSA_SIGN | CRF_DSA_VERIFY | CRF_DH_COMPUTE_KEY, p);
+ case CRIOGET:
+ fd = clonefd(filp);
+ ret = put_user(fd, p);
+@@ -852,6 +973,24 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ if (unlikely(ret))
+ return ret;
+ return copy_to_user(arg, &siop, sizeof(siop));
++ case CIOCKEY:
++ {
++ struct cryptodev_pkc *pkc =
++ kzalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
++
++ if (!pkc)
++ return -ENOMEM;
++
++ ret = kop_from_user(&pkc->kop, arg);
++ if (unlikely(ret)) {
++ kfree(pkc);
++ return ret;
++ }
++ pkc->type = SYNCHRONOUS;
++ ret = crypto_run_asym(pkc);
++ kfree(pkc);
++ }
++ return ret;
+ case CIOCCRYPT:
+ if (unlikely(ret = kcop_from_user(&kcop, fcr, arg))) {
+ dwarning(1, "Error copying from user");
+@@ -890,6 +1029,45 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+
+ return kcop_to_user(&kcop, fcr, arg);
+ #endif
++ case CIOCASYMASYNCRYPT:
++ {
++ struct cryptodev_pkc *pkc =
++ kzalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
++ ret = kop_from_user(&pkc->kop, arg);
++
++ if (unlikely(ret))
++ return -EINVAL;
++
++ /* Store associated FD priv data with asymmetric request */
++ pkc->priv = pcr;
++ pkc->type = ASYNCHRONOUS;
++ ret = crypto_run_asym(pkc);
++ if (ret == -EINPROGRESS)
++ ret = 0;
++ }
++ return ret;
++ case CIOCASYMASYNFETCH:
++ {
++ struct cryptodev_pkc *pkc;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcr->completion_lock, flags);
++ if (list_empty(&pcr->asym_completed_list)) {
++ spin_unlock_irqrestore(&pcr->completion_lock, flags);
++ return -ENOMEM;
++ }
++ pkc = list_first_entry(&pcr->asym_completed_list,
++ struct cryptodev_pkc, list);
++ list_del(&pkc->list);
++ spin_unlock_irqrestore(&pcr->completion_lock, flags);
++ ret = crypto_async_fetch_asym(pkc);
++
++ /* Reflect the updated request to user-space */
++ if (!ret)
++ kop_to_user(&pkc->kop, arg);
++ kfree(pkc);
++ }
++ return ret;
+ default:
+ return -EINVAL;
+ }
+@@ -1078,9 +1256,11 @@ static unsigned int cryptodev_poll(struct file *file, poll_table *wait)
+
+ poll_wait(file, &pcr->user_waiter, wait);
+
+- if (!list_empty_careful(&pcr->done.list))
++ if (!list_empty_careful(&pcr->done.list) ||
++ !list_empty_careful(&pcr->asym_completed_list))
+ ret |= POLLIN | POLLRDNORM;
+- if (!list_empty_careful(&pcr->free.list) || pcr->itemcount < MAX_COP_RINGSIZE)
++ if (!list_empty_careful(&pcr->free.list) ||
++ pcr->itemcount < MAX_COP_RINGSIZE)
+ ret |= POLLOUT | POLLWRNORM;
+
+ return ret;
+diff --git a/main.c b/main.c
+index 57e5c38..0b7951e 100644
+--- a/main.c
++++ b/main.c
+@@ -181,6 +181,384 @@ __crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop)
+ return ret;
+ }
+
++int crypto_kop_dsasign(struct cryptodev_pkc *pkc)
++{
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *cop = &kop->kop;
++ struct pkc_request *pkc_req = &pkc->req;
++ struct dsa_sign_req_s *dsa_req = &pkc_req->req_u.dsa_sign;
++ int rc, buf_size;
++ uint8_t *buf;
++
++ if (!cop->crk_param[0].crp_nbits || !cop->crk_param[1].crp_nbits ||
++ !cop->crk_param[2].crp_nbits || !cop->crk_param[3].crp_nbits ||
++ !cop->crk_param[4].crp_nbits || !cop->crk_param[5].crp_nbits ||
++ !cop->crk_param[6].crp_nbits || (cop->crk_iparams == 6 &&
++ !cop->crk_param[7].crp_nbits))
++ return -EINVAL;
++
++ dsa_req->m_len = (cop->crk_param[0].crp_nbits + 7)/8;
++ dsa_req->q_len = (cop->crk_param[1].crp_nbits + 7)/8;
++ dsa_req->r_len = (cop->crk_param[2].crp_nbits + 7)/8;
++ dsa_req->g_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ dsa_req->priv_key_len = (cop->crk_param[4].crp_nbits + 7)/8;
++ dsa_req->d_len = (cop->crk_param[6].crp_nbits + 7)/8;
++ buf_size = dsa_req->m_len + dsa_req->q_len + dsa_req->r_len +
++ dsa_req->g_len + dsa_req->priv_key_len + dsa_req->d_len +
++ dsa_req->d_len;
++ if (cop->crk_iparams == 6) {
++ dsa_req->ab_len = (cop->crk_param[5].crp_nbits + 7)/8;
++ buf_size += dsa_req->ab_len;
++ pkc_req->type = ECDSA_SIGN;
++ pkc_req->curve_type = cop->curve_type;
++ } else {
++ pkc_req->type = DSA_SIGN;
++ }
++
++ buf = kzalloc(buf_size, GFP_DMA);
++
++ dsa_req->q = buf;
++ dsa_req->r = dsa_req->q + dsa_req->q_len;
++ dsa_req->g = dsa_req->r + dsa_req->r_len;
++ dsa_req->priv_key = dsa_req->g + dsa_req->g_len;
++ dsa_req->m = dsa_req->priv_key + dsa_req->priv_key_len;
++ dsa_req->c = dsa_req->m + dsa_req->m_len;
++ dsa_req->d = dsa_req->c + dsa_req->d_len;
++ copy_from_user(dsa_req->m, cop->crk_param[0].crp_p, dsa_req->m_len);
++ copy_from_user(dsa_req->q, cop->crk_param[1].crp_p, dsa_req->q_len);
++ copy_from_user(dsa_req->r, cop->crk_param[2].crp_p, dsa_req->r_len);
++ copy_from_user(dsa_req->g, cop->crk_param[3].crp_p, dsa_req->g_len);
++ copy_from_user(dsa_req->priv_key, cop->crk_param[4].crp_p,
++ dsa_req->priv_key_len);
++ if (cop->crk_iparams == 6) {
++ dsa_req->ab = dsa_req->d + dsa_req->d_len;
++ copy_from_user(dsa_req->ab, cop->crk_param[5].crp_p,
++ dsa_req->ab_len);
++ }
++ rc = cryptodev_pkc_offload(pkc);
++ if (pkc->type == SYNCHRONOUS) {
++ if (rc)
++ goto err;
++ if (cop->crk_iparams == 6) {
++ copy_to_user(cop->crk_param[6].crp_p, dsa_req->c,
++ dsa_req->d_len);
++ copy_to_user(cop->crk_param[7].crp_p, dsa_req->d,
++ dsa_req->d_len);
++ } else {
++ copy_to_user(cop->crk_param[5].crp_p, dsa_req->c,
++ dsa_req->d_len);
++ copy_to_user(cop->crk_param[6].crp_p, dsa_req->d,
++ dsa_req->d_len);
++ }
++ } else {
++ if (rc != -EINPROGRESS && rc != 0)
++ goto err;
++
++ pkc->cookie = buf;
++ return rc;
++ }
++err:
++ kfree(buf);
++ return rc;
++}
++
++int crypto_kop_dsaverify(struct cryptodev_pkc *pkc)
++{
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *cop = &kop->kop;
++ struct pkc_request *pkc_req;
++ struct dsa_verify_req_s *dsa_req;
++ int rc, buf_size;
++ uint8_t *buf;
++
++ if (!cop->crk_param[0].crp_nbits || !cop->crk_param[1].crp_nbits ||
++ !cop->crk_param[2].crp_nbits || !cop->crk_param[3].crp_nbits ||
++ !cop->crk_param[4].crp_nbits || !cop->crk_param[5].crp_nbits ||
++ !cop->crk_param[6].crp_nbits || (cop->crk_iparams == 8 &&
++ !cop->crk_param[7].crp_nbits))
++ return -EINVAL;
++
++ pkc_req = &pkc->req;
++ dsa_req = &pkc_req->req_u.dsa_verify;
++ dsa_req->m_len = (cop->crk_param[0].crp_nbits + 7)/8;
++ dsa_req->q_len = (cop->crk_param[1].crp_nbits + 7)/8;
++ dsa_req->r_len = (cop->crk_param[2].crp_nbits + 7)/8;
++ dsa_req->g_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ dsa_req->pub_key_len = (cop->crk_param[4].crp_nbits + 7)/8;
++ dsa_req->d_len = (cop->crk_param[6].crp_nbits + 7)/8;
++ buf_size = dsa_req->m_len + dsa_req->q_len + dsa_req->r_len +
++ dsa_req->g_len + dsa_req->pub_key_len + dsa_req->d_len +
++ dsa_req->d_len;
++ if (cop->crk_iparams == 8) {
++ dsa_req->ab_len = (cop->crk_param[5].crp_nbits + 7)/8;
++ buf_size += dsa_req->ab_len;
++ pkc_req->type = ECDSA_VERIFY;
++ pkc_req->curve_type = cop->curve_type;
++ } else {
++ pkc_req->type = DSA_VERIFY;
++ }
++
++ buf = kzalloc(buf_size, GFP_DMA);
++
++ dsa_req->q = buf;
++ dsa_req->r = dsa_req->q + dsa_req->q_len;
++ dsa_req->g = dsa_req->r + dsa_req->r_len;
++ dsa_req->pub_key = dsa_req->g + dsa_req->g_len;
++ dsa_req->m = dsa_req->pub_key + dsa_req->pub_key_len;
++ dsa_req->c = dsa_req->m + dsa_req->m_len;
++ dsa_req->d = dsa_req->c + dsa_req->d_len;
++ copy_from_user(dsa_req->m, cop->crk_param[0].crp_p, dsa_req->m_len);
++ copy_from_user(dsa_req->q, cop->crk_param[1].crp_p, dsa_req->q_len);
++ copy_from_user(dsa_req->r, cop->crk_param[2].crp_p, dsa_req->r_len);
++ copy_from_user(dsa_req->g, cop->crk_param[3].crp_p, dsa_req->g_len);
++ copy_from_user(dsa_req->pub_key, cop->crk_param[4].crp_p,
++ dsa_req->pub_key_len);
++ if (cop->crk_iparams == 8) {
++ dsa_req->ab = dsa_req->d + dsa_req->d_len;
++ copy_from_user(dsa_req->ab, cop->crk_param[5].crp_p,
++ dsa_req->ab_len);
++ copy_from_user(dsa_req->c, cop->crk_param[6].crp_p,
++ dsa_req->d_len);
++ copy_from_user(dsa_req->d, cop->crk_param[7].crp_p,
++ dsa_req->d_len);
++ } else {
++ copy_from_user(dsa_req->c, cop->crk_param[5].crp_p,
++ dsa_req->d_len);
++ copy_from_user(dsa_req->d, cop->crk_param[6].crp_p,
++ dsa_req->d_len);
++ }
++ rc = cryptodev_pkc_offload(pkc);
++ if (pkc->type == SYNCHRONOUS) {
++ if (rc)
++ goto err;
++ } else {
++ if (rc != -EINPROGRESS && !rc)
++ goto err;
++ pkc->cookie = buf;
++ return rc;
++ }
++err:
++ kfree(buf);
++ return rc;
++}
++
++int crypto_kop_dh_key(struct cryptodev_pkc *pkc)
++{
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *cop = &kop->kop;
++ struct pkc_request *pkc_req;
++ struct dh_key_req_s *dh_req;
++ int buf_size;
++ uint8_t *buf;
++ int rc = -EINVAL;
++
++ pkc_req = &pkc->req;
++ dh_req = &pkc_req->req_u.dh_req;
++ dh_req->s_len = (cop->crk_param[0].crp_nbits + 7)/8;
++ dh_req->pub_key_len = (cop->crk_param[1].crp_nbits + 7)/8;
++ dh_req->q_len = (cop->crk_param[2].crp_nbits + 7)/8;
++ buf_size = dh_req->q_len + dh_req->pub_key_len + dh_req->s_len;
++ if (cop->crk_iparams == 4) {
++ pkc_req->type = ECDH_COMPUTE_KEY;
++ dh_req->ab_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ dh_req->z_len = (cop->crk_param[4].crp_nbits + 7)/8;
++ buf_size += dh_req->ab_len;
++ } else {
++ dh_req->z_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ pkc_req->type = DH_COMPUTE_KEY;
++ }
++ buf_size += dh_req->z_len;
++ buf = kzalloc(buf_size, GFP_DMA);
++ dh_req->q = buf;
++ dh_req->s = dh_req->q + dh_req->q_len;
++ dh_req->pub_key = dh_req->s + dh_req->s_len;
++ dh_req->z = dh_req->pub_key + dh_req->pub_key_len;
++ if (cop->crk_iparams == 4) {
++ dh_req->ab = dh_req->z + dh_req->z_len;
++ pkc_req->curve_type = cop->curve_type;
++ copy_from_user(dh_req->ab, cop->crk_param[3].crp_p,
++ dh_req->ab_len);
++ }
++ copy_from_user(dh_req->s, cop->crk_param[0].crp_p, dh_req->s_len);
++ copy_from_user(dh_req->pub_key, cop->crk_param[1].crp_p,
++ dh_req->pub_key_len);
++ copy_from_user(dh_req->q, cop->crk_param[2].crp_p, dh_req->q_len);
++ rc = cryptodev_pkc_offload(pkc);
++ if (pkc->type == SYNCHRONOUS) {
++ if (rc)
++ goto err;
++ if (cop->crk_iparams == 4)
++ copy_to_user(cop->crk_param[4].crp_p, dh_req->z,
++ dh_req->z_len);
++ else
++ copy_to_user(cop->crk_param[3].crp_p, dh_req->z,
++ dh_req->z_len);
++ } else {
++ if (rc != -EINPROGRESS && rc != 0)
++ goto err;
++
++ pkc->cookie = buf;
++ return rc;
++ }
++err:
++ kfree(buf);
++ return rc;
++}
++
++int crypto_modexp_crt(struct cryptodev_pkc *pkc)
++{
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *cop = &kop->kop;
++ struct pkc_request *pkc_req;
++ struct rsa_priv_frm3_req_s *rsa_req;
++ int rc;
++ uint8_t *buf;
++
++ if (!cop->crk_param[0].crp_nbits || !cop->crk_param[1].crp_nbits ||
++ !cop->crk_param[2].crp_nbits || !cop->crk_param[3].crp_nbits ||
++ !cop->crk_param[4].crp_nbits || !cop->crk_param[5].crp_nbits)
++ return -EINVAL;
++
++ pkc_req = &pkc->req;
++ pkc_req->type = RSA_PRIV_FORM3;
++ rsa_req = &pkc_req->req_u.rsa_priv_f3;
++ rsa_req->p_len = (cop->crk_param[0].crp_nbits + 7)/8;
++ rsa_req->q_len = (cop->crk_param[1].crp_nbits + 7)/8;
++ rsa_req->g_len = (cop->crk_param[2].crp_nbits + 7)/8;
++ rsa_req->dp_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ rsa_req->dq_len = (cop->crk_param[4].crp_nbits + 7)/8;
++ rsa_req->c_len = (cop->crk_param[5].crp_nbits + 7)/8;
++ rsa_req->f_len = (cop->crk_param[6].crp_nbits + 7)/8;
++ buf = kzalloc(rsa_req->p_len + rsa_req->q_len + rsa_req->f_len +
++ rsa_req->dp_len + rsa_req->dp_len + rsa_req->c_len +
++ rsa_req->g_len, GFP_DMA);
++ rsa_req->p = buf;
++ rsa_req->q = rsa_req->p + rsa_req->p_len;
++ rsa_req->g = rsa_req->q + rsa_req->q_len;
++ rsa_req->dp = rsa_req->g + rsa_req->g_len;
++ rsa_req->dq = rsa_req->dp + rsa_req->dp_len;
++ rsa_req->c = rsa_req->dq + rsa_req->dq_len;
++ rsa_req->f = rsa_req->c + rsa_req->c_len;
++ copy_from_user(rsa_req->p, cop->crk_param[0].crp_p, rsa_req->p_len);
++ copy_from_user(rsa_req->q, cop->crk_param[1].crp_p, rsa_req->q_len);
++ copy_from_user(rsa_req->g, cop->crk_param[2].crp_p, rsa_req->g_len);
++ copy_from_user(rsa_req->dp, cop->crk_param[3].crp_p, rsa_req->dp_len);
++ copy_from_user(rsa_req->dq, cop->crk_param[4].crp_p, rsa_req->dq_len);
++ copy_from_user(rsa_req->c, cop->crk_param[5].crp_p, rsa_req->c_len);
++ rc = cryptodev_pkc_offload(pkc);
++
++ if (pkc->type == SYNCHRONOUS) {
++ if (rc)
++ goto err;
++ copy_to_user(cop->crk_param[6].crp_p, rsa_req->f,
++ rsa_req->f_len);
++ } else {
++ if (rc != -EINPROGRESS && rc != 0)
++ goto err;
++
++ pkc->cookie = buf;
++ return rc;
++ }
++err:
++ kfree(buf);
++ return rc;
++}
++
++int crypto_bn_modexp(struct cryptodev_pkc *pkc)
++{
++ struct pkc_request *pkc_req;
++ struct rsa_pub_req_s *rsa_req;
++ int rc;
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *cop = &kop->kop;
++ uint8_t *buf;
++
++ if (!cop->crk_param[0].crp_nbits || !cop->crk_param[1].crp_nbits ||
++ !cop->crk_param[2].crp_nbits || !cop->crk_param[3].crp_nbits)
++ return -EINVAL;
++
++ pkc_req = &pkc->req;
++ pkc_req->type = RSA_PUB;
++ rsa_req = &pkc_req->req_u.rsa_pub_req;
++ rsa_req->f_len = (cop->crk_param[0].crp_nbits + 7)/8;
++ rsa_req->e_len = (cop->crk_param[1].crp_nbits + 7)/8;
++ rsa_req->n_len = (cop->crk_param[2].crp_nbits + 7)/8;
++ rsa_req->g_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ buf = kzalloc(rsa_req->f_len + rsa_req->e_len + rsa_req->n_len
++ + rsa_req->g_len, GFP_DMA);
++ if (!buf)
++ return -ENOMEM;
++
++ rsa_req->e = buf;
++ rsa_req->f = rsa_req->e + rsa_req->e_len;
++ rsa_req->g = rsa_req->f + rsa_req->f_len;
++ rsa_req->n = rsa_req->g + rsa_req->g_len;
++ copy_from_user(rsa_req->f, cop->crk_param[0].crp_p, rsa_req->f_len);
++ copy_from_user(rsa_req->e, cop->crk_param[1].crp_p, rsa_req->e_len);
++ copy_from_user(rsa_req->n, cop->crk_param[2].crp_p, rsa_req->n_len);
++ rc = cryptodev_pkc_offload(pkc);
++ if (pkc->type == SYNCHRONOUS) {
++ if (rc)
++ goto err;
++
++ copy_to_user(cop->crk_param[3].crp_p, rsa_req->g,
++ rsa_req->g_len);
++ } else {
++ if (rc != -EINPROGRESS && rc != 0)
++ goto err;
++
++ /* This one will be freed later in fetch handler */
++ pkc->cookie = buf;
++ return rc;
++ }
++err:
++ kfree(buf);
++ return rc;
++}
++
++int crypto_run_asym(struct cryptodev_pkc *pkc)
++{
++ int ret = -EINVAL;
++ struct kernel_crypt_kop *kop = &pkc->kop;
++
++ switch (kop->kop.crk_op) {
++ case CRK_MOD_EXP:
++ if (kop->kop.crk_iparams != 3 && kop->kop.crk_oparams != 1)
++ goto err;
++
++ ret = crypto_bn_modexp(pkc);
++ break;
++ case CRK_MOD_EXP_CRT:
++ if (kop->kop.crk_iparams != 6 && kop->kop.crk_oparams != 1)
++ goto err;
++
++ ret = crypto_modexp_crt(pkc);
++ break;
++ case CRK_DSA_SIGN:
++ if ((kop->kop.crk_iparams != 5 && kop->kop.crk_iparams != 6) ||
++ kop->kop.crk_oparams != 2)
++ goto err;
++
++ ret = crypto_kop_dsasign(pkc);
++ break;
++ case CRK_DSA_VERIFY:
++ if ((kop->kop.crk_iparams != 7 && kop->kop.crk_iparams != 8) ||
++ kop->kop.crk_oparams != 0)
++ goto err;
++
++ ret = crypto_kop_dsaverify(pkc);
++ break;
++ case CRK_DH_COMPUTE_KEY:
++ if ((kop->kop.crk_iparams != 3 && kop->kop.crk_iparams != 4) ||
++ kop->kop.crk_oparams != 1)
++ goto err;
++ ret = crypto_kop_dh_key(pkc);
++ break;
++ }
++err:
++ return ret;
++}
++
+ int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop)
+ {
+ struct csession *ses_ptr;
+--
+1.7.9.7
+
--- /dev/null
+From f6550035fe2c0e66798ace17d31d1d880beacc14 Mon Sep 17 00:00:00 2001
+From: Yashpal Dutta <yashpal.dutta@freescale.com>
+Date: Fri, 7 Mar 2014 06:52:13 +0545
+Subject: [[Patch][fsl 10/16] Compat versions of PKC IOCTLs
+
+Upstream-status: Pending
+
+Signed-off-by: Yashpal Dutta <yashpal.dutta@freescale.com>
+---
+ cryptodev_int.h | 20 ++++++++++
+ ioctl.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 140 insertions(+)
+
+diff --git a/cryptodev_int.h b/cryptodev_int.h
+index b08c253..229fcd0 100644
+--- a/cryptodev_int.h
++++ b/cryptodev_int.h
+@@ -75,6 +75,24 @@ struct compat_crypt_op {
+ compat_uptr_t iv;/* initialization vector for encryption operations */
+ };
+
++/* input of CIOCKEY */
++struct compat_crparam {
++ compat_uptr_t crp_p;
++ uint32_t crp_nbits;
++};
++
++struct compat_crypt_kop {
++ uint32_t crk_op; /* cryptodev_crk_ot_t */
++ uint32_t crk_status;
++ uint16_t crk_iparams;
++ uint16_t crk_oparams;
++ uint32_t crk_pad1;
++ struct compat_crparam crk_param[CRK_MAXPARAM];
++ enum curve_t curve_type; /* 0 == Discrete Log, 1 = EC_PRIME,
++ 2 = EC_BINARY */
++ compat_uptr_t cookie;
++};
++
+ /* input of CIOCAUTHCRYPT */
+ struct compat_crypt_auth_op {
+ uint32_t ses; /* session identifier */
+@@ -112,6 +130,8 @@ struct compat_crypt_auth_op {
+ #define COMPAT_CIOCASYNCCRYPT _IOW('c', 107, struct compat_crypt_op)
+ #define COMPAT_CIOCASYNCFETCH _IOR('c', 108, struct compat_crypt_op)
+ #define COMPAT_CIOCAUTHCRYPT _IOWR('c', 109, struct compat_crypt_auth_op)
++#define COMPAT_CIOCASYMASYNCRYPT _IOW('c', 110, struct compat_crypt_kop)
++#define COMPAT_CIOCASYMASYNFETCH _IOR('c', 111, struct compat_crypt_kop)
+
+ #endif /* CONFIG_COMPAT */
+
+diff --git a/ioctl.c b/ioctl.c
+index 44070e1..ec82c69 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -1076,6 +1076,68 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ /* compatibility code for 32bit userlands */
+ #ifdef CONFIG_COMPAT
+
++static inline void compat_to_crypt_kop(struct compat_crypt_kop *compat,
++ struct crypt_kop *kop)
++{
++ int i;
++ kop->crk_op = compat->crk_op;
++ kop->crk_status = compat->crk_status;
++ kop->crk_iparams = compat->crk_iparams;
++ kop->crk_oparams = compat->crk_oparams;
++
++ for (i = 0; i < CRK_MAXPARAM; i++) {
++ kop->crk_param[i].crp_p =
++ compat_ptr(compat->crk_param[i].crp_p);
++ kop->crk_param[i].crp_nbits = compat->crk_param[i].crp_nbits;
++ }
++
++ kop->curve_type = compat->curve_type;
++ kop->cookie = compat->cookie;
++}
++
++static int compat_kop_from_user(struct kernel_crypt_kop *kop,
++ void __user *arg)
++{
++ struct compat_crypt_kop compat_kop;
++
++ if (unlikely(copy_from_user(&compat_kop, arg, sizeof(compat_kop))))
++ return -EFAULT;
++
++ compat_to_crypt_kop(&compat_kop, &kop->kop);
++ return fill_kop_from_cop(kop);
++}
++
++static inline void crypt_kop_to_compat(struct crypt_kop *kop,
++ struct compat_crypt_kop *compat)
++{
++ int i;
++
++ compat->crk_op = kop->crk_op;
++ compat->crk_status = kop->crk_status;
++ compat->crk_iparams = kop->crk_iparams;
++ compat->crk_oparams = kop->crk_oparams;
++
++ for (i = 0; i < CRK_MAXPARAM; i++) {
++ compat->crk_param[i].crp_p =
++ ptr_to_compat(kop->crk_param[i].crp_p);
++ compat->crk_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
++ }
++ compat->cookie = kop->cookie;
++ compat->curve_type = kop->curve_type;
++}
++
++static int compat_kop_to_user(struct kernel_crypt_kop *kop, void __user *arg)
++{
++ struct compat_crypt_kop compat_kop;
++
++ crypt_kop_to_compat(&kop->kop, &compat_kop);
++ if (unlikely(copy_to_user(arg, &compat_kop, sizeof(compat_kop)))) {
++ dprintk(1, KERN_ERR, "Cannot copy to userspace\n");
++ return -EFAULT;
++ }
++ return 0;
++}
++
+ static inline void
+ compat_to_session_op(struct compat_session_op *compat, struct session_op *sop)
+ {
+@@ -1203,7 +1265,26 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+ return -EFAULT;
+ }
+ return ret;
++ case COMPAT_CIOCKEY:
++ {
++ struct cryptodev_pkc *pkc =
++ kzalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
++
++ if (!pkc)
++ return -ENOMEM;
++
++ ret = compat_kop_from_user(&pkc->kop, arg);
++
++ if (unlikely(ret)) {
++ kfree(pkc);
++ return ret;
++ }
+
++ pkc->type = SYNCHRONOUS;
++ ret = crypto_run_asym(pkc);
++ kfree(pkc);
++ }
++ return ret;
+ case COMPAT_CIOCCRYPT:
+ ret = compat_kcop_from_user(&kcop, fcr, arg);
+ if (unlikely(ret))
+@@ -1242,6 +1323,45 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+
+ return compat_kcop_to_user(&kcop, fcr, arg);
+ #endif
++ case COMPAT_CIOCASYMASYNCRYPT:
++ {
++ struct cryptodev_pkc *pkc =
++ kzalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
++
++ ret = compat_kop_from_user(&pkc->kop, arg);
++ if (unlikely(ret))
++ return -EINVAL;
++
++ /* Store associated FD priv data with asymmetric request */
++ pkc->priv = pcr;
++ pkc->type = ASYNCHRONOUS;
++ ret = crypto_run_asym(pkc);
++ if (ret == -EINPROGRESS)
++ ret = 0;
++ }
++ return ret;
++ case COMPAT_CIOCASYMASYNFETCH:
++ {
++ struct cryptodev_pkc *pkc;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcr->completion_lock, flags);
++ if (list_empty(&pcr->asym_completed_list)) {
++ spin_unlock_irqrestore(&pcr->completion_lock, flags);
++ return -ENOMEM;
++ }
++ pkc = list_first_entry(&pcr->asym_completed_list,
++ struct cryptodev_pkc, list);
++ list_del(&pkc->list);
++ spin_unlock_irqrestore(&pcr->completion_lock, flags);
++ ret = crypto_async_fetch_asym(pkc);
++
++ /* Reflect the updated request to user-space */
++ if (!ret)
++ compat_kop_to_user(&pkc->kop, arg);
++ kfree(pkc);
++ }
++ return ret;
+ default:
+ return -EINVAL;
+ }
+--
+1.7.9.7
+
--- /dev/null
+From ffa8fd090afaf3631e6abd0ab8daa6780be7c31c Mon Sep 17 00:00:00 2001
+From: Yashpal Dutta <yashpal.dutta@freescale.com>
+Date: Fri, 7 Mar 2014 07:24:00 +0545
+Subject: [[Patch][fsl 11/16] Asynchronous interface changes in cryptodev
+
+Upstream-status: Pending
+
+Signed-off-by: Yashpal Dutta <yashpal.dutta@freescale.com>
+---
+ cryptlib.h | 7 ++++-
+ crypto/cryptodev.h | 10 ++++++-
+ cryptodev_int.h | 10 ++++++-
+ ioctl.c | 76 +++++++++++++++++++++++++++++++++++-----------------
+ 4 files changed, 76 insertions(+), 27 deletions(-)
+
+diff --git a/cryptlib.h b/cryptlib.h
+index e77edc5..947d845 100644
+--- a/cryptlib.h
++++ b/cryptlib.h
+@@ -113,7 +113,12 @@ struct cryptodev_pkc {
+ struct pkc_request req; /* PKC request structure allocated
+ from CryptoAPI */
+ enum offload_type type; /* Synchronous Vs Asynchronous request */
+- void *cookie; /*Additional opaque cookie to be used in future */
++ /*
++ * cookie used for transfering tranparent information from async
++ * submission to async fetch. Currently some dynamic allocated
++ * buffers are maintained which will be freed later during fetch
++ */
++ void *cookie;
+ struct crypt_priv *priv;
+ };
+
+diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
+index 575ce63..0d65899 100644
+--- a/crypto/cryptodev.h
++++ b/crypto/cryptodev.h
+@@ -255,6 +255,14 @@ struct crypt_kop {
+ void *cookie;
+ };
+
++#define MAX_COOKIES 4
++
++struct pkc_cookie_list_s {
++ int cookie_available;
++ void *cookie[MAX_COOKIES];
++ int status[MAX_COOKIES];
++};
++
+ enum cryptodev_crk_op_t {
+ CRK_MOD_EXP = 0,
+ CRK_MOD_EXP_CRT = 1,
+@@ -299,5 +307,5 @@ enum cryptodev_crk_op_t {
+ #define CIOCASYNCFETCH _IOR('c', 111, struct crypt_op)
+ /* additional ioctls for asynchronous operation for asymmetric ciphers*/
+ #define CIOCASYMASYNCRYPT _IOW('c', 112, struct crypt_kop)
+-#define CIOCASYMASYNFETCH _IOR('c', 113, struct crypt_kop)
++#define CIOCASYMFETCHCOOKIE _IOR('c', 113, struct pkc_cookie_list_s)
+ #endif /* L_CRYPTODEV_H */
+diff --git a/cryptodev_int.h b/cryptodev_int.h
+index 229fcd0..8beeef0 100644
+--- a/cryptodev_int.h
++++ b/cryptodev_int.h
+@@ -93,6 +93,12 @@ struct compat_crypt_kop {
+ compat_uptr_t cookie;
+ };
+
++struct compat_pkc_cookie_list_s {
++ int cookie_available;
++ compat_uptr_t cookie[MAX_COOKIES];
++ int status[MAX_COOKIES];
++};
++
+ /* input of CIOCAUTHCRYPT */
+ struct compat_crypt_auth_op {
+ uint32_t ses; /* session identifier */
+@@ -127,11 +133,13 @@ struct compat_crypt_auth_op {
+ /* compat ioctls, defined for the above structs */
+ #define COMPAT_CIOCGSESSION _IOWR('c', 102, struct compat_session_op)
+ #define COMPAT_CIOCCRYPT _IOWR('c', 104, struct compat_crypt_op)
++#define COMPAT_CIOCKEY _IOW('c', 105, struct compat_crypt_kop)
+ #define COMPAT_CIOCASYNCCRYPT _IOW('c', 107, struct compat_crypt_op)
+ #define COMPAT_CIOCASYNCFETCH _IOR('c', 108, struct compat_crypt_op)
+ #define COMPAT_CIOCAUTHCRYPT _IOWR('c', 109, struct compat_crypt_auth_op)
+ #define COMPAT_CIOCASYMASYNCRYPT _IOW('c', 110, struct compat_crypt_kop)
+-#define COMPAT_CIOCASYMASYNFETCH _IOR('c', 111, struct compat_crypt_kop)
++#define COMPAT_CIOCASYMFETCHCOOKIE _IOR('c', 111, \
++ struct compat_pkc_cookie_list_s)
+
+ #endif /* CONFIG_COMPAT */
+
+diff --git a/ioctl.c b/ioctl.c
+index ec82c69..9f57d46 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -103,8 +103,6 @@ void cryptodev_complete_asym(struct crypto_async_request *req, int err)
+ crypto_free_pkc(pkc->s);
+ res->err = err;
+ if (pkc->type == SYNCHRONOUS) {
+- if (err == -EINPROGRESS)
+- return;
+ complete(&res->completion);
+ } else {
+ struct crypt_priv *pcr = pkc->priv;
+@@ -1046,26 +1044,41 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ ret = 0;
+ }
+ return ret;
+- case CIOCASYMASYNFETCH:
++ case CIOCASYMFETCHCOOKIE:
+ {
+ struct cryptodev_pkc *pkc;
+ unsigned long flags;
++ int i;
++ struct pkc_cookie_list_s cookie_list;
+
+ spin_lock_irqsave(&pcr->completion_lock, flags);
+- if (list_empty(&pcr->asym_completed_list)) {
+- spin_unlock_irqrestore(&pcr->completion_lock, flags);
+- return -ENOMEM;
++ cookie_list.cookie_available = 0;
++ for (i = 0; i < MAX_COOKIES; i++) {
++ if (!list_empty(&pcr->asym_completed_list)) {
++ /* Run a loop in the list for upto elements
++ and copy their response back */
++ pkc =
++ list_first_entry(&pcr->asym_completed_list,
++ struct cryptodev_pkc, list);
++ list_del(&pkc->list);
++ ret = crypto_async_fetch_asym(pkc);
++ if (!ret) {
++ cookie_list.cookie_available++;
++ cookie_list.cookie[i] =
++ pkc->kop.kop.cookie;
++ cookie_list.status[i] = pkc->result.err;
++ }
++ kfree(pkc);
++ } else {
++ break;
++ }
+ }
+- pkc = list_first_entry(&pcr->asym_completed_list,
+- struct cryptodev_pkc, list);
+- list_del(&pkc->list);
+ spin_unlock_irqrestore(&pcr->completion_lock, flags);
+- ret = crypto_async_fetch_asym(pkc);
+
+ /* Reflect the updated request to user-space */
+- if (!ret)
+- kop_to_user(&pkc->kop, arg);
+- kfree(pkc);
++ if (cookie_list.cookie_available)
++ copy_to_user(arg, &cookie_list,
++ sizeof(struct pkc_cookie_list_s));
+ }
+ return ret;
+ default:
+@@ -1340,26 +1353,41 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+ ret = 0;
+ }
+ return ret;
+- case COMPAT_CIOCASYMASYNFETCH:
++ case COMPAT_CIOCASYMFETCHCOOKIE:
+ {
+ struct cryptodev_pkc *pkc;
+ unsigned long flags;
++ int i = 0;
++ struct compat_pkc_cookie_list_s cookie_list;
+
+ spin_lock_irqsave(&pcr->completion_lock, flags);
+- if (list_empty(&pcr->asym_completed_list)) {
+- spin_unlock_irqrestore(&pcr->completion_lock, flags);
+- return -ENOMEM;
++ cookie_list.cookie_available = 0;
++
++ for (i = 0; i < MAX_COOKIES; i++) {
++ if (!list_empty(&pcr->asym_completed_list)) {
++ /* Run a loop in the list for upto elements
++ and copy their response back */
++ pkc =
++ list_first_entry(&pcr->asym_completed_list,
++ struct cryptodev_pkc, list);
++ list_del(&pkc->list);
++ ret = crypto_async_fetch_asym(pkc);
++ if (!ret) {
++ cookie_list.cookie_available++;
++ cookie_list.cookie[i] =
++ pkc->kop.kop.cookie;
++ }
++ kfree(pkc);
++ } else {
++ break;
++ }
+ }
+- pkc = list_first_entry(&pcr->asym_completed_list,
+- struct cryptodev_pkc, list);
+- list_del(&pkc->list);
+ spin_unlock_irqrestore(&pcr->completion_lock, flags);
+- ret = crypto_async_fetch_asym(pkc);
+
+ /* Reflect the updated request to user-space */
+- if (!ret)
+- compat_kop_to_user(&pkc->kop, arg);
+- kfree(pkc);
++ if (cookie_list.cookie_available)
++ copy_to_user(arg, &cookie_list,
++ sizeof(struct compat_pkc_cookie_list_s));
+ }
+ return ret;
+ default:
+--
+1.7.9.7
+
--- /dev/null
+From bda8dd5839da7a8e731b60b64b9fcb531c334b99 Mon Sep 17 00:00:00 2001
+From: Yashpal Dutta <yashpal.dutta@freescale.com>
+Date: Fri, 7 Mar 2014 07:53:53 +0545
+Subject: [[Patch][fsl 12/16] ECC_KEYGEN and DLC_KEYGEN supported in cryptodev
+ module
+
+Upstream-status: Pending
+
+Signed-off-by: Yashpal Dutta <yashpal.dutta@freescale.com>
+---
+ cryptlib.c | 2 ++
+ crypto/cryptodev.h | 5 +++-
+ ioctl.c | 29 ++++++++++++++++--
+ main.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 118 insertions(+), 3 deletions(-)
+
+diff --git a/cryptlib.c b/cryptlib.c
+index fa0b63f..41acb2c 100644
+--- a/cryptlib.c
++++ b/cryptlib.c
+@@ -437,6 +437,8 @@ int cryptodev_pkc_offload(struct cryptodev_pkc *pkc)
+ case DSA_VERIFY:
+ case ECDSA_SIGN:
+ case ECDSA_VERIFY:
++ case DLC_KEYGEN:
++ case ECC_KEYGEN:
+ pkc->s = crypto_alloc_pkc("pkc(dsa)",
+ CRYPTO_ALG_TYPE_PKC_DSA, 0);
+ break;
+diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
+index 0d65899..33cca2e 100644
+--- a/crypto/cryptodev.h
++++ b/crypto/cryptodev.h
+@@ -269,6 +269,8 @@ enum cryptodev_crk_op_t {
+ CRK_DSA_SIGN = 2,
+ CRK_DSA_VERIFY = 3,
+ CRK_DH_COMPUTE_KEY = 4,
++ CRK_DSA_GENERATE_KEY = 5,
++ CRK_DH_GENERATE_KEY = 6,
+ CRK_ALGORITHM_ALL
+ };
+
+@@ -281,7 +283,8 @@ enum cryptodev_crk_op_t {
+ #define CRF_DSA_SIGN (1 << CRK_DSA_SIGN)
+ #define CRF_DSA_VERIFY (1 << CRK_DSA_VERIFY)
+ #define CRF_DH_COMPUTE_KEY (1 << CRK_DH_COMPUTE_KEY)
+-
++#define CRF_DSA_GENERATE_KEY (1 << CRK_DSA_GENERATE_KEY)
++#define CRF_DH_GENERATE_KEY (1 << CRK_DH_GENERATE_KEY)
+
+ /* ioctl's. Compatible with old linux cryptodev.h
+ */
+diff --git a/ioctl.c b/ioctl.c
+index 9f57d46..cc1a2a9 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -721,6 +721,23 @@ static int crypto_async_fetch_asym(struct cryptodev_pkc *pkc)
+ dh_req->z, dh_req->z_len);
+ }
+ break;
++ case CRK_DSA_GENERATE_KEY:
++ case CRK_DH_GENERATE_KEY:
++ {
++ struct keygen_req_s *key_req = &pkc_req->req_u.keygen;
++
++ if (pkc_req->type == ECC_KEYGEN) {
++ copy_to_user(ckop->crk_param[4].crp_p, key_req->pub_key,
++ key_req->pub_key_len);
++ copy_to_user(ckop->crk_param[5].crp_p,
++ key_req->priv_key, key_req->priv_key_len);
++ } else {
++ copy_to_user(ckop->crk_param[3].crp_p,
++ key_req->pub_key, key_req->pub_key_len);
++ copy_to_user(ckop->crk_param[4].crp_p,
++ key_req->priv_key, key_req->priv_key_len);
++ }
++ }
+ default:
+ ret = -EINVAL;
+ }
+@@ -934,8 +951,9 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+
+ switch (cmd) {
+ case CIOCASYMFEAT:
+- return put_user(CRF_MOD_EXP_CRT | CRF_MOD_EXP |
+- CRF_DSA_SIGN | CRF_DSA_VERIFY | CRF_DH_COMPUTE_KEY, p);
++ return put_user(CRF_MOD_EXP_CRT | CRF_MOD_EXP | CRF_DSA_SIGN |
++ CRF_DSA_VERIFY | CRF_DH_COMPUTE_KEY |
++ CRF_DSA_GENERATE_KEY, p);
+ case CRIOGET:
+ fd = clonefd(filp);
+ ret = put_user(fd, p);
+@@ -1079,7 +1097,14 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ if (cookie_list.cookie_available)
+ copy_to_user(arg, &cookie_list,
+ sizeof(struct pkc_cookie_list_s));
++ else {
++ struct pkc_cookie_list_s *user_ck_list = (void *)arg;
++
++ put_user(0, &(user_ck_list->cookie_available));
++ }
++ ret = cookie_list.cookie_available;
+ }
++
+ return ret;
+ default:
+ return -EINVAL;
+diff --git a/main.c b/main.c
+index 0b7951e..c901bc7 100644
+--- a/main.c
++++ b/main.c
+@@ -342,6 +342,85 @@ err:
+ return rc;
+ }
+
++int crypto_kop_keygen(struct cryptodev_pkc *pkc)
++{
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *cop = &kop->kop;
++ struct pkc_request *pkc_req;
++ struct keygen_req_s *key_req;
++ int rc, buf_size;
++ uint8_t *buf;
++
++ if (!cop->crk_param[0].crp_nbits || !cop->crk_param[1].crp_nbits ||
++ !cop->crk_param[2].crp_nbits || !cop->crk_param[3].crp_nbits ||
++ !cop->crk_param[4].crp_nbits)
++ return -EINVAL;
++
++ pkc_req = &pkc->req;
++ key_req = &pkc_req->req_u.keygen;
++ key_req->q_len = (cop->crk_param[0].crp_nbits + 7)/8;
++ key_req->r_len = (cop->crk_param[1].crp_nbits + 7)/8;
++ key_req->g_len = (cop->crk_param[2].crp_nbits + 7)/8;
++ if (cop->crk_iparams == 3) {
++ key_req->pub_key_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ key_req->priv_key_len = (cop->crk_param[4].crp_nbits + 7)/8;
++ buf_size = key_req->q_len + key_req->r_len + key_req->g_len +
++ key_req->pub_key_len + key_req->priv_key_len;
++ pkc_req->type = DLC_KEYGEN;
++ } else {
++ key_req->ab_len = (cop->crk_param[3].crp_nbits + 7)/8;
++ key_req->pub_key_len = (cop->crk_param[4].crp_nbits + 7)/8;
++ key_req->priv_key_len = (cop->crk_param[5].crp_nbits + 7)/8;
++ buf_size = key_req->q_len + key_req->r_len + key_req->g_len +
++ key_req->pub_key_len + key_req->priv_key_len +
++ key_req->ab_len;
++ pkc_req->type = ECC_KEYGEN;
++ pkc_req->curve_type = cop->curve_type;
++ }
++
++ buf = kzalloc(buf_size, GFP_DMA);
++ if (!buf)
++ return -ENOMEM;
++
++ key_req->q = buf;
++ key_req->r = key_req->q + key_req->q_len;
++ key_req->g = key_req->r + key_req->r_len;
++ key_req->pub_key = key_req->g + key_req->g_len;
++ key_req->priv_key = key_req->pub_key + key_req->pub_key_len;
++ copy_from_user(key_req->q, cop->crk_param[0].crp_p, key_req->q_len);
++ copy_from_user(key_req->r, cop->crk_param[1].crp_p, key_req->r_len);
++ copy_from_user(key_req->g, cop->crk_param[2].crp_p, key_req->g_len);
++ if (cop->crk_iparams == 3) {
++ copy_from_user(key_req->pub_key, cop->crk_param[3].crp_p,
++ key_req->pub_key_len);
++ copy_from_user(key_req->priv_key, cop->crk_param[4].crp_p,
++ key_req->priv_key_len);
++ } else {
++ key_req->ab = key_req->priv_key + key_req->priv_key_len;
++ copy_from_user(key_req->ab, cop->crk_param[3].crp_p,
++ key_req->ab_len);
++ copy_from_user(key_req->pub_key, cop->crk_param[4].crp_p,
++ key_req->pub_key_len);
++ copy_from_user(key_req->priv_key, cop->crk_param[5].crp_p,
++ key_req->priv_key_len);
++ }
++
++ rc = cryptodev_pkc_offload(pkc);
++ if (pkc->type == SYNCHRONOUS) {
++ if (rc)
++ goto err;
++ } else {
++ if (rc != -EINPROGRESS && !rc)
++ goto err;
++
++ pkc->cookie = buf;
++ return rc;
++ }
++err:
++ kfree(buf);
++ return rc;
++}
++
+ int crypto_kop_dh_key(struct cryptodev_pkc *pkc)
+ {
+ struct kernel_crypt_kop *kop = &pkc->kop;
+@@ -554,6 +633,12 @@ int crypto_run_asym(struct cryptodev_pkc *pkc)
+ goto err;
+ ret = crypto_kop_dh_key(pkc);
+ break;
++ case CRK_DH_GENERATE_KEY:
++ case CRK_DSA_GENERATE_KEY:
++ if ((kop->kop.crk_iparams != 3 && kop->kop.crk_iparams != 4))
++ goto err;
++ ret = crypto_kop_keygen(pkc);
++ break;
+ }
+ err:
+ return ret;
+--
+1.7.9.7
+
--- /dev/null
+From 211a494a4f8ee6d5d31a1db938b771958ea32c6b Mon Sep 17 00:00:00 2001
+From: Yashpal Dutta <yashpal.dutta@freescale.com>
+Date: Fri, 7 Mar 2014 08:49:15 +0545
+Subject: [[Patch][fsl 13/16] RCU stall fixed in PKC asynchronous interface
+
+Upstream-status: Pending
+
+Signed-off-by: Yashpal Dutta <yashpal.dutta@freescale.com>
+---
+ ioctl.c | 23 +++++++++++------------
+ main.c | 43 +++++++++++++++++++++++++++----------------
+ 2 files changed, 38 insertions(+), 28 deletions(-)
+
+diff --git a/ioctl.c b/ioctl.c
+index cc1a2a9..1752880 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -106,10 +106,9 @@ void cryptodev_complete_asym(struct crypto_async_request *req, int err)
+ complete(&res->completion);
+ } else {
+ struct crypt_priv *pcr = pkc->priv;
+- unsigned long flags;
+- spin_lock_irqsave(&pcr->completion_lock, flags);
++ spin_lock_bh(&pcr->completion_lock);
+ list_add_tail(&pkc->list, &pcr->asym_completed_list);
+- spin_unlock_irqrestore(&pcr->completion_lock, flags);
++ spin_unlock_bh(&pcr->completion_lock);
+ /* wake for POLLIN */
+ wake_up_interruptible(&pcr->user_waiter);
+ }
+@@ -953,7 +952,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ case CIOCASYMFEAT:
+ return put_user(CRF_MOD_EXP_CRT | CRF_MOD_EXP | CRF_DSA_SIGN |
+ CRF_DSA_VERIFY | CRF_DH_COMPUTE_KEY |
+- CRF_DSA_GENERATE_KEY, p);
++ CRF_DSA_GENERATE_KEY | CRF_DH_GENERATE_KEY, p);
+ case CRIOGET:
+ fd = clonefd(filp);
+ ret = put_user(fd, p);
+@@ -992,7 +991,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ case CIOCKEY:
+ {
+ struct cryptodev_pkc *pkc =
+- kzalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
++ kmalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
+
+ if (!pkc)
+ return -ENOMEM;
+@@ -1048,7 +1047,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ case CIOCASYMASYNCRYPT:
+ {
+ struct cryptodev_pkc *pkc =
+- kzalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
++ kmalloc(sizeof(struct cryptodev_pkc), GFP_KERNEL);
+ ret = kop_from_user(&pkc->kop, arg);
+
+ if (unlikely(ret))
+@@ -1065,13 +1064,12 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ case CIOCASYMFETCHCOOKIE:
+ {
+ struct cryptodev_pkc *pkc;
+- unsigned long flags;
+ int i;
+ struct pkc_cookie_list_s cookie_list;
+
+- spin_lock_irqsave(&pcr->completion_lock, flags);
+ cookie_list.cookie_available = 0;
+ for (i = 0; i < MAX_COOKIES; i++) {
++ spin_lock_bh(&pcr->completion_lock);
+ if (!list_empty(&pcr->asym_completed_list)) {
+ /* Run a loop in the list for upto elements
+ and copy their response back */
+@@ -1079,6 +1077,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ list_first_entry(&pcr->asym_completed_list,
+ struct cryptodev_pkc, list);
+ list_del(&pkc->list);
++ spin_unlock_bh(&pcr->completion_lock);
+ ret = crypto_async_fetch_asym(pkc);
+ if (!ret) {
+ cookie_list.cookie_available++;
+@@ -1088,10 +1087,10 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ }
+ kfree(pkc);
+ } else {
++ spin_unlock_bh(&pcr->completion_lock);
+ break;
+ }
+ }
+- spin_unlock_irqrestore(&pcr->completion_lock, flags);
+
+ /* Reflect the updated request to user-space */
+ if (cookie_list.cookie_available)
+@@ -1381,14 +1380,13 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+ case COMPAT_CIOCASYMFETCHCOOKIE:
+ {
+ struct cryptodev_pkc *pkc;
+- unsigned long flags;
+ int i = 0;
+ struct compat_pkc_cookie_list_s cookie_list;
+
+- spin_lock_irqsave(&pcr->completion_lock, flags);
+ cookie_list.cookie_available = 0;
+
+ for (i = 0; i < MAX_COOKIES; i++) {
++ spin_lock_bh(&pcr->completion_lock);
+ if (!list_empty(&pcr->asym_completed_list)) {
+ /* Run a loop in the list for upto elements
+ and copy their response back */
+@@ -1396,6 +1394,7 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+ list_first_entry(&pcr->asym_completed_list,
+ struct cryptodev_pkc, list);
+ list_del(&pkc->list);
++ spin_unlock_bh(&pcr->completion_lock);
+ ret = crypto_async_fetch_asym(pkc);
+ if (!ret) {
+ cookie_list.cookie_available++;
+@@ -1404,10 +1403,10 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
+ }
+ kfree(pkc);
+ } else {
++ spin_unlock_bh(&pcr->completion_lock);
+ break;
+ }
+ }
+- spin_unlock_irqrestore(&pcr->completion_lock, flags);
+
+ /* Reflect the updated request to user-space */
+ if (cookie_list.cookie_available)
+diff --git a/main.c b/main.c
+index c901bc7..2747706 100644
+--- a/main.c
++++ b/main.c
+@@ -215,7 +215,9 @@ int crypto_kop_dsasign(struct cryptodev_pkc *pkc)
+ pkc_req->type = DSA_SIGN;
+ }
+
+- buf = kzalloc(buf_size, GFP_DMA);
++ buf = kmalloc(buf_size, GFP_DMA);
++ if (!buf)
++ return -ENOMEM;
+
+ dsa_req->q = buf;
+ dsa_req->r = dsa_req->q + dsa_req->q_len;
+@@ -298,7 +300,9 @@ int crypto_kop_dsaverify(struct cryptodev_pkc *pkc)
+ pkc_req->type = DSA_VERIFY;
+ }
+
+- buf = kzalloc(buf_size, GFP_DMA);
++ buf = kmalloc(buf_size, GFP_DMA);
++ if (!buf)
++ return -ENOMEM;
+
+ dsa_req->q = buf;
+ dsa_req->r = dsa_req->q + dsa_req->q_len;
+@@ -378,7 +382,7 @@ int crypto_kop_keygen(struct cryptodev_pkc *pkc)
+ pkc_req->curve_type = cop->curve_type;
+ }
+
+- buf = kzalloc(buf_size, GFP_DMA);
++ buf = kmalloc(buf_size, GFP_DMA);
+ if (!buf)
+ return -ENOMEM;
+
+@@ -390,25 +394,28 @@ int crypto_kop_keygen(struct cryptodev_pkc *pkc)
+ copy_from_user(key_req->q, cop->crk_param[0].crp_p, key_req->q_len);
+ copy_from_user(key_req->r, cop->crk_param[1].crp_p, key_req->r_len);
+ copy_from_user(key_req->g, cop->crk_param[2].crp_p, key_req->g_len);
+- if (cop->crk_iparams == 3) {
+- copy_from_user(key_req->pub_key, cop->crk_param[3].crp_p,
+- key_req->pub_key_len);
+- copy_from_user(key_req->priv_key, cop->crk_param[4].crp_p,
+- key_req->priv_key_len);
+- } else {
++ if (cop->crk_iparams == 4) {
+ key_req->ab = key_req->priv_key + key_req->priv_key_len;
+ copy_from_user(key_req->ab, cop->crk_param[3].crp_p,
+ key_req->ab_len);
+- copy_from_user(key_req->pub_key, cop->crk_param[4].crp_p,
+- key_req->pub_key_len);
+- copy_from_user(key_req->priv_key, cop->crk_param[5].crp_p,
+- key_req->priv_key_len);
+ }
+
+ rc = cryptodev_pkc_offload(pkc);
+ if (pkc->type == SYNCHRONOUS) {
+ if (rc)
+ goto err;
++
++ if (cop->crk_iparams == 4) {
++ copy_to_user(cop->crk_param[4].crp_p, key_req->pub_key,
++ key_req->pub_key_len);
++ copy_to_user(cop->crk_param[5].crp_p, key_req->priv_key,
++ key_req->priv_key_len);
++ } else {
++ copy_to_user(cop->crk_param[3].crp_p, key_req->pub_key,
++ key_req->pub_key_len);
++ copy_to_user(cop->crk_param[4].crp_p,
++ key_req->priv_key, key_req->priv_key_len);
++ }
+ } else {
+ if (rc != -EINPROGRESS && !rc)
+ goto err;
+@@ -447,7 +454,9 @@ int crypto_kop_dh_key(struct cryptodev_pkc *pkc)
+ pkc_req->type = DH_COMPUTE_KEY;
+ }
+ buf_size += dh_req->z_len;
+- buf = kzalloc(buf_size, GFP_DMA);
++ buf = kmalloc(buf_size, GFP_DMA);
++ if (!buf)
++ return -ENOMEM;
+ dh_req->q = buf;
+ dh_req->s = dh_req->q + dh_req->q_len;
+ dh_req->pub_key = dh_req->s + dh_req->s_len;
+@@ -508,9 +517,11 @@ int crypto_modexp_crt(struct cryptodev_pkc *pkc)
+ rsa_req->dq_len = (cop->crk_param[4].crp_nbits + 7)/8;
+ rsa_req->c_len = (cop->crk_param[5].crp_nbits + 7)/8;
+ rsa_req->f_len = (cop->crk_param[6].crp_nbits + 7)/8;
+- buf = kzalloc(rsa_req->p_len + rsa_req->q_len + rsa_req->f_len +
++ buf = kmalloc(rsa_req->p_len + rsa_req->q_len + rsa_req->f_len +
+ rsa_req->dp_len + rsa_req->dp_len + rsa_req->c_len +
+ rsa_req->g_len, GFP_DMA);
++ if (!buf)
++ return -ENOMEM;
+ rsa_req->p = buf;
+ rsa_req->q = rsa_req->p + rsa_req->p_len;
+ rsa_req->g = rsa_req->q + rsa_req->q_len;
+@@ -563,7 +574,7 @@ int crypto_bn_modexp(struct cryptodev_pkc *pkc)
+ rsa_req->e_len = (cop->crk_param[1].crp_nbits + 7)/8;
+ rsa_req->n_len = (cop->crk_param[2].crp_nbits + 7)/8;
+ rsa_req->g_len = (cop->crk_param[3].crp_nbits + 7)/8;
+- buf = kzalloc(rsa_req->f_len + rsa_req->e_len + rsa_req->n_len
++ buf = kmalloc(rsa_req->f_len + rsa_req->e_len + rsa_req->n_len
+ + rsa_req->g_len, GFP_DMA);
+ if (!buf)
+ return -ENOMEM;
+--
+1.7.9.7
+
--- /dev/null
+From 50c116780f736b3e6a11389c9d9b3f4a1d5cab90 Mon Sep 17 00:00:00 2001
+From: Cristian Stoica <cristian.stoica@freescale.com>
+Date: Wed, 19 Mar 2014 17:59:17 +0200
+Subject: [[Patch][fsl 14/16] use static allocation for keys copied from
+ userspace
+
+Upstream-status: Pending
+
+There is no need to keep keys around for the entire duration of the
+session. The keys are copied from user-space and then used to initialize
+the ciphers. After this, the original keys can be discarded.
+The total required space for keys is small and known in advance. This
+patch uses this information to allocate required space on stack.
+
+Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
+---
+ cryptodev_int.h | 1 -
+ ioctl.c | 38 ++++++++++++++++++++------------------
+ 2 files changed, 20 insertions(+), 19 deletions(-)
+
+diff --git a/cryptodev_int.h b/cryptodev_int.h
+index 8beeef0..7ea6976 100644
+--- a/cryptodev_int.h
++++ b/cryptodev_int.h
+@@ -212,7 +212,6 @@ struct csession {
+ struct hash_data hdata;
+ uint32_t sid;
+ uint32_t alignmask;
+- uint8_t *key;
+
+ unsigned int array_size;
+ unsigned int used_pages; /* the number of pages that are used */
+diff --git a/ioctl.c b/ioctl.c
+index 1752880..16ce72c 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -46,6 +46,8 @@
+ #include <linux/uaccess.h>
+ #include <crypto/cryptodev.h>
+ #include <linux/scatterlist.h>
++#include <linux/rtnetlink.h>
++#include <crypto/authenc.h>
+
+ #include <linux/sysctl.h>
+
+@@ -136,9 +138,17 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ const char *alg_name = NULL;
+ const char *hash_name = NULL;
+ int hmac_mode = 1, stream = 0, aead = 0;
+- uint8_t *key = NULL;
+- unsigned int keylen;
+- uint8_t mackey[CRYPTO_HMAC_MAX_KEY_LEN];
++ /*
++ * With aead, only ckey is used and it can cover all the struct space;
++ * otherwise both keys may be used simultaneously but they are confined
++ * to their spaces
++ */
++ struct {
++ uint8_t ckey[CRYPTO_CIPHER_MAX_KEY_LEN];
++ uint8_t mkey[CRYPTO_HMAC_MAX_KEY_LEN];
++ /* padding space for aead keys */
++ uint8_t pad[RTA_SPACE(sizeof(struct crypto_authenc_key_param))];
++ } keys;
+
+ /* Does the request make sense? */
+ if (unlikely(!sop->cipher && !sop->mac)) {
+@@ -257,23 +267,17 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+
+ /* Set-up crypto transform. */
+ if (alg_name) {
++ unsigned int keylen;
+ ret = cryptodev_get_cipher_keylen(&keylen, sop, aead);
+ if (unlikely(ret < 0))
+ goto error_cipher;
+
+- key = kmalloc(keylen, GFP_KERNEL);
+- ses_new->key = key;
+- if (unlikely(!key)) {
+- ret = -ENOMEM;
+- goto error_cipher;
+- }
+-
+- ret = cryptodev_get_cipher_key(key, sop, aead);
++ ret = cryptodev_get_cipher_key(keys.ckey, sop, aead);
+ if (unlikely(ret < 0))
+ goto error_cipher;
+
+- ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, key, keylen,
+- stream, aead);
++ ret = cryptodev_cipher_init(&ses_new->cdata, alg_name,
++ keys.ckey, keylen, stream, aead);
+ if (ret < 0) {
+ ddebug(1, "Failed to load cipher for %s", alg_name);
+ ret = -EINVAL;
+@@ -289,14 +293,14 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+ goto error_hash;
+ }
+
+- if (sop->mackey && unlikely(copy_from_user(mackey, sop->mackey,
+- sop->mackeylen))) {
++ if (sop->mackey && unlikely(copy_from_user(keys.mkey,
++ sop->mackey, sop->mackeylen))) {
+ ret = -EFAULT;
+ goto error_hash;
+ }
+
+ ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode,
+- mackey, sop->mackeylen);
++ keys.mkey, sop->mackeylen);
+ if (ret != 0) {
+ ddebug(1, "Failed to load hash for %s", hash_name);
+ ret = -EINVAL;
+@@ -349,7 +353,6 @@ error_hash:
+ kfree(ses_new->sg);
+ kfree(ses_new->pages);
+ error_cipher:
+- kfree(key);
+ kfree(ses_new);
+
+ return ret;
+@@ -370,7 +373,6 @@ crypto_destroy_session(struct csession *ses_ptr)
+ ddebug(2, "freeing space for %d user pages", ses_ptr->array_size);
+ kfree(ses_ptr->pages);
+ kfree(ses_ptr->sg);
+- kfree(ses_ptr->key);
+ mutex_unlock(&ses_ptr->sem);
+ mutex_destroy(&ses_ptr->sem);
+ kfree(ses_ptr);
+--
+1.7.9.7
+
--- /dev/null
+From 1d9c8084a9addaa071ca3e6c14167ebdb2673725 Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <B48286@freescale.com>
+Date: Wed, 19 Mar 2014 14:02:46 +0800
+Subject: [[Patch][fsl 15/16] Add RSA Key generation offloading
+
+Upstream-status: Pending
+
+Signed-off-by: Hou Zhiqiang <B48286@freescale.com>
+Tested-by: Cristian Stoica <cristian.stoica@freescale.com>
+---
+ cryptlib.c | 1 +
+ crypto/cryptodev.h | 2 ++
+ ioctl.c | 3 +-
+ main.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 4 files changed, 84 insertions(+), 2 deletions(-)
+
+diff --git a/cryptlib.c b/cryptlib.c
+index 41acb2c..89af77a 100644
+--- a/cryptlib.c
++++ b/cryptlib.c
+@@ -426,6 +426,7 @@ int cryptodev_pkc_offload(struct cryptodev_pkc *pkc)
+ struct pkc_request *pkc_req = &pkc->req, *pkc_requested;
+
+ switch (pkc_req->type) {
++ case RSA_KEYGEN:
+ case RSA_PUB:
+ case RSA_PRIV_FORM1:
+ case RSA_PRIV_FORM2:
+diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
+index 33cca2e..7990f27 100644
+--- a/crypto/cryptodev.h
++++ b/crypto/cryptodev.h
+@@ -271,6 +271,7 @@ enum cryptodev_crk_op_t {
+ CRK_DH_COMPUTE_KEY = 4,
+ CRK_DSA_GENERATE_KEY = 5,
+ CRK_DH_GENERATE_KEY = 6,
++ CRK_RSA_GENERATE_KEY = 7,
+ CRK_ALGORITHM_ALL
+ };
+
+@@ -280,6 +281,7 @@ enum cryptodev_crk_op_t {
+ */
+ #define CRF_MOD_EXP (1 << CRK_MOD_EXP)
+ #define CRF_MOD_EXP_CRT (1 << CRK_MOD_EXP_CRT)
++#define CRF_RSA_GENERATE_KEY (1 << CRK_RSA_GENERATE_KEY)
+ #define CRF_DSA_SIGN (1 << CRK_DSA_SIGN)
+ #define CRF_DSA_VERIFY (1 << CRK_DSA_VERIFY)
+ #define CRF_DH_COMPUTE_KEY (1 << CRK_DH_COMPUTE_KEY)
+diff --git a/ioctl.c b/ioctl.c
+index 16ce72c..0344c0c 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -954,7 +954,8 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
+ case CIOCASYMFEAT:
+ return put_user(CRF_MOD_EXP_CRT | CRF_MOD_EXP | CRF_DSA_SIGN |
+ CRF_DSA_VERIFY | CRF_DH_COMPUTE_KEY |
+- CRF_DSA_GENERATE_KEY | CRF_DH_GENERATE_KEY, p);
++ CRF_DSA_GENERATE_KEY | CRF_DH_GENERATE_KEY |
++ CRF_RSA_GENERATE_KEY, p);
+ case CRIOGET:
+ fd = clonefd(filp);
+ ret = put_user(fd, p);
+diff --git a/main.c b/main.c
+index 2747706..14dcf40 100644
+--- a/main.c
++++ b/main.c
+@@ -346,6 +346,82 @@ err:
+ return rc;
+ }
+
++int crypto_kop_rsa_keygen(struct cryptodev_pkc *pkc)
++{
++ struct kernel_crypt_kop *kop = &pkc->kop;
++ struct crypt_kop *cop = &kop->kop;
++ struct pkc_request *pkc_req;
++ struct rsa_keygen_req_s *key_req;
++ int rc, buf_size;
++ uint8_t *buf;
++
++ if (!cop->crk_param[0].crp_nbits || !cop->crk_param[1].crp_nbits ||
++ !cop->crk_param[2].crp_nbits || !cop->crk_param[3].crp_nbits ||
++ !cop->crk_param[4].crp_nbits || !cop->crk_param[5].crp_nbits ||
++ !cop->crk_param[6].crp_nbits)
++ return -EINVAL;
++
++ pkc_req = &pkc->req;
++ pkc_req->type = RSA_KEYGEN;
++ key_req = &pkc_req->req_u.rsa_keygen;
++ key_req->n_len = (cop->crk_param[2].crp_nbits + 7)/8;
++ key_req->p_len = (cop->crk_param[0].crp_nbits + 7) / 8;
++ key_req->q_len = (cop->crk_param[1].crp_nbits + 7) / 8;
++ key_req->n_len = (cop->crk_param[2].crp_nbits + 7) / 8;
++ key_req->d_len = (cop->crk_param[3].crp_nbits + 7) / 8;
++ key_req->dp_len = (cop->crk_param[4].crp_nbits + 7) / 8;
++ key_req->dq_len = (cop->crk_param[5].crp_nbits + 7) / 8;
++ key_req->c_len = (cop->crk_param[6].crp_nbits + 7) / 8;
++
++ buf_size = key_req->p_len + key_req->q_len + key_req->n_len +
++ key_req->d_len + key_req->dp_len +
++ key_req->dq_len + key_req->c_len;
++
++ buf = kmalloc(buf_size, GFP_DMA);
++ if (!buf)
++ return -ENOMEM;
++ key_req->p = buf;
++ key_req->q = key_req->p + key_req->p_len;
++ key_req->n = key_req->q + key_req->q_len;
++ key_req->d = key_req->n + key_req->n_len;
++ key_req->dp = key_req->d + key_req->d_len;
++ key_req->dq = key_req->dp + key_req->dp_len;
++ key_req->c = key_req->dq + key_req->dq_len;
++
++ rc = cryptodev_pkc_offload(pkc);
++
++ if (pkc->type == SYNCHRONOUS) {
++ if (rc)
++ goto err;
++
++ copy_to_user(cop->crk_param[0].crp_p,
++ key_req->p, key_req->p_len);
++ copy_to_user(cop->crk_param[1].crp_p,
++ key_req->q, key_req->q_len);
++ copy_to_user(cop->crk_param[2].crp_p,
++ key_req->n, key_req->n_len);
++ copy_to_user(cop->crk_param[3].crp_p,
++ key_req->d, key_req->d_len);
++ copy_to_user(cop->crk_param[4].crp_p,
++ key_req->dp, key_req->dp_len);
++ copy_to_user(cop->crk_param[5].crp_p,
++ key_req->dq, key_req->dq_len);
++ copy_to_user(cop->crk_param[6].crp_p,
++ key_req->c, key_req->c_len);
++ } else {
++ if (rc != -EINPROGRESS && !rc) {
++ printk("%s: Failed\n", __func__);
++ goto err;
++ }
++ pkc->cookie = buf;
++ return rc;
++ }
++err:
++ kfree(buf);
++ return rc;
++
++}
++
+ int crypto_kop_keygen(struct cryptodev_pkc *pkc)
+ {
+ struct kernel_crypt_kop *kop = &pkc->kop;
+@@ -385,7 +461,6 @@ int crypto_kop_keygen(struct cryptodev_pkc *pkc)
+ buf = kmalloc(buf_size, GFP_DMA);
+ if (!buf)
+ return -ENOMEM;
+-
+ key_req->q = buf;
+ key_req->r = key_req->q + key_req->q_len;
+ key_req->g = key_req->r + key_req->r_len;
+@@ -650,6 +725,9 @@ int crypto_run_asym(struct cryptodev_pkc *pkc)
+ goto err;
+ ret = crypto_kop_keygen(pkc);
+ break;
++ case CRK_RSA_GENERATE_KEY:
++ ret = crypto_kop_rsa_keygen(pkc);
++ break;
+ }
+ err:
+ return ret;
+--
+1.7.9.7
+
--- /dev/null
+From 2215332bff6034d0e22e92e8fda0993f2579a740 Mon Sep 17 00:00:00 2001
+From: Yashpal Dutta <yashpal.dutta@freescale.com>
+Date: Thu, 17 Apr 2014 07:08:47 +0545
+Subject: [[Patch][fsl 16/16] Fixed compilation error of openssl with fsl
+ cryptodev
+
+Upstream-status: Pending
+
+Signed-off-by: Yashpal Dutta <yashpal.dutta@freescale.com>
+Tested-by: Cristian Stoica <cristian.stoica@freescale.com>
+---
+ cryptlib.c | 6 +++---
+ crypto/cryptodev.h | 9 ++++++++-
+ cryptodev_int.h | 2 +-
+ ioctl.c | 6 +++++-
+ 4 files changed, 17 insertions(+), 6 deletions(-)
+
+diff --git a/cryptlib.c b/cryptlib.c
+index 89af77a..1fc03e5 100644
+--- a/cryptlib.c
++++ b/cryptlib.c
+@@ -129,7 +129,7 @@ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
+ if (alg->max_keysize > 0 &&
+ unlikely((keylen < alg->min_keysize) ||
+ (keylen > alg->max_keysize))) {
+- ddebug(1, "Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.",
++ ddebug(1, "Wrong keylen '%u' for algorithm '%s'. Use %u to %u.",
+ keylen, alg_name, alg->min_keysize, alg->max_keysize);
+ ret = -EINVAL;
+ goto error;
+@@ -156,7 +156,7 @@ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
+ }
+
+ if (unlikely(ret)) {
+- ddebug(1, "Setting key failed for %s-%zu.", alg_name, keylen*8);
++ ddebug(1, "Setting key failed for %s-%u.", alg_name, keylen*8);
+ ret = -EINVAL;
+ goto error;
+ }
+@@ -323,7 +323,7 @@ int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name,
+ if (hmac_mode != 0) {
+ ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen);
+ if (unlikely(ret)) {
+- ddebug(1, "Setting hmac key failed for %s-%zu.",
++ ddebug(1, "Setting hmac key failed for %s-%u.",
+ alg_name, mackeylen*8);
+ ret = -EINVAL;
+ goto error;
+diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
+index 7990f27..77bffc9 100644
+--- a/crypto/cryptodev.h
++++ b/crypto/cryptodev.h
+@@ -235,6 +235,13 @@ struct crypt_auth_op {
+ #define CRYPTO_ALG_FLAG_RNG_ENABLE 2
+ #define CRYPTO_ALG_FLAG_DSA_SHA 4
+
++enum ec_curve_t {
++ EC_DISCRETE_LOG,
++ EC_PRIME,
++ EC_BINARY,
++ MAX_EC_TYPE
++};
++
+ struct crparam {
+ __u8 *crp_p;
+ __u32 crp_nbits;
+@@ -250,7 +257,7 @@ struct crypt_kop {
+ __u16 crk_oparams;
+ __u32 crk_pad1;
+ struct crparam crk_param[CRK_MAXPARAM];
+- enum curve_t curve_type; /* 0 == Discrete Log,
++ enum ec_curve_t curve_type; /* 0 == Discrete Log,
+ 1 = EC_PRIME, 2 = EC_BINARY */
+ void *cookie;
+ };
+diff --git a/cryptodev_int.h b/cryptodev_int.h
+index 7ea6976..e379eaf 100644
+--- a/cryptodev_int.h
++++ b/cryptodev_int.h
+@@ -88,7 +88,7 @@ struct compat_crypt_kop {
+ uint16_t crk_oparams;
+ uint32_t crk_pad1;
+ struct compat_crparam crk_param[CRK_MAXPARAM];
+- enum curve_t curve_type; /* 0 == Discrete Log, 1 = EC_PRIME,
++ enum ec_curve_t curve_type; /* 0 == Discrete Log, 1 = EC_PRIME,
+ 2 = EC_BINARY */
+ compat_uptr_t cookie;
+ };
+diff --git a/ioctl.c b/ioctl.c
+index 0344c0c..66cb05a 100644
+--- a/ioctl.c
++++ b/ioctl.c
+@@ -498,6 +498,7 @@ cryptodev_open(struct inode *inode, struct file *filp)
+ INIT_LIST_HEAD(&pcr->done.list);
+ INIT_LIST_HEAD(&pcr->asym_completed_list);
+ spin_lock_init(&pcr->completion_lock);
++
+ INIT_WORK(&pcr->cryptask, cryptask_routine);
+
+ init_waitqueue_head(&pcr->user_waiter);
+@@ -777,8 +778,11 @@ static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
+
+ if (cop->iv) {
+ rc = copy_from_user(kcop->iv, cop->iv, kcop->ivlen);
+- if (unlikely(rc))
++ if (unlikely(rc)) {
++ derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p",
++ kcop->ivlen, rc, cop->iv);
+ return -EFAULT;
++ }
+ }
+
+ return 0;
+--
+1.7.9.7
+
--- /dev/null
+require recipes-kernel/cryptodev/cryptodev-fsl.inc
+
--- /dev/null
+require recipes-kernel/cryptodev/cryptodev-fsl.inc
+
+inherit qoriq_build_64bit_kernel
+
+do_install_append_fslmachine () {
+ rm -fr ${D}/usr
+}
+
+++ /dev/null
-SECTION = "devel"
-SUMMARY = "Linux Cryptodev KERNEL MODULE"
-DESCRIPTION = "The Cryptodev package contains the kernel /dev/crypto module"
-LICENSE = "GPLv2"
-LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263"
-RCONFLICTS_${PN} = "ocf-linux"
-
-inherit module
-
-PR = "r1"
-DEPENDS += "openssl"
-
-SRCREV = "1c24a0aa996630518d47826a2e3fea129ea094c7"
-
-SRC_URI = "git://repo.or.cz/cryptodev-linux.git;protocol=git \
- file://makefile_fixup.patch \
- file://Add-the-compile-and-install-rules-for-cryptodev-test.patch"
-
-EXTRA_OEMAKE='KERNEL_DIR="${STAGING_KERNEL_DIR}" PREFIX="${D}"'
-
-S = "${WORKDIR}/git"
-python () {
- ma = d.getVar("DISTRO_FEATURES", True)
- arch = d.getVar("OVERRIDES", True)
-
- # the : after the arch is to skip the message on 64b
- if not "multiarch" in ma and ("e5500:" in arch or "e6500:" in arch):
- raise bb.parse.SkipPackage("Building the kernel for this arch requires multiarch to be in DISTRO_FEATURES")
-
- promote_kernel = d.getVar('BUILD_64BIT_KERNEL')
-
- if promote_kernel == "1":
- d.setVar('KERNEL_CC_append', ' -m64')
- d.setVar('KERNEL_LD_append', ' -melf64ppc')
-
- error_qa = d.getVar('ERROR_QA', True)
- if 'arch' in error_qa:
- d.setVar('ERROR_QA', error_qa.replace(' arch', ''))
-}
-
-do_compile_append() {
- oe_runmake testprogs
-}
-
-do_install_append() {
- oe_runmake install_tests
-}
-
-PACKAGES += "${PN}-tests"
-FILES_${PN}-dbg += "${bindir}/tests_cryptodev/.debug"
-FILES_${PN}-tests = "${bindir}/tests_cryptodev/*"
+++ /dev/null
-From 1980a8f4779a955e73285e7a0d86549b69bea5c8 Mon Sep 17 00:00:00 2001
-From: Yu Zongchun <b40527@freescale.com>
-Date: Sun, 28 Apr 2013 14:39:22 +0800
-Subject: [PATCH] Add the compile and install rules for cryptodev tests folder
-
-This is required to install the cryptodev tests folder to rootfs
-
-Signed-off-by: Yu Zongchun <b40527@freescale.com>
-
-Upstream-Status: Pending
-
----
- Makefile | 6 ++++++
- tests/Makefile | 8 ++++++++
- 2 files changed, 14 insertions(+), 0 deletions(-)
-
-diff --git a/Makefile b/Makefile
-index 2be8825..4cbb865 100644
---- a/Makefile
-+++ b/Makefile
-@@ -17,6 +17,9 @@ install:
- @echo "Installing cryptodev.h in /usr/include/crypto ..."
- @install -D crypto/cryptodev.h /usr/include/crypto/cryptodev.h
-
-+install_tests:
-+ make -C tests install DESTDIR=$(PREFIX)
-+
- clean:
- make -C $(KERNEL_DIR) SUBDIRS=`pwd` clean
- rm -f $(hostprogs) *~
-@@ -25,6 +28,9 @@ clean:
- check:
- KERNEL_DIR=$(KERNEL_DIR) make -C tests check
-
-+testprogs:
-+ KERNEL_DIR=$(KERNEL_DIR) make -C tests testprogs
-+
- FILEBASE = cryptodev-linux-$(VERSION)
- TMPDIR ?= /tmp
- OUTPUT = $(FILEBASE).tar.gz
-diff --git a/tests/Makefile b/tests/Makefile
-index 87ca3c7..0488cf6 100644
---- a/tests/Makefile
-+++ b/tests/Makefile
-@@ -19,6 +19,12 @@ example-async-hmac-objs := async_hmac.o
- example-async-speed-objs := async_speed.o
- example-hashcrypt-speed-objs := hashcrypt_speed.c
-
-+install:
-+ install -d $(DESTDIR)/usr/bin/tests_cryptodev
-+ for bin in $(hostprogs); do \
-+ install -m 755 $${bin} $(DESTDIR)/usr/bin/tests_cryptodev/; \
-+ done
-+
- check: $(hostprogs)
- ./cipher
- ./hmac
-@@ -28,6 +34,8 @@ check: $(hostprogs)
- ./cipher-gcm
- ./cipher-aead
-
-+testprogs: $(hostprogs)
-+
- clean:
- rm -f *.o *~ $(hostprogs)
-
---
-1.7.5.4
-
+++ /dev/null
-diff --git a/Makefile b/Makefile
-index 2be8825..b36d68c 100644
---- a/Makefile
-+++ b/Makefile
-@@ -1,6 +1,7 @@
- KBUILD_CFLAGS += -I$(src)
- KERNEL_DIR = /lib/modules/$(shell uname -r)/build
- VERSION = 1.5
-+PREFIX =
-
- cryptodev-objs = ioctl.o main.o cryptlib.o authenc.o zc.o util.o
-
-@@ -12,10 +13,10 @@ build: version.h
- version.h: Makefile
- @echo "#define VERSION \"$(VERSION)\"" > version.h
-
--install:
-+modules_install:
- make -C $(KERNEL_DIR) SUBDIRS=`pwd` modules_install
-- @echo "Installing cryptodev.h in /usr/include/crypto ..."
-- @install -D crypto/cryptodev.h /usr/include/crypto/cryptodev.h
-+ @echo "Installing cryptodev.h in $(PREFIX)/usr/include/crypto ..."
-+ @install -D crypto/cryptodev.h $(PREFIX)/usr/include/crypto/cryptodev.h
-
- clean:
- make -C $(KERNEL_DIR) SUBDIRS=`pwd` clean